eel r2128 - in trunk: . eel



Author: cneumair
Date: Mon Jun  9 22:53:36 2008
New Revision: 2128
URL: http://svn.gnome.org/viewvc/eel?rev=2128&view=rev

Log:
2008-06-10  Christian Neumair  <cneumair gnome org>

	* eel/eel-editable-label.c
	(eel_editable_label_get_block_cursor_location),
	(eel_editable_label_draw_cursor),
	(eel_editable_label_toggle_overwrite):
	Use block cursor in insert mode. Fixes #511617. Thanks to Arthur
	Taylor.


Modified:
   trunk/ChangeLog
   trunk/eel/eel-editable-label.c

Modified: trunk/eel/eel-editable-label.c
==============================================================================
--- trunk/eel/eel-editable-label.c	(original)
+++ trunk/eel/eel-editable-label.c	Mon Jun  9 22:53:36 2008
@@ -1317,6 +1317,134 @@
   pango_layout_get_cursor_pos (label->layout, index, strong_pos, weak_pos);
 }
 
+/* Copied from gtkutil private function */
+static gboolean
+eel_editable_label_get_block_cursor_location (EelEditableLabel  *label,
+					      gint *index,
+					      PangoRectangle *pos,
+					      gboolean *at_line_end)
+{
+  const gchar *text;
+  const gchar *preedit_text;
+  PangoLayoutLine *layout_line;
+  PangoRectangle strong_pos, weak_pos;
+  gint line_no;
+  gboolean rtl;
+  PangoContext *context;
+  PangoFontMetrics *metrics;
+  const PangoFontDescription *font_desc;
+  
+  eel_editable_label_ensure_layout (label, TRUE);
+  
+  text = pango_layout_get_text (label->layout);
+  preedit_text = text + label->selection_anchor;
+  text = g_utf8_offset_to_pointer (preedit_text, label->preedit_cursor);
+  index[0] = label->selection_anchor + text - preedit_text;
+
+  pango_layout_index_to_pos (label->layout, index[0], pos);
+
+  index[1] = label->selection_anchor + g_utf8_next_char (text) - preedit_text;
+
+  if (pos->width != 0)
+    {
+      if (at_line_end)
+	*at_line_end = FALSE;
+      if (pos->width < 0) /* RTL char, shift x value back to top left of rect */
+	{
+	  pos->x += pos->width;
+	  pos->width = -pos->width;
+	}
+      return TRUE;
+    }
+
+  pango_layout_index_to_line_x (label->layout, index[0], FALSE, &line_no, NULL);
+  layout_line = pango_layout_get_line_readonly (label->layout, line_no);
+  if (layout_line == NULL)
+    return FALSE;
+
+    text = pango_layout_get_text (label->layout);
+  if (index[0] < layout_line->start_index + layout_line->length)
+    {
+      /* this may be a zero-width character in the middle of the line,
+       * or it could be a character where line is wrapped, we do want
+       * block cursor in latter case */
+      if (g_utf8_next_char (text + index[0]) - text !=
+	  layout_line->start_index + layout_line->length)
+	{
+	  /* zero-width character in the middle of the line, do not
+	   * bother with block cursor */
+	  return FALSE;
+	}
+    }
+
+  /* Cursor is at the line end. It may be an empty line, or it could
+   * be on the left or on the right depending on text direction, or it
+   * even could be in the middle of visual layout in bidi text. */
+
+  pango_layout_get_cursor_pos (label->layout, index[0], &strong_pos, &weak_pos);
+
+  if (strong_pos.x != weak_pos.x)
+    {
+      /* do not show block cursor in this case, since the character typed
+       * in may or may not appear at the cursor position */
+      return FALSE;
+    }
+
+  context = pango_layout_get_context (label->layout);
+
+  /* In case when index points to the end of line, pos->x is always most right
+   * pixel of the layout line, so we need to correct it for RTL text. */
+  if (layout_line->length)
+    {
+      if (layout_line->resolved_dir == PANGO_DIRECTION_RTL)
+	{
+	  PangoLayoutIter *iter;
+	  PangoRectangle line_rect;
+	  gint i;
+	  gint left, right;
+	  const gchar *p;
+
+	  p = g_utf8_prev_char (text + index[0]);
+
+	  pango_layout_line_index_to_x (layout_line, p - text, FALSE, &left);
+	  pango_layout_line_index_to_x (layout_line, p - text, TRUE, &right);
+	  pos->x = MIN (left, right);
+
+	  iter = pango_layout_get_iter (label->layout);
+	  for (i = 0; i < line_no; i++)
+	    pango_layout_iter_next_line (iter);
+	  pango_layout_iter_get_line_extents (iter, NULL, &line_rect);
+	  pango_layout_iter_free (iter);
+
+          rtl = TRUE;
+	  pos->x += line_rect.x;
+	}
+      else
+	rtl = FALSE;
+    }
+  else
+    {
+      rtl = pango_context_get_base_dir (context) == PANGO_DIRECTION_RTL;
+    }
+  
+  font_desc = pango_layout_get_font_description (label->layout);
+  if (!font_desc)
+    font_desc = pango_context_get_font_description (context);
+
+  metrics = pango_context_get_metrics (context, font_desc, NULL);
+  pos->width = pango_font_metrics_get_approximate_char_width (metrics);
+  pango_font_metrics_unref (metrics);
+
+  if (rtl)
+    pos->x -= pos->width - 1;
+
+  if (at_line_end)
+    *at_line_end = TRUE;
+
+  return pos->width != 0;
+}
+
+
 /* These functions are copies from gtk+, as they are not exported from gtk+ */
 
 static GdkGC *
