When dragging text, use a drag icon showing the (ellipsized) text that is

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.
This commit is contained in:
Matthias Clasen 2005-07-11 17:51:54 +00:00 committed by Matthias Clasen
parent 7912643e8f
commit 13a341e0e9
8 changed files with 351 additions and 25 deletions

View 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)

View 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)

View 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)

View 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);

View 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

View 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
*
@ -30,6 +31,11 @@
#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;
}

View 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__ */

View 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