]> Pileus Git - ~andy/gtk/commitdiff
When dragging text, use a drag icon showing the (ellipsized) text that is
authorMatthias Clasen <mclasen@redhat.com>
Mon, 11 Jul 2005 17:51:54 +0000 (17:51 +0000)
committerMatthias Clasen <matthiasc@src.gnome.org>
Mon, 11 Jul 2005 17:51:54 +0000 (17:51 +0000)
2005-07-11  Matthias Clasen  <mclasen@redhat.com>

When dragging text, use a drag icon showing the (ellipsized)
text that is being dragged: (#161132, Kevin Duffus, patch
by Carlos Garnacho Parro)

* gtk/gtktextutil.h:
* gtk/gtktextutil.c (_gtk_text_util_create_drag_icon): Add
a function to create a pixmap for use when dragging text.

* gtk/gtktextview.c (gtk_text_view_start_selection_dnd):
* gtk/gtklabel.c (gtk_label_motion):
* gtk/gtkentry.c (gtk_entry_motion_notify): Use a drag icon
showing the text being dragged.

2005-07-11  Matthias Clasen  <mclasen@redhat.com>

* gtk/gtkentry.c (gtk_entry_move_forward_word)
(gtk_entry_move_backward_word): Match the text view change
to allow selecting whitespace with double-click.

ChangeLog
ChangeLog.pre-2-10
ChangeLog.pre-2-8
gtk/gtkentry.c
gtk/gtklabel.c
gtk/gtktextutil.c
gtk/gtktextutil.h
gtk/gtktextview.c

index a73479ad3011d0e24fb309127789873a200de61c..8b557e90be46de20c4cb24c6933152df0a0b058d 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,24 @@
 2005-07-11  Matthias Clasen  <mclasen@redhat.com>
 
+       When dragging text, use a drag icon showing the (ellipsized)
+       text that is being dragged: (#161132, Kevin Duffus, patch
+       by Carlos Garnacho Parro)
+       
+       * gtk/gtktextutil.h: 
+       * gtk/gtktextutil.c (_gtk_text_util_create_drag_icon): Add
+       a function to create a pixmap for use when dragging text.
+
+       * gtk/gtktextview.c (gtk_text_view_start_selection_dnd): 
+       * gtk/gtklabel.c (gtk_label_motion): 
+       * gtk/gtkentry.c (gtk_entry_motion_notify): Use a drag icon
+       showing the text being dragged.  
+
+2005-07-11  Matthias Clasen  <mclasen@redhat.com>
+
+       * gtk/gtkentry.c (gtk_entry_move_forward_word) 
+       (gtk_entry_move_backward_word): Match the text view change
+       to allow selecting whitespace with double-click.
+
        * gtk/gtktextview.c (extend_selection): Make double-clicking
        between words select whitespace.  (#309860, Mike Miller, patch
        by Paolo Borelli)
index a73479ad3011d0e24fb309127789873a200de61c..8b557e90be46de20c4cb24c6933152df0a0b058d 100644 (file)
@@ -1,5 +1,24 @@
 2005-07-11  Matthias Clasen  <mclasen@redhat.com>
 
+       When dragging text, use a drag icon showing the (ellipsized)
+       text that is being dragged: (#161132, Kevin Duffus, patch
+       by Carlos Garnacho Parro)
+       
+       * gtk/gtktextutil.h: 
+       * gtk/gtktextutil.c (_gtk_text_util_create_drag_icon): Add
+       a function to create a pixmap for use when dragging text.
+
+       * gtk/gtktextview.c (gtk_text_view_start_selection_dnd): 
+       * gtk/gtklabel.c (gtk_label_motion): 
+       * gtk/gtkentry.c (gtk_entry_motion_notify): Use a drag icon
+       showing the text being dragged.  
+
+2005-07-11  Matthias Clasen  <mclasen@redhat.com>
+
+       * gtk/gtkentry.c (gtk_entry_move_forward_word) 
+       (gtk_entry_move_backward_word): Match the text view change
+       to allow selecting whitespace with double-click.
+
        * gtk/gtktextview.c (extend_selection): Make double-clicking
        between words select whitespace.  (#309860, Mike Miller, patch
        by Paolo Borelli)
index a73479ad3011d0e24fb309127789873a200de61c..8b557e90be46de20c4cb24c6933152df0a0b058d 100644 (file)
@@ -1,5 +1,24 @@
 2005-07-11  Matthias Clasen  <mclasen@redhat.com>
 
