0
|
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 Library 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 * Library General Public License for more details.
|
|
13 *
|
|
14 * You should have received a copy of the GNU Library 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-1999. 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 /*
|
|
28 * Small modification of the entry widget where keyboard navigation
|
|
29 * works even when the entry is not editable.
|
|
30 * Copyright 2003 Haavard Kvaalen <havardk@xmms.org>
|
|
31 */
|
|
32
|
|
33 #include <glib.h>
|
|
34 #include <gtk/gtk.h>
|
|
35 #include <gdk/gdkkeysyms.h>
|
|
36 #include <ctype.h>
|
|
37 #include <string.h>
|
|
38
|
|
39 #include "xentry.h"
|
|
40
|
|
41 static gint gtk_entry_key_press(GtkWidget * widget, GdkEventKey * event);
|
|
42 static void gtk_entry_move_cursor(GtkOldEditable * editable, int x);
|
|
43
|
|
44 static void gtk_move_forward_character(GtkEntry * entry);
|
|
45 static void gtk_move_backward_character(GtkEntry * entry);
|
|
46 static void gtk_move_forward_word(GtkEntry * entry);
|
|
47 static void gtk_move_backward_word(GtkEntry * entry);
|
|
48 static void gtk_move_beginning_of_line(GtkEntry * entry);
|
|
49 static void gtk_move_end_of_line(GtkEntry * entry);
|
|
50
|
|
51
|
|
52 static const GtkTextFunction control_keys[26] = {
|
|
53 (GtkTextFunction) gtk_move_beginning_of_line, /* a */
|
|
54 (GtkTextFunction) gtk_move_backward_character, /* b */
|
|
55 (GtkTextFunction) gtk_editable_copy_clipboard, /* c */
|
|
56 NULL, /* d */
|
|
57 (GtkTextFunction) gtk_move_end_of_line, /* e */
|
|
58 (GtkTextFunction) gtk_move_forward_character, /* f */
|
|
59 };
|
|
60
|
|
61 static const GtkTextFunction alt_keys[26] = {
|
|
62 NULL, /* a */
|
|
63 (GtkTextFunction) gtk_move_backward_word, /* b */
|
|
64 NULL, /* c */
|
|
65 NULL, /* d */
|
|
66 NULL, /* e */
|
|
67 (GtkTextFunction) gtk_move_forward_word, /* f */
|
|
68 };
|
|
69
|
|
70
|
|
71 static void
|
|
72 xmms_entry_class_init(GtkEntryClass * class)
|
|
73 {
|
|
74 GtkWidgetClass *widget_class = (GtkWidgetClass *) class;
|
|
75
|
|
76 widget_class->key_press_event = gtk_entry_key_press;
|
|
77 }
|
|
78
|
|
79 GtkType
|
|
80 xmms_entry_get_type(void)
|
|
81 {
|
|
82 static GtkType entry_type = 0;
|
|
83
|
|
84 if (!entry_type) {
|
|
85 static const GtkTypeInfo entry_info = {
|
|
86 "XmmsEntry",
|
|
87 sizeof(XmmsEntry),
|
|
88 sizeof(XmmsEntryClass),
|
|
89 (GtkClassInitFunc) xmms_entry_class_init,
|
|
90 NULL,
|
|
91 /* reserved_1 */ NULL,
|
|
92 /* reserved_2 */ NULL,
|
|
93 (GtkClassInitFunc) NULL,
|
|
94 };
|
|
95
|
|
96 entry_type = gtk_type_unique(GTK_TYPE_ENTRY, &entry_info);
|
|
97 }
|
|
98
|
|
99 return entry_type;
|
|
100 }
|
|
101
|
|
102 GtkWidget *
|
|
103 xmms_entry_new(void)
|
|
104 {
|
|
105 return GTK_WIDGET(gtk_type_new(XMMS_TYPE_ENTRY));
|
|
106 }
|
|
107
|
|
108 static int
|
|
109 gtk_entry_key_press(GtkWidget * widget, GdkEventKey * event)
|
|
110 {
|
|
111 GtkEntry *entry;
|
|
112 GtkOldEditable *editable;
|
|
113
|
|
114 int return_val;
|
|
115 guint initial_pos, sel_start_pos, sel_end_pos;
|
|
116 int extend_selection;
|
|
117 gboolean extend_start = FALSE;
|
|
118
|
|
119 g_return_val_if_fail(widget != NULL, FALSE);
|
|
120 g_return_val_if_fail(XMMS_IS_ENTRY(widget), FALSE);
|
|
121 g_return_val_if_fail(event != NULL, FALSE);
|
|
122
|
|
123 entry = GTK_ENTRY(widget);
|
|
124 editable = GTK_OLD_EDITABLE(widget);
|
|
125 return_val = FALSE;
|
|
126
|
|
127 if (editable->editable)
|
|
128 /* Let the regular entry handler do it */
|
|
129 return FALSE;
|
|
130
|
|
131 initial_pos = gtk_editable_get_position(GTK_EDITABLE(editable));
|
|
132
|
|
133 extend_selection = event->state & GDK_SHIFT_MASK;
|
|
134
|
|
135 sel_start_pos = editable->selection_start_pos;
|
|
136 sel_end_pos = editable->selection_end_pos;
|
|
137
|
|
138 if (extend_selection) {
|
|
139 if (sel_start_pos == sel_end_pos) {
|
|
140 sel_start_pos = editable->current_pos;
|
|
141 sel_end_pos = editable->current_pos;
|
|
142 }
|
|
143
|
|
144 extend_start = (editable->current_pos == sel_start_pos);
|
|
145 }
|
|
146
|
|
147 switch (event->keyval) {
|
|
148 case GDK_Insert:
|
|
149 return_val = TRUE;
|
|
150 if (event->state & GDK_CONTROL_MASK)
|
|
151 gtk_editable_copy_clipboard(GTK_EDITABLE(editable));
|
|
152 break;
|
|
153 case GDK_Home:
|
|
154 return_val = TRUE;
|
|
155 gtk_move_beginning_of_line(entry);
|
|
156 break;
|
|
157 case GDK_End:
|
|
158 return_val = TRUE;
|
|
159 gtk_move_end_of_line(entry);
|
|
160 break;
|
|
161 case GDK_Left:
|
|
162 return_val = TRUE;
|
|
163 if (!extend_selection && sel_start_pos != sel_end_pos) {
|
|
164 gtk_editable_set_position(GTK_EDITABLE(editable),
|
|
165 MIN(sel_start_pos, sel_end_pos));
|
|
166 /* Force redraw below */
|
|
167 initial_pos = -1;
|
|
168 }
|
|
169 else
|
|
170 gtk_move_backward_character(entry);
|
|
171 break;
|
|
172 case GDK_Right:
|
|
173 return_val = TRUE;
|
|
174 if (!extend_selection && sel_start_pos != sel_end_pos) {
|
|
175 gtk_editable_set_position(GTK_EDITABLE(editable),
|
|
176 MAX(sel_start_pos, sel_end_pos));
|
|
177 /* Force redraw below */
|
|
178 initial_pos = -1;
|
|
179 }
|
|
180 else
|
|
181 gtk_move_forward_character(entry);
|
|
182 break;
|
|
183 case GDK_Return:
|
|
184 return_val = TRUE;
|
|
185 gtk_widget_activate(widget);
|
|
186 break;
|
|
187 default:
|
|
188 if ((event->keyval >= 0x20) && (event->keyval <= 0xFF)) {
|
|
189 int key = event->keyval;
|
|
190
|
|
191 if (key >= 'A' && key <= 'Z')
|
|
192 key -= 'A' - 'a';
|
|
193
|
|
194 if (key >= 'a' && key <= 'z')
|
|
195 key -= 'a';
|
|
196 else
|
|
197 break;
|
|
198
|
|
199 if (event->state & GDK_CONTROL_MASK) {
|
|
200 if (control_keys[key]) {
|
|
201 (*control_keys[key]) (editable, event->time);
|
|
202 return_val = TRUE;
|
|
203 }
|
|
204 break;
|
|
205 }
|
|
206 else if (event->state & GDK_MOD1_MASK) {
|
|
207 if (alt_keys[key]) {
|
|
208 (*alt_keys[key]) (editable, event->time);
|
|
209 return_val = TRUE;
|
|
210 }
|
|
211 break;
|
|
212 }
|
|
213 }
|
|
214 }
|
|
215
|
|
216 if (return_val && (editable->current_pos != initial_pos)) {
|
|
217 if (extend_selection) {
|
|
218 int cpos = gtk_editable_get_position(GTK_EDITABLE(editable));
|
|
219 if (cpos < sel_start_pos)
|
|
220 sel_start_pos = cpos;
|
|
221 else if (cpos > sel_end_pos)
|
|
222 sel_end_pos = cpos;
|
|
223 else {
|
|
224 if (extend_start)
|
|
225 sel_start_pos = cpos;
|
|
226 else
|
|
227 sel_end_pos = cpos;
|
|
228 }
|
|
229 }
|
|
230 else {
|
|
231 sel_start_pos = 0;
|
|
232 sel_end_pos = 0;
|
|
233 }
|
|
234
|
|
235 gtk_editable_select_region(GTK_EDITABLE(editable), sel_start_pos,
|
|
236 sel_end_pos);
|
|
237 }
|
|
238
|
|
239 return return_val;
|
|
240 }
|
|
241
|
|
242 static void
|
|
243 gtk_entry_move_cursor(GtkOldEditable * editable, int x)
|
|
244 {
|
|
245 int set, pos = gtk_editable_get_position(GTK_EDITABLE(editable));
|
|
246 if (pos + x < 0)
|
|
247 set = 0;
|
|
248 else
|
|
249 set = pos + x;
|
|
250 gtk_editable_set_position(GTK_EDITABLE(editable), set);
|
|
251 }
|
|
252
|
|
253 static void
|
|
254 gtk_move_forward_character(GtkEntry * entry)
|
|
255 {
|
|
256 gtk_entry_move_cursor(GTK_OLD_EDITABLE(entry), 1);
|
|
257 }
|
|
258
|
|
259 static void
|
|
260 gtk_move_backward_character(GtkEntry * entry)
|
|
261 {
|
|
262 gtk_entry_move_cursor(GTK_OLD_EDITABLE(entry), -1);
|
|
263 }
|
|
264
|
|
265 static void
|
|
266 gtk_move_forward_word(GtkEntry * entry)
|
|
267 {
|
|
268 GtkOldEditable *editable;
|
|
269 GdkWChar *text;
|
|
270 int i;
|
|
271
|
|
272 editable = GTK_OLD_EDITABLE(entry);
|
|
273
|
|
274 /* Prevent any leak of information */
|
|
275 if (!editable->visible) {
|
|
276 gtk_editable_set_position(GTK_EDITABLE(entry), -1);
|
|
277 return;
|
|
278 }
|
|
279
|
|
280 if (entry->text && (editable->current_pos < entry->text_length)) {
|
|
281 text = (GdkWChar *) entry->text;
|
|
282 i = editable->current_pos;
|
|
283
|
|
284 /* if ((entry->use_wchar && !gdk_iswalnum(text[i])) ||
|
|
285 !isalnum(text[i]))
|
|
286 for (; i < entry->text_length; i++)
|
|
287 {
|
|
288 if (entry->use_wchar)
|
|
289 {
|
|
290 if (gdk_iswalnum(text[i]))
|
|
291 break;
|
|
292 else if (isalnum(text[i]))
|
|
293 break;
|
|
294 }
|
|
295 }
|
|
296
|
|
297 for (; i < entry->text_length; i++)
|
|
298 {
|
|
299 if (entry->use_wchar)
|
|
300 {
|
|
301 if (gdk_iswalnum(text[i]))
|
|
302 break;
|
|
303 else if (isalnum(text[i]))
|
|
304 break;
|
|
305 }
|
|
306 }
|
|
307
|
|
308 */
|
|
309
|
|
310 gtk_editable_set_position(GTK_EDITABLE(entry), i);
|
|
311 }
|
|
312 }
|
|
313
|
|
314 static void
|
|
315 gtk_move_backward_word(GtkEntry * entry)
|
|
316 {
|
|
317 GtkOldEditable *editable;
|
|
318 GdkWChar *text;
|
|
319 int i;
|
|
320
|
|
321 editable = GTK_OLD_EDITABLE(entry);
|
|
322
|
|
323 /* Prevent any leak of information */
|
|
324 if (!editable->visible) {
|
|
325 gtk_editable_set_position(GTK_EDITABLE(entry), 0);
|
|
326 return;
|
|
327 }
|
|
328
|
|
329 if (entry->text && editable->current_pos > 0) {
|
|
330 text = (GdkWChar *) entry->text;
|
|
331 i = editable->current_pos;
|
|
332
|
|
333 /* if ((entry->use_wchar && !gdk_iswalnum(text[i])) ||
|
|
334 !isalnum(text[i]))
|
|
335 for (; i >= 0; i--)
|
|
336 {
|
|
337 if (entry->use_wchar)
|
|
338 {
|
|
339 if (gdk_iswalnum(text[i]))
|
|
340 break;
|
|
341 else if (isalnum(text[i]))
|
|
342 break;
|
|
343 }
|
|
344 }
|
|
345 for (; i >= 0; i--)
|
|
346 {
|
|
347 if ((entry->use_wchar && !gdk_iswalnum(text[i])) ||
|
|
348 !isalnum(text[i]))
|
|
349 {
|
|
350 i++;
|
|
351 break;
|
|
352 }
|
|
353 }
|
|
354 */
|
|
355 if (i < 0)
|
|
356 i = 0;
|
|
357
|
|
358 gtk_editable_set_position(GTK_EDITABLE(entry), i);
|
|
359 }
|
|
360 }
|
|
361
|
|
362 static void
|
|
363 gtk_move_beginning_of_line(GtkEntry * entry)
|
|
364 {
|
|
365 gtk_editable_set_position(GTK_EDITABLE(entry), 0);
|
|
366 }
|
|
367
|
|
368 static void
|
|
369 gtk_move_end_of_line(GtkEntry * entry)
|
|
370 {
|
|
371 gtk_editable_set_position(GTK_EDITABLE(entry), -1);
|
|
372 }
|