1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 * Modified by the GTK+ Team and others 1997-2001. See the AUTHORS
22 * file for a list of people on the GTK+ Team. See the ChangeLog
23 * files for a list of changes. These files are distributed with
24 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
28 #include "gtktextutil.h"
30 #include "gtkmenuitem.h"
33 #define DRAG_ICON_MAX_WIDTH 250
34 #define DRAG_ICON_LAYOUT_BORDER 2
35 #define DRAG_ICON_MAX_LINES 7
36 #define ELLIPSIS_CHARACTER "\xe2\x80\xa6"
38 typedef struct _GtkUnicodeMenuEntry GtkUnicodeMenuEntry;
39 typedef struct _GtkTextUtilCallbackInfo GtkTextUtilCallbackInfo;
41 struct _GtkUnicodeMenuEntry {
46 struct _GtkTextUtilCallbackInfo
48 GtkTextUtilCharChosenFunc func;
52 static const GtkUnicodeMenuEntry bidi_menu_entries[] = {
53 { N_("LRM _Left-to-right mark"), 0x200E },
54 { N_("RLM _Right-to-left mark"), 0x200F },
55 { N_("LRE Left-to-right _embedding"), 0x202A },
56 { N_("RLE Right-to-left e_mbedding"), 0x202B },
57 { N_("LRO Left-to-right _override"), 0x202D },
58 { N_("RLO Right-to-left o_verride"), 0x202E },
59 { N_("PDF _Pop directional formatting"), 0x202C },
60 { N_("ZWS _Zero width space"), 0x200B },
61 { N_("ZWJ Zero width _joiner"), 0x200D },
62 { N_("ZWNJ Zero width _non-joiner"), 0x200C }
66 activate_cb (GtkWidget *menu_item,
69 GtkUnicodeMenuEntry *entry;
70 GtkTextUtilCallbackInfo *info = data;
73 entry = g_object_get_data (G_OBJECT (menu_item), "gtk-unicode-menu-entry");
75 buf[g_unichar_to_utf8 (entry->ch, buf)] = '\0';
77 (* info->func) (buf, info->data);
81 * _gtk_text_util_append_special_char_menuitems
82 * @menushell: a #GtkMenuShell
83 * @callback: call this when an item is chosen
84 * @data: data for callback
86 * Add menuitems for various bidi control characters to a menu;
87 * the menuitems, when selected, will call the given function
88 * with the chosen character.
90 * This function is private/internal in GTK 2.0, the functionality may
91 * become public sometime, but it probably needs more thought first.
92 * e.g. maybe there should be a way to just get the list of items,
93 * instead of requiring the menu items to be created.
96 _gtk_text_util_append_special_char_menuitems (GtkMenuShell *menushell,
97 GtkTextUtilCharChosenFunc func,
102 for (i = 0; i < G_N_ELEMENTS (bidi_menu_entries); i++)
105 GtkTextUtilCallbackInfo *info;
107 /* wasteful to have a bunch of copies, but simplifies mem management */
108 info = g_new (GtkTextUtilCallbackInfo, 1);
112 menuitem = gtk_menu_item_new_with_mnemonic (_(bidi_menu_entries[i].label));
113 g_object_set_data (G_OBJECT (menuitem), I_("gtk-unicode-menu-entry"),
114 (gpointer)&bidi_menu_entries[i]);
116 g_signal_connect_data (menuitem, "activate",
117 G_CALLBACK (activate_cb),
118 info, (GClosureNotify) g_free, 0);
120 gtk_widget_show (menuitem);
121 gtk_menu_shell_append (menushell, menuitem);
126 append_n_lines (GString *str, const gchar *text, GSList *lines, gint n_lines)
128 PangoLayoutLine *line;
131 for (i = 0; i < n_lines; i++)
134 g_string_append_len (str, &text[line->start_index], line->length);
140 limit_layout_lines (PangoLayout *layout)
144 GSList *lines, *elem;
147 n_lines = pango_layout_get_line_count (layout);
149 if (n_lines >= DRAG_ICON_MAX_LINES)
151 text = pango_layout_get_text (layout);
152 str = g_string_new (NULL);
153 lines = pango_layout_get_lines (layout);
155 /* get first lines */
157 append_n_lines (str, text, elem,
158 DRAG_ICON_MAX_LINES / 2);
160 g_string_append (str, "\n" ELLIPSIS_CHARACTER "\n");
163 elem = g_slist_nth (lines, n_lines - DRAG_ICON_MAX_LINES / 2);
164 append_n_lines (str, text, elem,
165 DRAG_ICON_MAX_LINES / 2);
167 pango_layout_set_text (layout, str->str, -1);
168 g_string_free (str, TRUE);
173 * _gtk_text_util_create_drag_icon
174 * @widget: #GtkWidget to extract the pango context
175 * @text: a #gchar to render the icon
176 * @len: length of @text, or -1 for NUL-terminated text
178 * Creates a drag and drop icon from @text.
181 _gtk_text_util_create_drag_icon (GtkWidget *widget,
185 GdkDrawable *drawable = NULL;
186 PangoContext *context;
188 gint pixmap_height, pixmap_width;
189 gint layout_width, layout_height;
192 g_return_val_if_fail (widget != NULL, NULL);
193 g_return_val_if_fail (text != NULL, NULL);
195 context = gtk_widget_get_pango_context (widget);
196 layout = pango_layout_new (context);
198 pango_layout_set_text (layout, text, len);
199 pango_layout_set_wrap (layout, PANGO_WRAP_WORD_CHAR);
200 pango_layout_get_size (layout, &layout_width, &layout_height);
202 layout_width = MIN (layout_width, DRAG_ICON_MAX_WIDTH * PANGO_SCALE);
203 pango_layout_set_width (layout, layout_width);
204 n_lines = pango_layout_get_line_count (layout);
206 limit_layout_lines (layout);
208 /* get again layout extents, they may have changed */
209 pango_layout_get_size (layout, &layout_width, &layout_height);
211 pixmap_width = layout_width / PANGO_SCALE + DRAG_ICON_LAYOUT_BORDER * 2;
212 pixmap_height = layout_height / PANGO_SCALE + DRAG_ICON_LAYOUT_BORDER * 2;
214 drawable = gdk_pixmap_new (widget->window,
219 gdk_draw_rectangle (drawable,
220 widget->style->base_gc [GTK_WIDGET_STATE (widget)],
226 gdk_draw_layout (drawable,
227 widget->style->text_gc [GTK_WIDGET_STATE (widget)],
228 1 + DRAG_ICON_LAYOUT_BORDER,
229 1 + DRAG_ICON_LAYOUT_BORDER,
232 gdk_draw_rectangle (drawable,
233 widget->style->black_gc,
239 g_object_unref (layout);