diff options
Diffstat (limited to 'gtk/gtktextlayout.c')
-rw-r--r-- | gtk/gtktextlayout.c | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/gtk/gtktextlayout.c b/gtk/gtktextlayout.c index 2cb2981f7e..8faefef552 100644 --- a/gtk/gtktextlayout.c +++ b/gtk/gtktextlayout.c @@ -82,6 +82,7 @@ #include "gtktextlayout.h" #include "gtktextbtree.h" #include "gtktextiterprivate.h" +#include "gtktextutil.h" #include "gtkintl.h" #include "gtkalias.h" @@ -398,6 +399,25 @@ gtk_text_layout_set_contexts (GtkTextLayout *layout, } /** + * gtk_text_layout_set_overwrite_mode: + * @layout: a #GtkTextLayout + * @overwrite: overwrite mode + * + * Sets overwrite mode + **/ +void +gtk_text_layout_set_overwrite_mode (GtkTextLayout *layout, + gboolean overwrite) +{ + overwrite = overwrite != 0; + if (overwrite != layout->overwrite_mode) + { + layout->overwrite_mode = overwrite; + gtk_text_layout_invalidate_cursor_line (layout, TRUE); + } +} + +/** * gtk_text_layout_set_cursor_direction: * @direction: the new direction(s) for which to draw cursors. * %GTK_TEXT_DIR_NONE means draw cursors for both @@ -795,6 +815,7 @@ gtk_text_layout_invalidate_cache (GtkTextLayout *layout, g_slist_free (display->cursors); display->cursors = NULL; display->cursors_invalid = TRUE; + display->has_block_cursor = FALSE; } else { @@ -1648,6 +1669,52 @@ add_child_attrs (GtkTextLayout *layout, pango_attr_list_insert (attrs, attr); } +/** + * get_block_cursor: + * @layout: a #GtkTextLayout + * @display: a #GtkTextLineDisplay + * @insert_iter: iter pointing to the cursor location + * @insert_index: cursor offset in the @display's layout, it may + * be different from @insert_iter's offset in case when preedit + * string is present. + * @pos: location to store cursor position + * @cursor_at_line_end: whether cursor is at the end of line + * + * Checks whether layout should display block cursor at given position. + * For this layout must be in overwrite mode and text at @insert_iter + * must be editable. + **/ +static gboolean +get_block_cursor (GtkTextLayout *layout, + GtkTextLineDisplay *display, + const GtkTextIter *insert_iter, + gint insert_index, + GdkRectangle *pos, + gboolean *cursor_at_line_end) +{ + PangoRectangle pango_pos; + + if (layout->overwrite_mode && + gtk_text_iter_editable (insert_iter, TRUE) && + _gtk_text_util_get_block_cursor_location (display->layout, + insert_index, + &pango_pos, + cursor_at_line_end)) + { + if (pos) + { + pos->x = PANGO_PIXELS (pango_pos.x); + pos->y = PANGO_PIXELS (pango_pos.y); + pos->width = PANGO_PIXELS (pango_pos.width); + pos->height = PANGO_PIXELS (pango_pos.height); + } + + return TRUE; + } + else + return FALSE; +} + static void add_cursor (GtkTextLayout *layout, GtkTextLineDisplay *display, @@ -1668,6 +1735,26 @@ add_cursor (GtkTextLayout *layout, gtk_text_buffer_get_selection_bounds (layout->buffer, NULL, NULL))) return; + if (layout->overwrite_mode && + _gtk_text_btree_mark_is_insert (_gtk_text_buffer_get_btree (layout->buffer), + seg->body.mark.obj)) + { + GtkTextIter iter; + gboolean cursor_at_line_end; + + _gtk_text_btree_get_iter_at_mark (_gtk_text_buffer_get_btree (layout->buffer), + &iter, seg->body.mark.obj); + + if (get_block_cursor (layout, display, &iter, start, + &display->block_cursor, + &cursor_at_line_end)) + { + display->has_block_cursor = TRUE; + display->cursor_at_line_end = cursor_at_line_end; + return; + } + } + pango_layout_get_cursor_pos (display->layout, start, &strong_pos, &weak_pos); if (layout->cursor_direction == GTK_TEXT_DIR_NONE) @@ -2139,6 +2226,9 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout, { cursor_byte_offsets = g_slist_prepend (cursor_byte_offsets, GINT_TO_POINTER (layout_byte_offset)); cursor_segs = g_slist_prepend (cursor_segs, seg); + if (_gtk_text_btree_mark_is_insert (_gtk_text_buffer_get_btree (layout->buffer), + seg->body.mark.obj)) + display->insert_index = layout_byte_offset; } } else @@ -2613,6 +2703,66 @@ gtk_text_layout_get_cursor_locations (GtkTextLayout *layout, } /** + * _gtk_text_layout_get_block_cursor: + * @layout: a #GtkTextLayout + * @pos: a #GdkRectangle to store block cursor position + * + * If layout is to display a block cursor, calculates its position + * and returns %TRUE. Otherwise it returns %FALSE. In case when + * cursor is visible, it simply returns the position stored in + * the line display, otherwise it has to compute the position + * (see get_block_cursor()). + **/ +gboolean +_gtk_text_layout_get_block_cursor (GtkTextLayout *layout, + GdkRectangle *pos) +{ + GtkTextLine *line; + GtkTextLineDisplay *display; + GtkTextIter iter; + GdkRectangle rect; + gboolean block = FALSE; + + g_return_val_if_fail (layout != NULL, FALSE); + + gtk_text_buffer_get_iter_at_mark (layout->buffer, &iter, + gtk_text_buffer_get_insert (layout->buffer)); + line = _gtk_text_iter_get_text_line (&iter); + display = gtk_text_layout_get_line_display (layout, line, FALSE); + + if (display->has_block_cursor) + { + block = TRUE; + rect = display->block_cursor; + } + else + { + gint index = display->insert_index; + + if (index < 0) + index = gtk_text_iter_get_line_index (&iter); + + if (get_block_cursor (layout, display, &iter, index, &rect, NULL)) + block = TRUE; + } + + if (block && pos) + { + gint line_top; + + line_top = _gtk_text_btree_find_line_top (_gtk_text_buffer_get_btree (layout->buffer), + line, layout); + + *pos = rect; + pos->x += display->x_offset; + pos->y += line_top + display->top_margin; + } + + gtk_text_layout_free_line_display (layout, display); + return block; +} + +/** * gtk_text_layout_get_line_yrange: * @layout: a #GtkTextLayout * @iter: a #GtkTextIter |