]> Pileus Git - ~andy/gtk/blob - gtk/gtktextutil.c
Intern some more strings.
[~andy/gtk] / gtk / gtktextutil.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
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.
8  *
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.
13  *
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.
18  */
19
20 /*
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/. 
25  */
26
27 #include <config.h>
28 #include "gtktextutil.h"
29 #include "gtkintl.h"
30 #include "gtkmenuitem.h"
31 #include "gtkalias.h"
32
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"
37
38 typedef struct _GtkUnicodeMenuEntry GtkUnicodeMenuEntry;
39 typedef struct _GtkTextUtilCallbackInfo GtkTextUtilCallbackInfo;
40
41 struct _GtkUnicodeMenuEntry {
42   const char *label;
43   gunichar ch;
44 };
45
46 struct _GtkTextUtilCallbackInfo
47 {
48   GtkTextUtilCharChosenFunc func;
49   gpointer data;
50 };
51
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 }
63 };
64
65 static void
66 activate_cb (GtkWidget *menu_item,
67              gpointer   data)
68 {
69   GtkUnicodeMenuEntry *entry;
70   GtkTextUtilCallbackInfo *info = data;
71   char buf[7];
72   
73   entry = g_object_get_data (G_OBJECT (menu_item), "gtk-unicode-menu-entry");
74
75   buf[g_unichar_to_utf8 (entry->ch, buf)] = '\0';
76   
77   (* info->func) (buf, info->data);
78 }
79
80 /**
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
85  * 
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.
89  *
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.
94  **/
95 void
96 _gtk_text_util_append_special_char_menuitems (GtkMenuShell              *menushell,
97                                               GtkTextUtilCharChosenFunc  func,
98                                               gpointer                   data)
99 {
100   int i;
101   
102   for (i = 0; i < G_N_ELEMENTS (bidi_menu_entries); i++)
103     {
104       GtkWidget *menuitem;
105       GtkTextUtilCallbackInfo *info;
106
107       /* wasteful to have a bunch of copies, but simplifies mem management */
108       info = g_new (GtkTextUtilCallbackInfo, 1);
109       info->func = func;
110       info->data = data;
111       
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]);
115       
116       g_signal_connect_data (menuitem, "activate",
117                              G_CALLBACK (activate_cb),
118                              info, (GClosureNotify) g_free, 0);
119       
120       gtk_widget_show (menuitem);
121       gtk_menu_shell_append (menushell, menuitem);
122     }
123 }
124
125 static void
126 append_n_lines (GString *str, const gchar *text, GSList *lines, gint n_lines)
127 {
128   PangoLayoutLine *line;
129   gint i;
130
131   for (i = 0; i < n_lines; i++)
132     {
133       line = lines->data;
134       g_string_append_len (str, &text[line->start_index], line->length);
135       lines = lines->next;
136     }
137 }
138
139 static void
140 limit_layout_lines (PangoLayout *layout)
141 {
142   const gchar *text;
143   GString     *str;
144   GSList      *lines, *elem;
145   gint         n_lines;
146
147   n_lines = pango_layout_get_line_count (layout);
148   
149   if (n_lines >= DRAG_ICON_MAX_LINES)
150     {
151       text  = pango_layout_get_text (layout);
152       str   = g_string_new (NULL);
153       lines = pango_layout_get_lines (layout);
154
155       /* get first lines */
156       elem = lines;
157       append_n_lines (str, text, elem,
158                       DRAG_ICON_MAX_LINES / 2);
159
160       g_string_append (str, "\n" ELLIPSIS_CHARACTER "\n");
161
162       /* get last lines */
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);
166
167       pango_layout_set_text (layout, str->str, -1);
168       g_string_free (str, TRUE);
169     }
170 }
171
172 /**
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
177  *
178  * Creates a drag and drop icon from @text.
179  **/
180 GdkPixmap*
181 _gtk_text_util_create_drag_icon (GtkWidget *widget, 
182                                  gchar     *text,
183                                  gsize      len)
184 {
185   GdkDrawable  *drawable = NULL;
186   PangoContext *context;
187   PangoLayout  *layout;
188   gint          pixmap_height, pixmap_width;
189   gint          layout_width, layout_height;
190   gint          n_lines;
191
192   g_return_val_if_fail (widget != NULL, NULL);
193   g_return_val_if_fail (text != NULL, NULL);
194
195   context = gtk_widget_get_pango_context (widget);
196   layout  = pango_layout_new (context);
197
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);
201
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);
205
206   limit_layout_lines (layout);
207
208   /* get again layout extents, they may have changed */
209   pango_layout_get_size (layout, &layout_width, &layout_height);
210
211   pixmap_width  = layout_width  / PANGO_SCALE + DRAG_ICON_LAYOUT_BORDER * 2;
212   pixmap_height = layout_height / PANGO_SCALE + DRAG_ICON_LAYOUT_BORDER * 2;
213
214   drawable = gdk_pixmap_new (widget->window,
215                              pixmap_width  + 2,
216                              pixmap_height + 2,
217                              -1);
218
219   gdk_draw_rectangle (drawable,
220                       widget->style->base_gc [GTK_WIDGET_STATE (widget)],
221                       TRUE,
222                       0, 0,
223                       pixmap_width + 1,
224                       pixmap_height + 1);
225
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,
230                    layout);
231
232   gdk_draw_rectangle (drawable,
233                       widget->style->black_gc,
234                       FALSE,
235                       0, 0,
236                       pixmap_width + 1,
237                       pixmap_height + 1);
238
239   g_object_unref (layout);
240
241   return drawable;
242 }