+       When dragging text, use a drag icon showing the (ellipsized)
+       text that is being dragged: (#161132, Kevin Duffus, patch
+       by Carlos Garnacho Parro)
+       
+       * gtk/gtktextutil.h: 
+       * gtk/gtktextutil.c (_gtk_text_util_create_drag_icon): Add
+       a function to create a pixmap for use when dragging text.
+
+       * gtk/gtktextview.c (gtk_text_view_start_selection_dnd): 
+       * gtk/gtklabel.c (gtk_label_motion): 
+       * gtk/gtkentry.c (gtk_entry_motion_notify): Use a drag icon
+       showing the text being dragged.  
+
+2005-07-11  Matthias Clasen  <mclasen@redhat.com>
+
+       * gtk/gtkentry.c (gtk_entry_move_forward_word) 
+       (gtk_entry_move_backward_word): Match the text view change
+       to allow selecting whitespace with double-click.
+
        * gtk/gtktextview.c (extend_selection): Make double-clicking
        between words select whitespace.  (#309860, Mike Miller, patch
        by Paolo Borelli)
index f44e75c20b41222eb9b59dfc7c00be0474eb4f85..748873ee39c0f1254273b32fadbad0d0e8fa8de0 100644 (file)
@@ -1,3 +1,4 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* GTK - The GIMP Toolkit
  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
  *
@@ -1649,6 +1650,49 @@ gtk_entry_button_release (GtkWidget      *widget,
   return TRUE;
 }
 
+static gchar *
+_gtk_entry_get_selected_text (GtkEntry *entry)
+{
+  GtkEditable *editable = GTK_EDITABLE (entry);
+  gint         start_text, end_text;
+  gchar       *text = NULL;
+
+  if (gtk_editable_get_selection_bounds (editable, &start_text, &end_text))
+    text = gtk_editable_get_chars (editable, start_text, end_text);
+
+  return text;
+}
+
+static void
+drag_begin_cb (GtkWidget      *widget,
+               GdkDragContext *context,
+               gpointer        data)
+{
+  GtkEntry *entry;
+  gchar *text;
+  GdkPixmap *pixmap = NULL;
+
+  g_signal_handlers_disconnect_by_func (widget, drag_begin_cb, NULL);
+
+  entry = GTK_ENTRY (widget);
+
+  text = _gtk_entry_get_selected_text (entry);
+  pixmap = _gtk_text_util_create_drag_icon (widget, text, -1);
+
+  if (entry->visible && pixmap)
+    gtk_drag_set_icon_pixmap (context,
+                              gdk_drawable_get_colormap (pixmap),
+                              pixmap,
+                              NULL,
+                              -2, -2);
+  else
+    gtk_drag_set_icon_default (context);
+  
+  if (pixmap)
+    g_object_unref (pixmap);
+  g_free (text);
+}
+
 static gint
 gtk_entry_motion_notify (GtkWidget      *widget,
                         GdkEventMotion *event)
