by using the right function to figure the location of both kinds of
cursors. Also fix crash in my last cursor movement commit: check for
error values returned by pango_layout_move_cursor_visually() and don't
try to move the cursor beyond the buffer boundaries.
Use pango_layout_move_cursor_visually() instead of e.g. simply using
gtk_text_iter_forward_cursor_position() when "right" was pressed.
This is much more correct now but still not 100% right.
instead of duplicating GimpTextLayout's positioning logic in two
different incomplete ways. Also gets rid of the unrelated offset
return values of gimp_text_tool_editor_get_cursor_rect().
Earlier I claimed that drawing would work now because we make sure
that buffer and layout are always in sync. This was nonsense. In fact,
we constantly ran into the sutiation where the buffer was modified,
and we were drawing with the previous layout. It's unclear why this
didn't cause drawing artifacts, but it did cause e.g. the cursor
temporarily jumping to the next position while editing in the middle
of text (especially visible at line ends).
Several underlying problems existed: first, we now modify the buffer
from outside the text tool (from GimpTextStyleEditor) where we can't
pause the tool; second, proxy changes are handled asymetrically
(property changes are queued and processed all together in an idle
function) so we can't pause/resume drawing across the entire operation
because it has many beginnings and only one end.
Therefore:
- add gimp_text_tool_block_drawing()/unblock_drawing(), where block()
can be called as many times as needed, and a single unblock()
enables drawing again. block() also clears the layout, because it
served its purpose (it was just used to pause drawing, and we know
the buffer will change, so kill it).
- connect to GtkTextBuffer::begin-user-action and call block() from
the callback, so we undraw stuff and kill the cached layout before
any buffer change happens.
- call unblock() at the end of gimp_text_tool_apply() because then
the text and the buffer are in sync again, the tool is undrawn and
we can safely create the layout again to draw our stuff.
- also call block()/unblock() from some other places, like when a
new text layer is created.
- get rid of *all* calls to draw_tool_pause()/resume() around buffer
modifications, they are not needed any longer.
- add calls to begin/end_user_action() where they were missing.
Add gimp_text_buffer_get_iter_at_index() which does the reverse thing
than the already existing function gimp_text_buffer_get_iter_index().
Use the new function when cursor-navigation lines. Add "gboolean
layout_index" to both functions, which if TRUE indicates that the
passed in/out index is an index into the PangoLayout's content rather
than the text buffer's. When dealing with layout indices, take into
account the additional characters we insert into the serialized markup
(and thus the layout) for each character that is tagged with spacing.
Instead of including dialogs/dialogs.h everywhere, introduce
gimp_dialog_factory_get_singleton(). The dialog factory singleton is
still initialized by dialogs.c though.
Right now the assumption is that we never will have another dialog
factory instance around. There were so many problems before when we
had four of them, so let's just keep one of them around.
We only have one dialog factory now, and
gimp_dialog_factory_from_name() doesn't provide compile-time type
safety, so use global_dialog_factory directly instead.
Add anchor and spacing parameters to the shell overlay API, so
overlays can be positioned on each side of a point in image space,
with configurable spacing in display space.
Add a list of available baseline tags to GimpTextBuffer and
automatically create baseline tags as needed. They get serialized as
<span rise="value">, so add attribute and value parameters to the
buffer's tag_to_name() and name_to_tag() functions. Properly managing
the rise's amount is a TODO, currently each keystroke changes the
baseline by 1024 pango units, which might be whatever depending on the
output grid.
- create a GimpTextStyleEditor on the canvas when editing text.
- sync "text" and "markup" between proxy and text, not only "text.
- connect to chages to text marks on the buffer.
Pull all text buffer utility functions as methods and use
GimpTextBuffer all over the place instead of GtkTextBuffer.
Some actually usefuly features coming soon...
Switch to a completely new PangoLayout managing stategy: The drawing
code relies on text_tool->layout being a view on text_tool->text_buffer,
if they get out of sync, drawing is b0rk.
Therefore, split the update_layout() function into clear_layout()
(which kill the layout) and ensure_layout() (which creates the layout
if it doesn't exist).
Whenever the buffer gets modified, pause the draw tool before the
modification so the old cursor/selection undraw, then clear the
layout. Resuming the draw tool will automatically re-create the layout
for the buffer's new contents.
Also switch off any clipping for cursor and selection, so we can at
least see that our input has some effect, even if we don't actually
see the edited text because it's out-of-layer.
Take the X position of the lines into account when navigating up and
down by lines, so we end up at the right x-pos also for centered and
right-aligned lines.
- hide the generated "empty" menu item in the IM submenu
- pause/resume the text tool around all selection/cursor/buffer changes
(fixes most drawing artifacts)
This has several advantages:
- it's always readable, no matter how sick font/colors are.
- it does not mess up the buffer, which is a model that should not
contain temporary edit states.
- preediting does not clutter undo.
- it fixes the remaining bugs in the old preediting code because that
code is completely gone now.
- Reset the IM context in much more situations, like on button_press
and when the text editor is initialized and halted (pretty much what
GtkTextView does).
- As a consequence, halt the rectangle text tool after the text tool
in control() because cancelling the IM preedit might cause a
re-framing of the layer because it resized.
- pause()/resume() the draw tool around gimp_text_tool_halt() so we
definitely avoid drawing atrifacts when the text tool is shut down
in the middle of an IM preedit. That pause/resume pair should have
been there from the beginning actually.
- most importantly, when the text changes and we set the buffer (as
happens when undoing), block the "changed" signal on the *buffer*
and not on the proxy (which doesn't even have a "changed"
signal). This was apparently something that happened during the
on-canvas editor merging.
- don't update the proxy when the layout changes, that's the wrong way
around. Instead, update the layout whenever the proxy changes,
remove lots of calls to update_layout() from the text editor and let
the "changed" callback on the buffer do its job of updating
everything.