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)
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)
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)
+/* -*- 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
*
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)
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
{
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);
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);
#include "gtkimagemenuitem.h"
#include "gtkintl.h"
#include "gtkseparatormenuitem.h"
+#include "gtktextutil.h"
#include "gtkmenuitem.h"
#include "gtknotebook.h"
#include "gtkstock.h"
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)
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
+/* -*- 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;
}
}
+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;
+}
#include <gtk/gtkwidget.h>
#include <gtk/gtkmenushell.h>
+#include <gtk/gtkeditable.h>
G_BEGIN_DECLS
G_END_DECLS
+GdkPixmap* _gtk_text_util_create_drag_icon (GtkWidget *widget,
+ gchar *text,
+ gsize len);
#endif /* __GTK_TEXT_UTIL_H__ */
+/* -*- 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.
*
}
}
+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;
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