@@ -1678,25 +1722,25 @@ gtk_entry_motion_notify (GtkWidget      *widget,
   if (entry->in_drag)
     {
       if (gtk_drag_check_threshold (widget,
-                                   entry->drag_start_x, entry->drag_start_y,
-                                   event->x + entry->scroll_offset, event->y))
-       {
-         GdkDragContext *context;
-         GtkTargetList *target_list = gtk_target_list_new (NULL, 0);
-         guint actions = entry->editable ? GDK_ACTION_COPY | GDK_ACTION_MOVE : GDK_ACTION_COPY;
+                                    entry->drag_start_x, entry->drag_start_y,
+                                    event->x + entry->scroll_offset, event->y))
+        {
+          GdkDragContext *context;
+          GtkTargetList  *target_list = gtk_target_list_new (NULL, 0);
+          guint actions = entry->editable ? GDK_ACTION_COPY | GDK_ACTION_MOVE : GDK_ACTION_COPY;
 
-         gtk_target_list_add_text_targets (target_list, 0);
+          gtk_target_list_add_text_targets (target_list, 0);
 
-         context = gtk_drag_begin (widget, target_list, actions,
-                         entry->button, (GdkEvent *)event);
+          g_signal_connect (widget, "drag-begin", 
+                            G_CALLBACK (drag_begin_cb), NULL);
+          context = gtk_drag_begin (widget, target_list, actions,
+                                    entry->button, (GdkEvent *)event);
 
+          entry->in_drag = FALSE;
+          entry->button = 0;
          
-         entry->in_drag = FALSE;
-         entry->button = 0;
-         
-         gtk_target_list_unref (target_list);
-         gtk_drag_set_icon_default (context);
-       }
+          gtk_target_list_unref (target_list);
+        }
     }
   else
     {
@@ -3549,9 +3593,9 @@ gtk_entry_move_forward_word (GtkEntry *entry,
 
       pango_layout_get_log_attrs (layout, &log_attrs, &n_attrs);
       
-      /* Find the next word end */
+      /* Find the next word boundary */
       new_pos++;
-      while (new_pos < n_attrs && !log_attrs[new_pos].is_word_end)
+      while (new_pos < n_attrs && !(log_attrs[new_pos].is_word_start || log_attrs[new_pos].is_word_end))
        new_pos++;
 
       g_free (log_attrs);
@@ -3582,8 +3626,8 @@ gtk_entry_move_backward_word (GtkEntry *entry,
 
       new_pos = start - 1;
 
-      /* Find the previous word beginning */
-      while (new_pos > 0 && !log_attrs[new_pos].is_word_start)
+      /* Find the previous word boundary */
+      while (new_pos > 0 && !(log_attrs[new_pos].is_word_start || log_attrs[new_pos].is_word_end))
        new_pos--;
 
       g_free (log_attrs);
index df890c9b8087921410904856c40b35dffd9e1b58..460285a0be3969c96eeedbcd0b4e93d40a32eca6 100644 (file)
@@ -37,6 +37,7 @@
 #include "gtkimagemenuitem.h"
 #include "gtkintl.h"
 #include "gtkseparatormenuitem.h"
+#include "gtktextutil.h"
 #include "gtkmenuitem.h"
 #include "gtknotebook.h"
 #include "gtkstock.h"
@@ -2832,6 +2833,56 @@ gtk_label_button_release (GtkWidget      *widget,
   return TRUE;
 }
 
+static void
+drag_begin_cb (GtkWidget      *widget,
+               GdkDragContext *context,
+               gpointer        data)
+{
+  GtkLabel *label;
+  GdkPixmap *pixmap = NULL;
+
+  g_signal_handlers_disconnect_by_func (widget, drag_begin_cb, NULL);
+
+  label = GTK_LABEL (widget);
+
+  if ((label->select_info->selection_anchor !=
+       label->select_info->selection_end) &&
+      label->text)
+    {
+      gint start, end;
+      gint len;
+      
+      start = MIN (label->select_info->selection_anchor,
+                   label->select_info->selection_end);
+      end = MAX (label->select_info->selection_anchor,
+                 label->select_info->selection_end);
+      
+      len = strlen (label->text);
+      
+      if (end > len)
+        end = len;
+      
+      if (start > len)
+        start = len;
+      
+      pixmap = _gtk_text_util_create_drag_icon (widget, 
+                                               label->text + start,
+                                               end - start);
+    }
+
+  if (pixmap)
+    gtk_drag_set_icon_pixmap (context,
+                              gdk_drawable_get_colormap (pixmap),
+                              pixmap,
+                              NULL,
+                              -2, -2);
+  else
+    gtk_drag_set_icon_default (context);
+  
+  if (pixmap)
+    g_object_unref (pixmap);
+}
+
 static gboolean
 gtk_label_motion (GtkWidget      *widget,
                   GdkEventMotion *event)
@@ -2863,16 +2914,16 @@ gtk_label_motion (GtkWidget      *widget,
          GtkTargetList *target_list = gtk_target_list_new (NULL, 0);
 
          gtk_target_list_add_text_targets (target_list, 0);
-
+         
+          g_signal_connect (widget, "drag-begin", 
+                            G_CALLBACK (drag_begin_cb), NULL);
          context = gtk_drag_begin (widget, target_list, 
                                    GDK_ACTION_COPY,
                                    1, (GdkEvent *)event);
-
          
          label->select_info->in_drag = FALSE;
          
          gtk_target_list_unref (target_list);
-         gtk_drag_set_icon_default (context);
        }
     }
   else
index 9d72c18646dd8e17900f634d183452e01f8ad4c7..e9f535c7c354d31b8dddccbf7a6c0ba8ca1418ca 100644 (file)
@@ -1,3 +1,4 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* GTK - The GIMP Toolkit
  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
  *
 #include "gtkmenuitem.h"
 #include "gtkalias.h"
 
+#define DRAG_ICON_MAX_WIDTH 250
+#define DRAG_ICON_LAYOUT_BORDER 2
+#define DRAG_ICON_MAX_LINES 7
+#define ELLIPSIS_CHARACTER "\xe2\x80\xa6"
+
 typedef struct _GtkUnicodeMenuEntry GtkUnicodeMenuEntry;
 typedef struct _GtkTextUtilCallbackInfo GtkTextUtilCallbackInfo;
 
@@ -117,3 +123,121 @@ _gtk_text_util_append_special_char_menuitems (GtkMenuShell              *menushe
     }
 }
 
+static void
+append_n_lines (GString *str, const gchar *text, GSList *lines, gint n_lines)
+{
+  PangoLayoutLine *line;
+  gint i;
+
+  for (i = 0; i < n_lines; i++)
+    {
+      line = lines->data;
+      g_string_append_len (str, &text[line->start_index], line->length);
+      lines = lines->next;
+    }
+}
+
+static void
+limit_layout_lines (PangoLayout *layout)
+{
+  const gchar *text;
+  GString     *str;
+  GSList      *lines, *elem;
+  gint         n_lines;
+
+  n_lines = pango_layout_get_line_count (layout);
+  
+  if (n_lines >= DRAG_ICON_MAX_LINES)
+    {
+      text  = pango_layout_get_text (layout);
+      str   = g_string_new (NULL);
+      lines = pango_layout_get_lines (layout);
+
+      /* get first lines */
+      elem = lines;
+      append_n_lines (str, text, elem,
+                      DRAG_ICON_MAX_LINES / 2);
+
+      g_string_append (str, "\n" ELLIPSIS_CHARACTER "\n");
+
+      /* get last lines */
+      elem = g_slist_nth (lines, n_lines - DRAG_ICON_MAX_LINES / 2);
+      append_n_lines (str, text, elem,
+                      DRAG_ICON_MAX_LINES / 2);
+
+      pango_layout_set_text (layout, str->str, -1);
+      g_string_free (str, TRUE);
+    }
+}
+
+/**
+ * _gtk_text_util_create_drag_icon
+ * @widget: #GtkWidget to extract the pango context
+ * @text: a #gchar to render the icon
+ * @len: length of @text, or -1 for NUL-terminated text
+ *
+ * Creates a drag and drop icon from @text.
+ **/
+GdkPixmap*
+_gtk_text_util_create_drag_icon (GtkWidget *widget, 
+                                 gchar     *text,
+                                 gsize      len)
+{
+  GdkDrawable  *drawable = NULL;
+  PangoContext *context;
+  PangoLayout  *layout;
+  gint          pixmap_height, pixmap_width;
+  gint          layout_width, layout_height;
+  gint          n_lines;
+
+  g_return_val_if_fail (widget != NULL, NULL);
+  g_return_val_if_fail (text != NULL, NULL);
+
+  context = gtk_widget_get_pango_context (widget);
+  layout  = pango_layout_new (context);
+
+  pango_layout_set_text (layout, text, len);
+  pango_layout_set_wrap (layout, PANGO_WRAP_WORD_CHAR);
+  pango_layout_get_size (layout, &layout_width, &layout_height);
+
+  layout_width = MIN (layout_width, DRAG_ICON_MAX_WIDTH * PANGO_SCALE);
+  pango_layout_set_width (layout, layout_width);
+  n_lines = pango_layout_get_line_count (layout);
+
+  limit_layout_lines (layout);
+
+  /* get again layout extents, they may have changed */
+  pango_layout_get_size (layout, &layout_width, &layout_height);
+
+  pixmap_width  = layout_width  / PANGO_SCALE + DRAG_ICON_LAYOUT_BORDER * 2;
+  pixmap_height = layout_height / PANGO_SCALE + DRAG_ICON_LAYOUT_BORDER * 2;
+
+  drawable = gdk_pixmap_new (widget->window,
+                             pixmap_width  + 2,
+                             pixmap_height + 2,
+                             -1);
+
+  gdk_draw_rectangle (drawable,
+                      widget->style->base_gc [GTK_WIDGET_STATE (widget)],
+                      TRUE,
+                      0, 0,
+                      pixmap_width + 1,
+                      pixmap_height + 1);
+
+  gdk_draw_layout (drawable,
+                   widget->style->text_gc [GTK_WIDGET_STATE (widget)],
+                   1 + DRAG_ICON_LAYOUT_BORDER,
+                   1 + DRAG_ICON_LAYOUT_BORDER,
+                   layout);
+
+  gdk_draw_rectangle (drawable,
+                      widget->style->black_gc,
+                      FALSE,
+                      0, 0,
+                      pixmap_width + 1,
+                      pixmap_height + 1);
+
+  g_object_unref (layout);
+
+  return drawable;
+}
index 2a9b6d3b2f01c4f6572e8a1c566d7df5fb786994..27b900e4355ff98fbf5937400edf411baeb7858f 100644 (file)
@@ -30,6 +30,7 @@
 
 #include <gtk/gtkwidget.h>
 #include <gtk/gtkmenushell.h>
+#include <gtk/gtkeditable.h>
 
 
 G_BEGIN_DECLS
@@ -46,5 +47,8 @@ void _gtk_text_util_append_special_char_menuitems (GtkMenuShell              *me
 
 G_END_DECLS
 
+GdkPixmap* _gtk_text_util_create_drag_icon  (GtkWidget *widget, 
+                                            gchar     *text,
+                                            gsize      len);
 
 #endif /* __GTK_TEXT_UTIL_H__ */
index 9a1aa7300721b0640f7fb4bc5a95a08dcde88c73..0b5c7322c54e883807f5819e79c11a5391f24d53 100644 (file)
@@ -1,3 +1,4 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* GTK - The GIMP Toolkit
  * gtktextview.c Copyright (C) 2000 Red Hat, Inc.
  *
@@ -5977,17 +5978,62 @@ gtk_text_view_reset_im_context (GtkTextView *text_view)
     }
 }
 
