]> Pileus Git - ~andy/gtk/blob - gtk/gtkaccellabel.c
changed scrolled window inheritance, it inherits from GtkBin now.
[~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_get_accel_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_string_width +
215           (accel_label->accel_string_width ? accel_label->accel_padding : 0));
216 }
217
218 static void
219 gtk_accel_label_size_request (GtkWidget      *widget,
220                               GtkRequisition *requisition)
221 {
222   GtkAccelLabel *accel_label;
223   
224   g_return_if_fail (widget != NULL);
225   g_return_if_fail (GTK_IS_ACCEL_LABEL (widget));
226   g_return_if_fail (requisition != NULL);
227   
228   accel_label = GTK_ACCEL_LABEL (widget);
229   
230   if (GTK_WIDGET_CLASS (parent_class)->size_request)
231     GTK_WIDGET_CLASS (parent_class)->size_request (widget, requisition);
232   
233   accel_label->accel_string_width = gdk_string_width (GTK_WIDGET (accel_label)->style->font,
234                                                       accel_label->accel_string);
235 }
236
237 static gint
238 gtk_accel_label_expose_event (GtkWidget      *widget,
239                               GdkEventExpose *event)
240 {
241   GtkMisc *misc;
242   GtkAccelLabel *accel_label;
243   
244   g_return_val_if_fail (widget != NULL, FALSE);
245   g_return_val_if_fail (GTK_IS_ACCEL_LABEL (widget), FALSE);
246   g_return_val_if_fail (event != NULL, FALSE);
247   
248   accel_label = GTK_ACCEL_LABEL (widget);
249   misc = GTK_MISC (accel_label);
250           
251   if (GTK_WIDGET_DRAWABLE (accel_label))
252     {
253       guint ac_width;
254       
255       ac_width = gtk_accel_label_get_accel_width (accel_label);
256       
257       if (widget->allocation.width >= widget->requisition.width + ac_width)
258         {
259           guint x;
260           guint y;
261           
262           widget->allocation.width -= ac_width;
263           if (GTK_WIDGET_CLASS (parent_class)->expose_event)
264             GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
265           widget->allocation.width += ac_width;
266           
267           x = widget->allocation.x + widget->allocation.width - misc->xpad - ac_width;
268           
269           y = (widget->allocation.y * (1.0 - misc->yalign) +
270                (widget->allocation.y + widget->allocation.height -
271                 (widget->requisition.height - misc->ypad * 2)) *
272                misc->yalign + widget->style->font->ascent) + 1.5;
273           
274           if (GTK_WIDGET_STATE (accel_label) == GTK_STATE_INSENSITIVE)
275             gdk_draw_string (widget->window,
276                              widget->style->font,
277                              widget->style->white_gc,
278                              x + 1,
279                              y + 1,
280                              accel_label->accel_string);
281           
282           gdk_draw_string (widget->window,
283                            widget->style->font,
284                            widget->style->fg_gc[GTK_WIDGET_STATE (accel_label)],
285                            x,
286                            y,
287                            accel_label->accel_string);
288         }
289       else
290         {
291           if (GTK_WIDGET_CLASS (parent_class)->expose_event)
292             GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
293         }
294     }
295   
296   return TRUE;
297 }
298
299 static void
300 gtk_accel_label_queue_refetch (GtkAccelLabel *accel_label)
301 {
302   g_return_if_fail (accel_label != NULL);
303   g_return_if_fail (GTK_IS_ACCEL_LABEL (accel_label));
304
305   if (accel_label->queue_id == 0)
306     accel_label->queue_id = gtk_idle_add_priority (GTK_PRIORITY_HIGH - 2,
307                                                    (GtkFunction) gtk_accel_label_refetch,
308                                                    accel_label);
309 }
310
311 void
312 gtk_accel_label_set_accel_widget (GtkAccelLabel *accel_label,
313                                   GtkWidget     *accel_widget)
314 {
315   g_return_if_fail (accel_label != NULL);
316   g_return_if_fail (GTK_IS_ACCEL_LABEL (accel_label));
317   if (accel_widget != NULL)
318     g_return_if_fail (GTK_IS_WIDGET (accel_widget));
319   
320   if (accel_widget != accel_label->accel_widget)
321     {
322       if (accel_label->accel_widget)
323         {
324           gtk_signal_disconnect_by_func (GTK_OBJECT (accel_label->accel_widget),
325                                          GTK_SIGNAL_FUNC (gtk_accel_label_queue_refetch),
326                                          accel_label);
327           gtk_widget_unref (accel_label->accel_widget);
328         }
329       if (accel_label->queue_id)
330         {
331           gtk_idle_remove (accel_label->queue_id);
332           accel_label->queue_id = 0;
333         }
334       accel_label->accel_widget = accel_widget;
335       if (accel_label->accel_widget)
336         {
337           gtk_widget_ref (accel_label->accel_widget);
338           gtk_signal_connect_object_after (GTK_OBJECT (accel_label->accel_widget),
339                                            "add-accelerator",
340                                            GTK_SIGNAL_FUNC (gtk_accel_label_queue_refetch),
341                                            GTK_OBJECT (accel_label));
342           gtk_signal_connect_object_after (GTK_OBJECT (accel_label->accel_widget),
343                                            "remove-accelerator",
344                                            GTK_SIGNAL_FUNC (gtk_accel_label_queue_refetch),
345                                            GTK_OBJECT (accel_label));
346         }
347     }
348 }
349
350 gboolean
351 gtk_accel_label_refetch (GtkAccelLabel *accel_label)
352 {
353   GtkAccelLabelClass *class;
354
355   g_return_val_if_fail (accel_label != NULL, FALSE);
356   g_return_val_if_fail (GTK_IS_ACCEL_LABEL (accel_label), FALSE);
357
358   class = GTK_ACCEL_LABEL_CLASS (GTK_OBJECT (accel_label)->klass);
359   
360   g_free (accel_label->accel_string);
361   accel_label->accel_string = NULL;
362   
363   if (accel_label->accel_widget)
364     {
365       GtkAccelEntry *entry = NULL;
366       GSList *slist;
367       
368       slist = gtk_accel_group_entries_from_object (GTK_OBJECT (accel_label->accel_widget));
369       for (; slist; slist = slist->next)
370         {
371           entry = slist->data;
372           if (entry->accel_flags & GTK_ACCEL_VISIBLE)
373             {
374               GString *gstring;
375               gboolean had_mod;
376               
377               gstring = g_string_new (accel_label->accel_string);
378               if (gstring->len)
379                 g_string_append (gstring, class->accel_seperator);
380               else
381                 g_string_append (gstring, "   ");
382
383               if (entry->accel_flags & GTK_ACCEL_SIGNAL_VISIBLE)
384                 {
385                   g_string_append (gstring, class->signal_quote1);
386                   g_string_append (gstring, gtk_signal_name (entry->signal_id));
387                   g_string_append (gstring, class->signal_quote2);
388                 }
389               
390               had_mod = FALSE;
391               if (entry->accelerator_mods & GDK_SHIFT_MASK)
392                 {
393                   g_string_append (gstring, class->mod_name_shift);
394                   had_mod = TRUE;
395                 }
396               if (entry->accelerator_mods & GDK_CONTROL_MASK)
397                 {
398                   if (had_mod)
399                     g_string_append (gstring, class->mod_separator);
400                   g_string_append (gstring, class->mod_name_control);
401                   had_mod = TRUE;
402                 }
403               if (entry->accelerator_mods & GDK_MOD1_MASK)
404                 {
405                   if (had_mod)
406                     g_string_append (gstring, class->mod_separator);
407                   g_string_append (gstring, class->mod_name_alt);
408                   had_mod = TRUE;
409                 }
410               
411               if (had_mod)
412                 g_string_append (gstring, class->mod_separator);
413               if (entry->accelerator_key < 0x80 ||
414                   (entry->accelerator_key > 0x80 &&
415                    entry->accelerator_key <= 0xff &&
416                    class->latin1_to_char))
417                 {
418                   switch (entry->accelerator_key)
419                     {
420                     case ' ':
421                       g_string_append (gstring, "Space");
422                       break;
423                     case '\\':
424                       g_string_append (gstring, "Backslash");
425                       break;
426                     default:
427                       g_string_append_c (gstring, toupper (entry->accelerator_key));
428                       break;
429                     }
430                 }
431               else
432                 {
433                   gchar *tmp;
434                   
435                   tmp = gtk_accelerator_name (entry->accelerator_key, 0);
436                   if (tmp[0] != 0 && tmp[1] == 0)
437                     tmp[0] = toupper (tmp[0]);
438                   g_string_append (gstring, tmp);
439                   g_free (tmp);
440                 }
441
442               g_free (accel_label->accel_string);
443               accel_label->accel_string = gstring->str;
444               g_string_free (gstring, FALSE);
445             }
446         }
447     }
448
449   if (!accel_label->accel_string)
450     accel_label->accel_string = g_strdup ("");
451
452   if (accel_label->queue_id)
453     {
454       gtk_idle_remove (accel_label->queue_id);
455       accel_label->queue_id = 0;
456     }
457
458   gtk_widget_queue_resize (GTK_WIDGET (accel_label));
459
460   return FALSE;
461 }