diff options
author | Owen Taylor <otaylor@redhat.com> | 2004-03-01 16:07:45 +0000 |
---|---|---|
committer | Owen Taylor <otaylor@src.gnome.org> | 2004-03-01 16:07:45 +0000 |
commit | 8130a8a227f891d0d3aab433c7b19ccaf51e5fa7 (patch) | |
tree | 48c76c69ac87b41ab48ff08a64b970a40f90d44f /gtk/gtktextlayout.c | |
parent | f0d22047c3126ab2c420dc084b4caaa82a0bd324 (diff) | |
download | gtk+-8130a8a227f891d0d3aab433c7b19ccaf51e5fa7.tar.gz |
Patch from Dov Grobgeld to implement auto-bidi-direction for GtkTextView
Mon Mar 1 10:41:27 2004 Owen Taylor <otaylor@redhat.com>
Patch from Dov Grobgeld to implement auto-bidi-direction
for GtkTextView (#118543)
* gtk/gtktextbtree.[ch]: Resolve bidi base direction
for each line by propagating backwards/forwards as
necessary.
* gtk/gtktextlayout.[ch] gtk/gtktextview.c: Set the
bidi base direction for the ;ine with the cursor from
the keyboard direction. Add gtk_text_layout_set_keyboard_direction().
Mon Mar 1 10:31:11 2004 Owen Taylor <otaylor@redhat.com>
* gtk/gtkentry.[ch]: Implement auto-bidi-direction,
based on a patch from Dov Grobgeld. (#118540)
Diffstat (limited to 'gtk/gtktextlayout.c')
-rw-r--r-- | gtk/gtktextlayout.c | 182 |
1 files changed, 165 insertions, 17 deletions
diff --git a/gtk/gtktextlayout.c b/gtk/gtktextlayout.c index 157435a8b8..9c98dd7899 100644 --- a/gtk/gtktextlayout.c +++ b/gtk/gtktextlayout.c @@ -85,6 +85,18 @@ #include <stdlib.h> #include <string.h> +#define GTK_TEXT_LAYOUT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_TEXT_LAYOUT, GtkTextLayoutPrivate)) + +typedef struct _GtkTextLayoutPrivate GtkTextLayoutPrivate; + +struct _GtkTextLayoutPrivate +{ + /* Cache the line that the cursor is positioned on, as the keyboard + direction only influences the direction of the cursor line. + */ + GtkTextLine *cursor_line; +}; + static GtkTextLineData *gtk_text_layout_real_wrap (GtkTextLayout *layout, GtkTextLine *line, /* may be NULL */ @@ -110,6 +122,22 @@ static void gtk_text_layout_invalidate_all (GtkTextLayout *layout); static PangoAttribute *gtk_text_attr_appearance_new (const GtkTextAppearance *appearance); +static void gtk_text_layout_mark_set_handler (GtkTextBuffer *buffer, + const GtkTextIter *location, + GtkTextMark *mark, + gpointer data); +static void gtk_text_layout_buffer_insert_text (GtkTextBuffer *textbuffer, + GtkTextIter *iter, + gchar *str, + gint len, + gpointer data); +static void gtk_text_layout_buffer_delete_range (GtkTextBuffer *textbuffer, + GtkTextIter *start, + GtkTextIter *end, + gpointer data); + +static void gtk_text_layout_update_cursor_line (GtkTextLayout *layout); + enum { INVALIDATED, CHANGED, @@ -209,6 +237,8 @@ gtk_text_layout_class_init (GtkTextLayoutClass *klass) GTK_TYPE_OBJECT, G_TYPE_INT, G_TYPE_INT); + + g_type_class_add_private (object_class, sizeof (GtkTextLayoutPrivate)); } static void @@ -284,6 +314,16 @@ gtk_text_layout_set_buffer (GtkTextLayout *layout, _gtk_text_btree_remove_view (_gtk_text_buffer_get_btree (layout->buffer), layout); + g_signal_handlers_disconnect_by_func (layout->buffer, + G_CALLBACK (gtk_text_layout_mark_set_handler), + layout); + g_signal_handlers_disconnect_by_func (layout->buffer, + G_CALLBACK (gtk_text_layout_buffer_insert_text), + layout); + g_signal_handlers_disconnect_by_func (layout->buffer, + G_CALLBACK (gtk_text_layout_buffer_delete_range), + layout); + g_object_unref (layout->buffer); layout->buffer = NULL; } @@ -295,6 +335,14 @@ gtk_text_layout_set_buffer (GtkTextLayout *layout, g_object_ref (buffer); _gtk_text_btree_add_view (_gtk_text_buffer_get_btree (buffer), layout); + + /* Bind to all signals that move the insert mark. */ + g_signal_connect_after (layout->buffer, "mark_set", + G_CALLBACK (gtk_text_layout_mark_set_handler), layout); + g_signal_connect_after (layout->buffer, "insert_text", + G_CALLBACK (gtk_text_layout_buffer_insert_text), layout); + g_signal_connect_after (layout->buffer, "delete_range", + G_CALLBACK (gtk_text_layout_buffer_delete_range), layout); } } @@ -375,6 +423,25 @@ gtk_text_layout_set_cursor_direction (GtkTextLayout *layout, } /** + * gtk_text_layout_set_keyboard_direction: + * @keyboard_dir: the current direction of the keyboard. + * + * Sets the keyboard direction; this is used as for the bidirectional + * base direction for the line with the cursor if the line contains + * only neutral characters. + **/ +void +gtk_text_layout_set_keyboard_direction (GtkTextLayout *layout, + GtkTextDirection keyboard_dir) +{ + if (keyboard_dir != layout->keyboard_direction) + { + layout->keyboard_direction = keyboard_dir; + gtk_text_layout_invalidate_cursor_line (layout); + } +} + +/** * gtk_text_layout_get_buffer: * @layout: a #GtkTextLayout * @@ -704,24 +771,34 @@ gtk_text_layout_invalidate_cache (GtkTextLayout *layout, static void gtk_text_layout_invalidate_cursor_line (GtkTextLayout *layout) { - GtkTextIter iter; - GtkTextLine *line; + GtkTextLayoutPrivate *priv = GTK_TEXT_LAYOUT_GET_PRIVATE (layout); GtkTextLineData *line_data; - gtk_text_buffer_get_iter_at_mark (layout->buffer, &iter, - gtk_text_buffer_get_mark (layout->buffer, "insert")); + if (priv->cursor_line == NULL) + return; - line = _gtk_text_iter_get_text_line (&iter); - line_data = _gtk_text_line_get_data (line, layout); + line_data = _gtk_text_line_get_data (priv->cursor_line, layout); if (line_data) { - gtk_text_layout_invalidate_cache (layout, line); - _gtk_text_line_invalidate_wrap (line, line_data); + gtk_text_layout_invalidate_cache (layout, priv->cursor_line); + _gtk_text_line_invalidate_wrap (priv->cursor_line, line_data); gtk_text_layout_invalidated (layout); } } static void +gtk_text_layout_update_cursor_line(GtkTextLayout *layout) +{ + GtkTextLayoutPrivate *priv = GTK_TEXT_LAYOUT_GET_PRIVATE (layout); + GtkTextIter iter; + + gtk_text_buffer_get_iter_at_mark (layout->buffer, &iter, + gtk_text_buffer_get_mark (layout->buffer, "insert")); + + priv->cursor_line = _gtk_text_iter_get_text_line (&iter); +} + +static void gtk_text_layout_real_invalidate (GtkTextLayout *layout, const GtkTextIter *start, const GtkTextIter *end) @@ -1121,26 +1198,46 @@ totally_invisible_line (GtkTextLayout *layout, static void set_para_values (GtkTextLayout *layout, - GtkTextAttributes *style, + PangoDirection base_dir, + GtkTextAttributes *style, GtkTextLineDisplay *display) { PangoAlignment pango_align = PANGO_ALIGN_LEFT; int layout_width; - display->direction = style->direction; + switch (base_dir) + { + /* If no base direction was found, then use the style direction */ + case PANGO_DIRECTION_NEUTRAL : + display->direction = style->direction; - if (display->direction == GTK_TEXT_DIR_LTR) - display->layout = pango_layout_new (layout->ltr_context); - else + /* Override the base direction */ + if (display->direction == GTK_TEXT_DIR_RTL) + base_dir = PANGO_DIRECTION_RTL; + else + base_dir = PANGO_DIRECTION_LTR; + + break; + case PANGO_DIRECTION_RTL : + display->direction = GTK_TEXT_DIR_RTL; + break; + default: + display->direction = GTK_TEXT_DIR_LTR; + break; + } + + if (display->direction == GTK_TEXT_DIR_RTL) display->layout = pango_layout_new (layout->rtl_context); + else + display->layout = pango_layout_new (layout->ltr_context); switch (style->justification) { case GTK_JUSTIFY_LEFT: - pango_align = (style->direction == GTK_TEXT_DIR_LTR) ? PANGO_ALIGN_LEFT : PANGO_ALIGN_RIGHT; + pango_align = (base_dir == PANGO_DIRECTION_LTR) ? PANGO_ALIGN_LEFT : PANGO_ALIGN_RIGHT; break; case GTK_JUSTIFY_RIGHT: - pango_align = (style->direction == GTK_TEXT_DIR_LTR) ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT; + pango_align = (base_dir == PANGO_DIRECTION_LTR) ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT; break; case GTK_JUSTIFY_CENTER: pango_align = PANGO_ALIGN_CENTER; @@ -1683,6 +1780,7 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout, GtkTextLine *line, gboolean size_only) { + GtkTextLayoutPrivate *priv = GTK_TEXT_LAYOUT_GET_PRIVATE (layout); GtkTextLineDisplay *display; GtkTextLineSegment *seg; GtkTextIter iter; @@ -1696,6 +1794,7 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout, GSList *cursor_segs = NULL; GSList *tmp_list1, *tmp_list2; gboolean saw_widget = FALSE; + PangoDirection base_dir; g_return_val_if_fail (line != NULL, NULL); @@ -1728,6 +1827,18 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout, if (totally_invisible_line (layout, line, &iter)) return display; + /* Find the bidi base direction */ + base_dir = line->dir_propagated_forward; + if (base_dir == PANGO_DIRECTION_NEUTRAL) + base_dir = line->dir_propagated_back; + + if (line == priv->cursor_line && + line->dir_strong == PANGO_DIRECTION_NEUTRAL) + { + base_dir = (layout->keyboard_direction == GTK_TEXT_DIR_LTR) ? + PANGO_DIRECTION_LTR : PANGO_DIRECTION_RTL; + } + /* Allocate space for flat text for buffer */ text_allocated = _gtk_text_line_byte_count (line); @@ -1758,7 +1869,7 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout, */ if (!para_values_set) { - set_para_values (layout, style, display); + set_para_values (layout, base_dir, style, display); para_values_set = TRUE; } @@ -1927,7 +2038,7 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout, if (!para_values_set) { style = get_style (layout, &iter); - set_para_values (layout, style, display); + set_para_values (layout, base_dir, style, display); release_style (layout, style); } @@ -3070,3 +3181,40 @@ gtk_text_layout_spew (GtkTextLayout *layout) layout->height, layout->screen_width); #endif } + +/* Catch all situations that move the insertion point. + */ +static void +gtk_text_layout_mark_set_handler (GtkTextBuffer *buffer, + const GtkTextIter *location, + GtkTextMark *mark, + gpointer data) +{ + GtkTextLayout *layout = GTK_TEXT_LAYOUT (data); + + if (mark == gtk_text_buffer_get_insert (buffer)) + gtk_text_layout_update_cursor_line (layout); +} + +static void +gtk_text_layout_buffer_insert_text (GtkTextBuffer *textbuffer, + GtkTextIter *iter, + gchar *str, + gint len, + gpointer data) +{ + GtkTextLayout *layout = GTK_TEXT_LAYOUT (data); + + gtk_text_layout_update_cursor_line (layout); +} + +static void +gtk_text_layout_buffer_delete_range (GtkTextBuffer *textbuffer, + GtkTextIter *start, + GtkTextIter *end, + gpointer data) +{ + GtkTextLayout *layout = GTK_TEXT_LAYOUT (data); + + gtk_text_layout_update_cursor_line (layout); +} |