Insertion cursor drawing improvements
- From: Owen Taylor <otaylor redhat com>
- To: gtk-devel-list gnome org
- Subject: Insertion cursor drawing improvements
- Date: 24 Sep 2001 12:22:30 -0400
Just found the following patch on one of my computers - I've had
it sitting around for a few months. What it
does is:
- Make the insertion cursor draw with wider width for taller cursors
- Adds small directional arrows when you have split
cursors to make it clear which cursor is which.
- Adds a "cursor_color" property to GtkTextView to match
the cursor_color property in GtkEntry.
Possible questions:
- Should _gtk_draw_insertion_cursor() be public? It's conceivable
that custom widgets or modified versions of
GtkEntry/GtkLabel/GtkTextView will need access to this function.
It's not really a normal gtk_draw_* function as it's not
virtualized in the style, takes a GdkGC as input, and so forth.
- Does the cursor_gc addition to gtk_text_layout_draw() make sense?
The alternative would be to remove the "cursor_color" style
properties and add a global "cursor_color" setting.
Regards,
Owen
Index: gtkentry.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkentry.c,v
retrieving revision 1.149
diff -u -p -r1.149 gtkentry.c
--- gtkentry.c 2001/09/19 00:49:51 1.149
+++ gtkentry.c 2001/09/24 16:08:20
@@ -2583,6 +2583,7 @@ gtk_entry_draw_cursor (GtkEntry *entry,
if (GTK_WIDGET_DRAWABLE (entry))
{
GtkWidget *widget = GTK_WIDGET (entry);
+ GdkRectangle cursor_location;
gboolean split_cursor;
gint xoffset = INNER_BORDER - entry->scroll_offset;
@@ -2590,6 +2591,8 @@ gtk_entry_draw_cursor (GtkEntry *entry,
gint text_area_height;
GdkGC *gc1 = NULL;
GdkGC *gc2 = NULL;
+ GtkTextDirection dir1 = GTK_TEXT_DIR_NONE;
+ GtkTextDirection dir2 = GTK_TEXT_DIR_NONE;
gint x1 = 0;
gint x2 = 0;
@@ -2608,6 +2611,9 @@ gtk_entry_draw_cursor (GtkEntry *entry,
if (weak_x != strong_x)
{
+ dir1 = widget_direction;
+ dir2 = (widget_direction == GTK_TEXT_DIR_LTR) ? GTK_TEXT_DIR_RTL : GTK_TEXT_DIR_LTR;
+
gc2 = widget->style->text_gc[GTK_STATE_NORMAL];
x2 = weak_x;
}
@@ -2621,15 +2627,21 @@ gtk_entry_draw_cursor (GtkEntry *entry,
else
x1 = weak_x;
}
+
+ cursor_location.x = xoffset + x1;
+ cursor_location.y = INNER_BORDER;
+ cursor_location.width = 0;
+ cursor_location.height = text_area_height - 2 * INNER_BORDER ;
- gdk_draw_line (entry->text_area, gc1,
- xoffset + x1, INNER_BORDER,
- xoffset + x1, text_area_height - INNER_BORDER);
+ _gtk_draw_insertion_cursor (entry->text_area, gc1,
+ &cursor_location, dir1);
if (gc2)
- gdk_draw_line (entry->text_area, gc2,
- xoffset + x2, INNER_BORDER,
- xoffset + x2, text_area_height - INNER_BORDER);
+ {
+ cursor_location.x = xoffset + x2;
+ _gtk_draw_insertion_cursor (entry->text_area, gc2,
+ &cursor_location, dir2);
+ }
}
}
Index: gtklabel.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtklabel.c,v
retrieving revision 1.100
diff -u -p -r1.100 gtklabel.c
--- gtklabel.c 2001/09/19 00:49:51 1.100
+++ gtklabel.c 2001/09/24 16:08:20
@@ -1595,13 +1595,16 @@ gtk_label_draw_cursor (GtkLabel *label,
if (GTK_WIDGET_DRAWABLE (label))
{
GtkWidget *widget = GTK_WIDGET (label);
-
+
GtkTextDirection keymap_direction;
GtkTextDirection widget_direction;
PangoRectangle strong_pos, weak_pos;
gboolean split_cursor;
PangoRectangle *cursor1 = NULL;
PangoRectangle *cursor2 = NULL;
+ GdkRectangle cursor_location;
+ GtkTextDirection dir1 = GTK_TEXT_DIR_NONE;
+ GtkTextDirection dir2 = GTK_TEXT_DIR_NONE;
GdkGC *gc1 = NULL;
GdkGC *gc2 = NULL;
@@ -1628,6 +1631,9 @@ gtk_label_draw_cursor (GtkLabel *label,
if (strong_pos.x != weak_pos.x ||
strong_pos.y != weak_pos.y)
{
+ dir1 = widget_direction;
+ dir2 = (widget_direction == GTK_TEXT_DIR_LTR) ? GTK_TEXT_DIR_RTL : GTK_TEXT_DIR_LTR;
+
gc2 = widget->style->black_gc;
cursor2 = &weak_pos;
}
@@ -1641,15 +1647,25 @@ gtk_label_draw_cursor (GtkLabel *label,
else
cursor1 = &weak_pos;
}
+
+ cursor_location.x = xoffset + PANGO_PIXELS (cursor1->x);
+ cursor_location.y = yoffset + PANGO_PIXELS (cursor1->y);
+ cursor_location.width = 0;
+ cursor_location.height = PANGO_PIXELS (cursor1->height);
- gdk_draw_line (widget->window, gc1,
- xoffset + PANGO_PIXELS (cursor1->x), yoffset + PANGO_PIXELS (cursor1->y),
- xoffset + PANGO_PIXELS (cursor1->x), yoffset + PANGO_PIXELS (cursor1->y + cursor1->height));
+ _gtk_draw_insertion_cursor (widget->window, gc1,
+ &cursor_location, dir1);
if (gc2)
- gdk_draw_line (widget->window, gc2,
- xoffset + PANGO_PIXELS (cursor2->x), yoffset + PANGO_PIXELS (cursor2->y),
- xoffset + PANGO_PIXELS (cursor2->x), yoffset + PANGO_PIXELS (cursor2->y + cursor2->height));
+ {
+ cursor_location.x = xoffset + PANGO_PIXELS (cursor2->x);
+ cursor_location.y = yoffset + PANGO_PIXELS (cursor2->y);
+ cursor_location.width = 0;
+ cursor_location.height = PANGO_PIXELS (cursor2->height);
+
+ _gtk_draw_insertion_cursor (widget->window, gc2,
+ &cursor_location, dir2);
+ }
}
}
Index: gtkstyle.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkstyle.c,v
retrieving revision 1.80
diff -u -p -r1.80 gtkstyle.c
--- gtkstyle.c 2001/09/18 20:06:46 1.80
+++ gtkstyle.c 2001/09/24 16:08:20
@@ -5050,3 +5050,60 @@ gtk_style_set_font (GtkStyle *style,
style->private_font_desc = NULL;
}
}
+
+/**
+ * _gtk_draw_insertion_cursor:
+ * @drawable: a #GdkDrawable
+ * @gc: a #GdkGC
+ * @location: location where to draw the cursor (@location->width is ignored)
+ * @dir: text direction for the cursor, used to decide whether to draw a
+ * directional arrow on the cursor and in what direction. Unless both
+ * strong and weak cursors are displayed, this should be %GTK_TEXT_DIR_NONE.
+ *
+ * Draws a text caret on @drawable at @location. This is not a style function
+ * but merely a convenience function for drawing the standard cursor shape.
+ **/
+void
+_gtk_draw_insertion_cursor (GdkDrawable *drawable,
+ GdkGC *gc,
+ GdkRectangle *location,
+ GtkTextDirection dir)
+{
+ gint stem_width = location->height / 30 + 1;
+ gint arrow_width = stem_width + 1;
+ gint x, y;
+ gint i;
+
+ for (i = 0; i < stem_width; i++)
+ gdk_draw_line (drawable, gc,
+ location->x + i - stem_width / 2, location->y,
+ location->x + i - stem_width / 2, location->y + location->height);
+
+ if (dir == GTK_TEXT_DIR_RTL)
+ {
+ x = location->x - stem_width / 2 - 1;
+ y = location->y + location->height - arrow_width * 2 - arrow_width + 1;
+
+ for (i = 0; i < arrow_width; i++)
+ {
+ gdk_draw_line (drawable, gc,
+ x, y + i + 1,
+ x, y + 2 * arrow_width - i - 1);
+ x --;
+ }
+ }
+ else if (dir == GTK_TEXT_DIR_LTR)
+ {
+ x = location->x + stem_width - stem_width / 2;
+ y = location->y + location->height - arrow_width * 2 - arrow_width + 1;
+
+ for (i = 0; i < arrow_width; i++)
+ {
+ gdk_draw_line (drawable, gc,
+ x, y + i + 1,
+ x, y + 2 * arrow_width - i - 1);
+ x++;
+ }
+ }
+}
+
Index: gtkstyle.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkstyle.h,v
retrieving revision 1.31
diff -u -p -r1.31 gtkstyle.h
--- gtkstyle.h 2001/09/18 20:06:46 1.31
+++ gtkstyle.h 2001/09/24 16:08:20
@@ -868,6 +868,11 @@ void gtk_paint_string (GtkStyle
const gchar *string);
#endif /* GTK_DISABLE_DEPRECATED */
+void _gtk_draw_insertion_cursor (GdkDrawable *drawable,
+ GdkGC *gc,
+ GdkRectangle *location,
+ GtkTextDirection dir);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
Index: gtktextdisplay.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtktextdisplay.c,v
retrieving revision 1.29
diff -u -p -r1.29 gtktextdisplay.c
--- gtktextdisplay.c 2001/09/19 00:49:52 1.29
+++ gtktextdisplay.c 2001/09/24 16:08:20
@@ -716,6 +716,7 @@ void
gtk_text_layout_draw (GtkTextLayout *layout,
GtkWidget *widget,
GdkDrawable *drawable,
+ GdkGC *cursor_gc,
/* Location of the drawable
in layout coordinates */
gint x_offset,
@@ -775,6 +776,8 @@ gtk_text_layout_draw (GtkTextLayout *lay
GtkTextLineDisplay *line_display;
gint selection_start_index = -1;
gint selection_end_index = -1;
+ gboolean have_strong;
+ gboolean have_weak;
GtkTextLine *line = tmp_list->data;
@@ -823,23 +826,53 @@ gtk_text_layout_draw (GtkTextLayout *lay
/* We paint the cursors last, because they overlap another chunk
and need to appear on top. */
+ have_strong = FALSE;
+ have_weak = FALSE;
+
+ cursor_list = line_display->cursors;
+ while (cursor_list)
+ {
+ GtkTextCursorDisplay *cursor = cursor_list->data;
+ if (cursor->is_strong)
+ have_strong = TRUE;
+ else
+ have_weak = TRUE;
+
+ cursor_list = cursor_list->next;
+ }
+
cursor_list = line_display->cursors;
while (cursor_list)
{
GtkTextCursorDisplay *cursor = cursor_list->data;
+ GtkTextDirection dir;
+ GdkRectangle cursor_location;
+
GdkGC *gc;
if (cursor->is_strong)
- gc = widget->style->base_gc[GTK_STATE_SELECTED];
+ gc = cursor_gc;
else
gc = widget->style->text_gc[GTK_STATE_NORMAL];
- gdk_gc_set_clip_rectangle (gc, &clip);
- gdk_draw_line (drawable, gc,
- line_display->x_offset + cursor->x - x_offset,
- current_y + line_display->top_margin + cursor->y,
- line_display->x_offset + cursor->x - x_offset,
- current_y + line_display->top_margin + cursor->y + cursor->height - 1);
+ if (have_strong && have_weak)
+ {
+ dir = line_display->direction;
+ if (!cursor->is_strong)
+ dir = (dir == GTK_TEXT_DIR_RTL) ? GTK_TEXT_DIR_LTR : GTK_TEXT_DIR_RTL;
+ }
+ else
+ {
+ dir = GTK_TEXT_DIR_NONE;
+ }
+
+ cursor_location.x = line_display->x_offset + cursor->x - x_offset;
+ cursor_location.y = current_y + line_display->top_margin + cursor->y;
+ cursor_location.width = 0;
+ cursor_location.height = cursor->height;
+
+ gdk_gc_set_clip_rectangle(gc, &clip);
+ _gtk_draw_insertion_cursor (drawable, gc, &cursor_location, dir);
gdk_gc_set_clip_rectangle (gc, NULL);
cursor_list = cursor_list->next;
Index: gtktextdisplay.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtktextdisplay.h,v
retrieving revision 1.6
diff -u -p -r1.6 gtktextdisplay.h
--- gtktextdisplay.h 2000/10/30 17:02:57 1.6
+++ gtktextdisplay.h 2001/09/24 16:08:20
@@ -90,6 +90,7 @@ extern "C" {
/* The drawable should be pre-initialized to your preferred background.
* widget - Widget to grab some style info from
* drawable - Drawable to render to
+ * cursor_gc - Graphics context to use for cursor
* x_offset/y_offset - Position of the drawable in layout coordinates
* x/y/width/height - Region of the layout to render. x,y must be inside
* the drawable.
@@ -97,6 +98,7 @@ extern "C" {
void gtk_text_layout_draw (GtkTextLayout *layout,
GtkWidget *widget,
GdkDrawable *drawable,
+ GdkGC *cursor_gc,
gint x_offset,
gint y_offset,
gint x,
Index: gtktextview.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtktextview.c,v
retrieving revision 1.112
diff -u -p -r1.112 gtktextview.c
--- gtktextview.c 2001/09/22 00:08:18 1.112
+++ gtktextview.c 2001/09/24 16:08:20
@@ -620,6 +620,18 @@ gtk_text_view_class_init (GtkTextViewCla
/*
+ * Style properties
+ */
+
+ gtk_widget_class_install_style_property (widget_class,
+ g_param_spec_boxed ("cursor_color",
+ _("Cursor color"),
+ _("Color with which to draw insertion cursor"),
+ GDK_TYPE_COLOR,
+ G_PARAM_READABLE));
+
+
+ /*
* Signals
*/
@@ -2909,6 +2921,24 @@ changed_handler (GtkTextLayout *layout,
}
static void
+gtk_text_view_realize_cursor_gc (GtkTextView *text_view)
+{
+ GdkColor *cursor_color;
+
+ if (text_view->cursor_gc)
+ gdk_gc_unref (text_view->cursor_gc);
+
+ gtk_widget_style_get (GTK_WIDGET (text_view), "cursor_color", &cursor_color, NULL);
+ if (cursor_color)
+ {
+ text_view->cursor_gc = gdk_gc_new (text_view->text_window->bin_window);
+ gdk_gc_set_rgb_fg_color (text_view->cursor_gc, cursor_color);
+ }
+ else
+ text_view->cursor_gc = gdk_gc_ref (GTK_WIDGET (text_view)->style->base_gc[GTK_STATE_SELECTED]);
+}
+
+static void
gtk_text_view_realize (GtkWidget *widget)
{
GtkTextView *text_view;
@@ -2958,6 +2988,8 @@ gtk_text_view_realize (GtkWidget *widget
text_window_realize (text_view->bottom_window,
widget->window);
+ gtk_text_view_realize_cursor_gc (text_view);
+
gtk_text_view_ensure_layout (text_view);
if (text_view->buffer)
@@ -2976,6 +3008,12 @@ gtk_text_view_unrealize (GtkWidget *widg
gtk_text_buffer_remove_selection_clipboard (text_view->buffer,
gtk_clipboard_get (GDK_SELECTION_PRIMARY));
+ if (text_view->cursor_gc)
+ {
+ gdk_gc_unref (text_view->cursor_gc);
+ text_view->cursor_gc = NULL;
+ }
+
if (text_view->first_validate_idle)
{
g_source_remove (text_view->first_validate_idle);
@@ -3041,6 +3079,8 @@ gtk_text_view_style_set (GtkWidget *widg
if (text_view->bottom_window)
gdk_window_set_background (text_view->bottom_window->bin_window,
&widget->style->bg[GTK_WIDGET_STATE (widget)]);
+
+ gtk_text_view_realize_cursor_gc (text_view);
}
if (text_view->layout && previous_style)
@@ -3575,6 +3615,7 @@ gtk_text_view_paint (GtkWidget *widget,
gtk_text_layout_draw (text_view->layout,
widget,
text_view->text_window->bin_window,
+ text_view->cursor_gc,
text_view->xoffset,
text_view->yoffset,
area->x, area->y,
Index: gtktextview.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtktextview.h,v
retrieving revision 1.28
diff -u -p -r1.28 gtktextview.h
--- gtktextview.h 2001/06/24 16:08:15 1.28
+++ gtktextview.h 2001/09/24 16:08:20
@@ -142,6 +142,7 @@ struct _GtkTextView
GSList *children;
GtkTextPendingScroll *pending_scroll;
+ GdkGC *cursor_gc;
};
struct _GtkTextViewClass
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]