]> Pileus Git - ~andy/gtk/blob - gtk/gtkaccellabel.c
changed reversed_[12] to reserved_[12] in gtk_*_get_type functions.
[~andy/gtk] / gtk / gtkaccellabel.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * GtkAccelLabel: GtkLabel with accelerator monitoring facilities.
5  * Copyright (C) 1998 Tim Janik
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22 #include <string.h>
23 #include <ctype.h>
24 #include "gtkmain.h"
25 #include "gtksignal.h"
26 #include "gtkaccellabel.h"
27
28
29 enum {
30   ARG_0,
31   ARG_ACCEL_WIDGET,
32 };
33
34 static void gtk_accel_label_class_init   (GtkAccelLabelClass  *klass);
35 static void gtk_accel_label_init         (GtkAccelLabel       *accel_label);
36 static void gtk_accel_label_set_arg      (GtkObject      *object,
37                                           GtkArg         *arg,
38                                           guint           arg_id);
39 static void gtk_accel_label_get_arg      (GtkObject      *object,
40                                           GtkArg         *arg,
41                                           guint           arg_id);
42 static void gtk_accel_label_destroy      (GtkObject      *object);
43 static void gtk_accel_label_finalize     (GtkObject      *object);
44 static void gtk_accel_label_size_request (GtkWidget      *widget,
45                                           GtkRequisition *requisition);
46 static gint gtk_accel_label_expose_event (GtkWidget      *widget,
47                                           GdkEventExpose *event);
48
49 static GtkAccelLabelClass *accel_label_class = NULL;
50 static GtkLabelClass *parent_class = NULL;
51
52
53 GtkType
54 gtk_accel_label_get_type (void)
55 {
56   static GtkType accel_label_type = 0;
57   
58   if (!accel_label_type)
59     {
60       GtkTypeInfo accel_label_info =
61       {
62         "GtkAccelLabel",
63         sizeof (GtkAccelLabel),
64         sizeof (GtkAccelLabelClass),
65         (GtkClassInitFunc) gtk_accel_label_class_init,
66         (GtkObjectInitFunc) gtk_accel_label_init,
67         /* reserved_1 */ NULL,
68         /* reserved_2 */ NULL,
69         (GtkClassInitFunc) NULL,
70       };
71       
72       accel_label_type = gtk_type_unique (gtk_label_get_type (), &accel_label_info);
73     }
74   
75   return accel_label_type;
76 }
77
78 static void
79 gtk_accel_label_class_init (GtkAccelLabelClass *class)
80 {
81   GtkObjectClass *object_class;
82   GtkWidgetClass *widget_class;
83   GtkMiscClass *misc_class;
84   GtkLabelClass *label_class;
85   
86   accel_label_class = class;
87   object_class = (GtkObjectClass*) class;
88   widget_class = (GtkWidgetClass*) class;
89   misc_class = (GtkMiscClass*) class;
90   label_class = (GtkLabelClass*) class;
91   
92   parent_class = gtk_type_class (gtk_label_get_type ());
93   
94   gtk_object_add_arg_type ("GtkAccelLabel::accel_widget", GTK_TYPE_WIDGET, GTK_ARG_READWRITE, ARG_ACCEL_WIDGET);
95
96   object_class->set_arg = gtk_accel_label_set_arg;
97   object_class->get_arg = gtk_accel_label_get_arg;
98   object_class->destroy = gtk_accel_label_destroy;
99   object_class->finalize = gtk_accel_label_finalize;
100   
101   widget_class->size_request = gtk_accel_label_size_request;
102   widget_class->expose_event = gtk_accel_label_expose_event;
103
104   class->signal_quote1 = g_strdup ("<:");
105   class->signal_quote2 = g_strdup (":>");
106   class->mod_name_shift = g_strdup ("Shft");
107   class->mod_name_control = g_strdup ("Ctl");
108   class->mod_name_alt = g_strdup ("Alt");
109   class->mod_separator = g_strdup ("+");
110   class->accel_seperator = g_strdup (" / ");
111   class->latin1_to_char = TRUE;
112 }
113
114 static void
115 gtk_accel_label_set_arg (GtkObject      *object,
116                          GtkArg         *arg,
117                          guint           arg_id)
118 {
119   GtkAccelLabel  *accel_label;
120
121   accel_label = GTK_ACCEL_LABEL (object);
122
123   switch (arg_id)
124     {
125     case ARG_ACCEL_WIDGET:
126       gtk_accel_label_set_accel_widget (accel_label, (GtkWidget*) GTK_VALUE_OBJECT (*arg));
127       break;
128     default:
129       break;
130     }
131 }
132
133 static void
134 gtk_accel_label_get_arg (GtkObject      *object,
135                          GtkArg         *arg,
136                          guint           arg_id)
137 {
138   GtkAccelLabel  *accel_label;
139
140   accel_label = GTK_ACCEL_LABEL (object);
141
142   switch (arg_id)
143     {
144     case ARG_ACCEL_WIDGET:
145       GTK_VALUE_OBJECT (*arg) = (GtkObject*) accel_label->accel_widget;
146       break;
147     default:
148       arg->type = GTK_TYPE_INVALID;
149       break;
150     }
151 }
152
153 static void
154 gtk_accel_label_init (GtkAccelLabel *accel_label)
155 {
156   accel_label->queue_id = 0;
157   accel_label->accel_padding = 3;
158   accel_label->accel_widget = NULL;
159   accel_label->accel_string = NULL;
160   
161   gtk_accel_label_refetch (accel_label);
162 }
163
164 GtkWidget*
165 gtk_accel_label_new (const gchar *string)
166 {
167   GtkAccelLabel *accel_label;
168   
169   g_return_val_if_fail (string != NULL, NULL);
170   
171   accel_label = gtk_type_new (GTK_TYPE_ACCEL_LABEL);
172   
173   gtk_label_set (GTK_LABEL (accel_label), string);
174   
175   return GTK_WIDGET (accel_label);
176 }
177
178 static void
179 gtk_accel_label_destroy (GtkObject *object)
180 {
181   GtkAccelLabel *accel_label;
182   
183   g_return_if_fail (object != NULL);
184   g_return_if_fail (GTK_IS_ACCEL_LABEL (object));
185   
186   accel_label = GTK_ACCEL_LABEL (object);
187
188   gtk_accel_label_set_accel_widget (accel_label, NULL);
189   
190   GTK_OBJECT_CLASS (parent_class)->destroy (object);
191 }
192
193 static void
194 gtk_accel_label_finalize (GtkObject *object)
195 {
196   GtkAccelLabel *accel_label;
197   
198   g_return_if_fail (object != NULL);
199   g_return_if_fail (GTK_IS_ACCEL_LABEL (object));
200   
201   accel_label = GTK_ACCEL_LABEL (object);
202   
203   g_free (accel_label->accel_string);
204   
205   GTK_OBJECT_CLASS (parent_class)->finalize (object);
206 }
207
208 guint
209 gtk_accel_label_accelerator_width (GtkAccelLabel *accel_label)
210 {
211   g_return_val_if_fail (accel_label != NULL, 0);
212   g_return_val_if_fail (GTK_IS_ACCEL_LABEL (accel_label), 0);
213   
214   return accel_label->accel_padding + accel_label->accel_string_width;
215 }
216
217 static void
218 gtk_accel_label_size_request (GtkWidget      *widget,
219                               GtkRequisition *requisition)
220 {
221   GtkAccelLabel *accel_label;
222   
223   g_return_if_fail (widget != NULL);
224   g_return_if_fail (GTK_IS_ACCEL_LABEL (widget));
225   g_return_if_fail (requisition != NULL);
226   
227   accel_label = GTK_ACCEL_LABEL (widget);
228   
229   if (GTK_WIDGET_CLASS (parent_class)->size_request)
230     GTK_WIDGET_CLASS (parent_class)->size_request (widget, requisition);
231   
232   accel_label->accel_string_width = gdk_string_width (GTK_WIDGET (accel_label)->style->font,
233                                                       accel_label->accel_string);
234 }
235
236 static gint
237 gtk_accel_label_expose_event (GtkWidget      *widget,
238                               GdkEventExpose *event)
239 {
240   GtkMisc *misc;
241   GtkAccelLabel *accel_label;
242   
243   g_return_val_if_fail (widget != NULL, FALSE);
244   g_return_val_if_fail (GTK_IS_ACCEL_LABEL (widget), FALSE);
245   g_return_val_if_fail (event != NULL, FALSE);
246   
247   accel_label = GTK_ACCEL_LABEL (widget);
248   misc = GTK_MISC (accel_label);
249           
250   if (GTK_WIDGET_DRAWABLE (accel_label))
251     {
252       guint ac_width;
253       
254       ac_width = gtk_accel_label_accelerator_width (accel_label);
255       
256       if (widget->allocation.width >= widget->requisition.width + ac_width)
257         {
258           guint x;
259           guint y;
260           
261           widget->allocation.width -= ac_width;
262           if (GTK_WIDGET_CLASS (parent_class)->expose_event)
263             GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
264           widget->allocation.width += ac_width;
265           
266           x = widget->allocation.x + widget->allocation.width - misc->xpad - ac_width;
267           
268           y = (widget->allocation.y * (1.0 - misc->yalign) +
269                (widget->allocation.y + widget->allocation.height -
270                 (widget->requisition.height - misc->ypad * 2)) *
271                misc->yalign + widget->style->font->ascent) + 1.5;
272           
273           if (GTK_WIDGET_STATE (accel_label) == GTK_STATE_INSENSITIVE)
274             gdk_draw_string (widget->window,
275                              widget->style->font,
276                              widget->style->white_gc,
277                              x + 1,
278                              y + 1,
279                              accel_label->accel_string);
280           
281           gdk_draw_string (widget->window,
282                            widget->style->font,
283                            widget->style->fg_gc[GTK_WIDGET_STATE (accel_label)],
284                            x,
285                            y,
286                            accel_label->accel_string);
287         }
288       else
289         {
290           if (GTK_WIDGET_CLASS (parent_class)->expose_event)
291             GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
292         }
293     }
294   
295   return TRUE;
296 }
297
298 static void
299 gtk_accel_label_queue_refetch (GtkAccelLabel *accel_label)
300 {
301   g_return_if_fail (accel_label != NULL);
302   g_return_if_fail (GTK_IS_ACCEL_LABEL (accel_label));
303
304   if (accel_label->queue_id == 0)
305     accel_label->queue_id = gtk_idle_add_priority (GTK_PRIORITY_HIGH - 2,
306                                                    (GtkFunction) gtk_accel_label_refetch,
307                                                    accel_label);
308 }
309
310 void
311 gtk_accel_label_set_accel_widget (GtkAccelLabel *accel_label,
312                                   GtkWidget     *accel_widget)
313 {
314   g_return_if_fail (accel_label != NULL);
315   g_return_if_fail (GTK_IS_ACCEL_LABEL (accel_label));
316   if (accel_widget != NULL)
317     g_return_if_fail (GTK_IS_WIDGET (accel_widget));
318   
319   if (accel_widget != accel_label->accel_widget)
320     {
321       if (accel_label->accel_widget)
322         {
323           gtk_signal_disconnect_by_func (GTK_OBJECT (accel_label->accel_widget),
324                                          GTK_SIGNAL_FUNC (gtk_accel_label_queue_refetch),
325                                          accel_label);
326           gtk_widget_unref (accel_label->accel_widget);
327         }
328       if (accel_label->queue_id)
329         {
330           gtk_idle_remove (accel_label->queue_id);
331           accel_label->queue_id = 0;
332         }
333       accel_label->accel_widget = accel_widget;
334       if (accel_label->accel_widget)
335         {
336           gtk_widget_ref (accel_label->accel_widget);
337           gtk_signal_connect_object_after (GTK_OBJECT (accel_label->accel_widget),
338                                            "add-accelerator",
339                                            GTK_SIGNAL_FUNC (gtk_accel_label_queue_refetch),
340                                            GTK_OBJECT (accel_label));
341           gtk_signal_connect_object_after (GTK_OBJECT (accel_label->accel_widget),
342                                            "remove-accelerator",
343                                            GTK_SIGNAL_FUNC (gtk_accel_label_queue_refetch),
344                                            GTK_OBJECT (accel_label));
345         }
346     }
347 }
348
349 gboolean
350 gtk_accel_label_refetch (GtkAccelLabel *accel_label)
351 {
352   GtkAccelLabelClass *class;
353
354   g_return_val_if_fail (accel_label != NULL, FALSE);
355   g_return_val_if_fail (GTK_IS_ACCEL_LABEL (accel_label), FALSE);
356
357   class = GTK_ACCEL_LABEL_CLASS (GTK_OBJECT (accel_label)->klass);
358   
359   g_free (accel_label->accel_string);
360   accel_label->accel_string = NULL;
361   
362   if (accel_label->accel_widget)
363     {
364       GtkAccelEntry *entry = NULL;
365       GSList *slist;
366       
367       slist = gtk_accel_group_entries_from_object (GTK_OBJECT (accel_label->accel_widget));
368       for (; slist; slist = slist->next)
369         {
370           entry = slist->data;
371           if (entry->accel_flags & GTK_ACCEL_VISIBLE)
372             {
373               GString *gstring;
374               gboolean had_mod;
375               
376               gstring = g_string_new (accel_label->accel_string);
377               if (gstring->len)
378                 g_string_append (gstring, class->accel_seperator);
379               else
380                 g_string_append (gstring, "   ");
381
382               if (entry->accel_flags & GTK_ACCEL_SIGNAL_VISIBLE)
383                 {
384                   g_string_append (gstring, class->signal_quote1);
385                   g_string_append (gstring, gtk_signal_name (entry->signal_id));
386                   g_string_append (gstring, class->signal_quote2);
387                 }
388               
389               had_mod = FALSE;
390               if (entry->accelerator_mods & GDK_SHIFT_MASK)
391                 {
392                   g_string_append (gstring, class->mod_name_shift);
393                   had_mod = TRUE;
394                 }
395               if (entry->accelerator_mods & GDK_CONTROL_MASK)
396                 {
397                   if (had_mod)
398                     g_string_append (gstring, class->mod_separator);
399                   g_string_append (gstring, class->mod_name_control);
400                   had_mod = TRUE;
401                 }
402               if (entry->accelerator_mods & GDK_MOD1_MASK)
403                 {
404                   if (had_mod)
405                     g_string_append (gstring, class->mod_separator);
406                   g_string_append (gstring, class->mod_name_alt);
407                   had_mod = TRUE;
408                 }
409               
410               if (had_mod)
411                 g_string_append (gstring, class->mod_separator);
412               if (entry->accelerator_key < 0x80 ||
413                   (entry->accelerator_key > 0x80 &&
414                    entry->accelerator_key <= 0xff &&
415                    class->latin1_to_char))
416                 {
417                   switch (entry->accelerator_key)
418                     {
419                     case ' ':
420                       g_string_append (gstring, "Space");
421                       break;
422                     case '\\':
423                       g_string_append (gstring, "Backslash");
424                       break;
425                     default:
426                       g_string_append_c (gstring, toupper (entry->accelerator_key));
427                       break;
428                     }
429                 }
430               else
431                 {
432                   gchar *tmp;
433                   
434                   tmp = gtk_accelerator_name (entry->accelerator_key, 0);
435                   if (tmp[0] != 0 && tmp[1] == 0)
436                     tmp[0] = toupper (tmp[0]);
437                   g_string_append (gstring, tmp);
438                   g_free (tmp);
439                 }
440
441               g_free (accel_label->accel_string);
442               accel_label->accel_string = gstring->str;
443               g_string_free (gstring, FALSE);
444             }
445         }
446     }
447
448   if (!accel_label->accel_string)
449     accel_label->accel_string = g_strdup ("");
450
451   if (accel_label->queue_id)
452     {
453       gtk_idle_remove (accel_label->queue_id);
454       accel_label->queue_id = 0;
455     }
456
457   gtk_widget_queue_resize (GTK_WIDGET (accel_label));
458
459   return FALSE;
460 }