@@ -1347,7 +1475,7 @@
 _eel_draw_insertion_cursor (GtkWidget        *widget,
 			    GdkDrawable      *drawable,
 			    GdkGC            *gc,
-			    GdkRectangle     *location,
+                            GdkRectangle     *location,
                             GtkTextDirection  direction,
                             gboolean          draw_arrow)
 {
@@ -1416,8 +1544,11 @@
 
       GtkTextDirection keymap_direction;
       GtkTextDirection widget_direction;
-      PangoRectangle strong_pos, weak_pos;
       gboolean split_cursor;
+      gboolean block;
+      gboolean block_at_line_end;
+      gint range[2];
+      PangoRectangle strong_pos, weak_pos;
       PangoRectangle *cursor1 = NULL;
       PangoRectangle *cursor2 = NULL;
       GdkRectangle cursor_location;
@@ -1430,54 +1561,98 @@
 
       widget_direction = gtk_widget_get_direction (widget);
 
-      eel_editable_label_get_cursor_pos (label, &strong_pos, &weak_pos);
+      if (label->overwrite_mode &&
+	  eel_editable_label_get_block_cursor_location (label, range,
+							&strong_pos,
+							&block_at_line_end))
+	block = TRUE;
+      else
+	block = FALSE;
 
-      g_object_get (gtk_widget_get_settings (widget),
-		    "gtk-split-cursor", &split_cursor,
-		    NULL);
+      if (!block)
+	{ 
+          eel_editable_label_get_cursor_pos (label, &strong_pos, &weak_pos);
 
-      dir1 = widget_direction;
-      
-      if (split_cursor)
-	{
-	  cursor1 = &strong_pos;
+          g_object_get (gtk_widget_get_settings (widget),
+			"gtk-split-cursor", &split_cursor,
+			NULL);
 
-	  if (strong_pos.x != weak_pos.x ||
-	      strong_pos.y != weak_pos.y)
+          dir1 = widget_direction;
+      
+	  if (split_cursor)
 	    {
-	      dir2 = (widget_direction == GTK_TEXT_DIR_LTR) ? GTK_TEXT_DIR_RTL : GTK_TEXT_DIR_LTR;
-	      cursor2 = &weak_pos;
+	      cursor1 = &strong_pos;
+
+	      if (strong_pos.x != weak_pos.x ||
+		  strong_pos.y != weak_pos.y)
+		{
+		  dir2 = (widget_direction == GTK_TEXT_DIR_LTR) ? GTK_TEXT_DIR_RTL : GTK_TEXT_DIR_LTR;
+		  cursor2 = &weak_pos;
+		}
 	    }
-	}
-      else
-	{
-	  if (keymap_direction == widget_direction)
-	    cursor1 = &strong_pos;
 	  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);
-
-      _eel_draw_insertion_cursor (widget, widget->window,
-				  label->primary_cursor_gc,
-				  &cursor_location, dir1,
-                                  dir2 != GTK_TEXT_DIR_NONE);
+	    {
+	      if (keymap_direction == widget_direction)
+		  cursor1 = &strong_pos;
+	      else
+		  cursor1 = &weak_pos;
+	    }
       
-      if (dir2 != GTK_TEXT_DIR_NONE)
-	{
-	  cursor_location.x = xoffset + PANGO_PIXELS (cursor2->x);
-	  cursor_location.y = yoffset + PANGO_PIXELS (cursor2->y);
+          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 (cursor2->height);
+	  cursor_location.height = PANGO_PIXELS (cursor1->height);
 
 	  _eel_draw_insertion_cursor (widget, widget->window,
-				      label->secondary_cursor_gc,
-				      &cursor_location, dir2, TRUE);
+				      label->primary_cursor_gc,
+				      &cursor_location, dir1,
+				      dir2 != GTK_TEXT_DIR_NONE);
+
+	  if (dir2 != GTK_TEXT_DIR_NONE)
+	    {
+	      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);
+
+	      _eel_draw_insertion_cursor (widget, widget->window,
+					  label->secondary_cursor_gc,
+					  &cursor_location, dir2, TRUE);
+	    }
 	}
+      else /* Block cursor */
+	{
+          GdkRegion *clip;
+
+	  gdk_draw_rectangle (widget->window, label->primary_cursor_gc, TRUE,
+			      xoffset + PANGO_PIXELS (strong_pos.x),
+			      yoffset + PANGO_PIXELS (strong_pos.y),
+			      PANGO_PIXELS (strong_pos.width),
+			      PANGO_PIXELS (strong_pos.height));
+
+	  if (!block_at_line_end)
+	    {
+	      clip = gdk_pango_layout_get_clip_region (label->layout,
+						       xoffset, yoffset,
+						       range, 1);
+
+	      /* FIXME should use gtk_paint, but it can't use a clip
+	       * region
+	       */
+
+	      gdk_gc_set_clip_region (label->primary_cursor_gc, clip);
+
+	      gdk_draw_layout_with_colors (widget->window,
+		                           label->primary_cursor_gc,
+					   xoffset, yoffset,
+					   label->layout,
+					   &widget->style->base[GTK_STATE_NORMAL],
+					   NULL);
+
+	      gdk_gc_set_clip_region (label->primary_cursor_gc, NULL);
+	      gdk_region_destroy (clip);
+	    }
+	}	  
     }
 }
 
@@ -3005,6 +3180,7 @@
 eel_editable_label_toggle_overwrite (EelEditableLabel *label)
 {
   label->overwrite_mode = !label->overwrite_mode;
+  gtk_widget_queue_draw (GTK_WIDGET (label));
 }
 
 typedef struct



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]