+static gchar*
+_gtk_text_view_get_selected_text (GtkTextView *text_view)
+{
+  GtkTextBuffer *buffer;
+  GtkTextIter    start, end;
+  gchar         *text = NULL;
+
+  buffer = gtk_text_view_get_buffer (text_view);
+
+  if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
+    text = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
+
+  return text;
+}
+
 /*
  * DND feature
  */
 
+static void
+drag_begin_cb (GtkWidget      *widget,
+               GdkDragContext *context,
+               gpointer        data)
+{
+  GtkTextView *text_view;
+  gchar *text;
+  GdkPixmap *pixmap = NULL;
+
+  g_signal_handlers_disconnect_by_func (widget, drag_begin_cb, NULL);
+
+  text_view = GTK_TEXT_VIEW (widget);
+
+  text   = _gtk_text_view_get_selected_text (text_view);
+  pixmap = _gtk_text_util_create_drag_icon (widget, text, -1);
+
+  if (pixmap)
+    gtk_drag_set_icon_pixmap (context,
+                              gdk_drawable_get_colormap (pixmap),
+                              pixmap,
+                              NULL,
+                              -2, -2);
+  else
+    gtk_drag_set_icon_default (context);
+  
+  if (pixmap)
+    g_object_unref (pixmap);
+  g_free (text);
+}
+
 static void
 gtk_text_view_start_selection_dnd (GtkTextView       *text_view,
                                    const GtkTextIter *iter,
                                    GdkEventMotion    *event)
 {
   GdkDragContext *context;
-  GtkTargetList *target_list;
+  GtkTargetList  *target_list;
 
   text_view->drag_start_x = -1;
   text_view->drag_start_y = -1;
@@ -5997,13 +6043,13 @@ gtk_text_view_start_selection_dnd (GtkTextView       *text_view,
                                      G_N_ELEMENTS (target_table));
   gtk_target_list_add_text_targets (target_list, 0);
 
+  g_signal_connect (text_view, "drag-begin", 
+                    G_CALLBACK (drag_begin_cb), NULL);
   context = gtk_drag_begin (GTK_WIDGET (text_view), target_list,
                             GDK_ACTION_COPY | GDK_ACTION_MOVE,
                             1, (GdkEvent*)event);
 
   gtk_target_list_unref (target_list);
-
-  gtk_drag_set_icon_default (context);
 }
 
 static void