source: trunk/third/gtk/gtk/gtkaccellabel.c @ 14482

Revision 14482, 13.0 KB checked in by ghudson, 25 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r14481, which included commits to RCS files with non-trunk default branches.
RevLine 
[14481]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
23/*
24 * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
25 * file for a list of people on the GTK+ Team.  See the ChangeLog
26 * files for a list of changes.  These files are distributed with
27 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
28 */
29
30#include <string.h>
31#include <ctype.h>
32#include "gtkmain.h"
33#include "gtksignal.h"
34#include "gtkaccellabel.h"
35
36
37enum {
38  ARG_0,
39  ARG_ACCEL_WIDGET
40};
41
42static void gtk_accel_label_class_init   (GtkAccelLabelClass  *klass);
43static void gtk_accel_label_init         (GtkAccelLabel       *accel_label);
44static void gtk_accel_label_set_arg      (GtkObject      *object,
45                                          GtkArg         *arg,
46                                          guint           arg_id);
47static void gtk_accel_label_get_arg      (GtkObject      *object,
48                                          GtkArg         *arg,
49                                          guint           arg_id);
50static void gtk_accel_label_destroy      (GtkObject      *object);
51static void gtk_accel_label_finalize     (GtkObject      *object);
52static void gtk_accel_label_size_request (GtkWidget      *widget,
53                                          GtkRequisition *requisition);
54static gint gtk_accel_label_expose_event (GtkWidget      *widget,
55                                          GdkEventExpose *event);
56static gboolean gtk_accel_label_refetch_idle (GtkAccelLabel *accel_label);
57
58static GtkAccelLabelClass *accel_label_class = NULL;
59static GtkLabelClass *parent_class = NULL;
60
61
62GtkType
63gtk_accel_label_get_type (void)
64{
65  static GtkType accel_label_type = 0;
66 
67  if (!accel_label_type)
68    {
69      static const GtkTypeInfo accel_label_info =
70      {
71        "GtkAccelLabel",
72        sizeof (GtkAccelLabel),
73        sizeof (GtkAccelLabelClass),
74        (GtkClassInitFunc) gtk_accel_label_class_init,
75        (GtkObjectInitFunc) gtk_accel_label_init,
76        /* reserved_1 */ NULL,
77        /* reserved_2 */ NULL,
78        (GtkClassInitFunc) NULL,
79      };
80     
81      accel_label_type = gtk_type_unique (gtk_label_get_type (), &accel_label_info);
82    }
83 
84  return accel_label_type;
85}
86
87static void
88gtk_accel_label_class_init (GtkAccelLabelClass *class)
89{
90  GtkObjectClass *object_class;
91  GtkWidgetClass *widget_class;
92  GtkMiscClass *misc_class;
93  GtkLabelClass *label_class;
94 
95  accel_label_class = class;
96  object_class = (GtkObjectClass*) class;
97  widget_class = (GtkWidgetClass*) class;
98  misc_class = (GtkMiscClass*) class;
99  label_class = (GtkLabelClass*) class;
100 
101  parent_class = gtk_type_class (gtk_label_get_type ());
102 
103  gtk_object_add_arg_type ("GtkAccelLabel::accel_widget", GTK_TYPE_WIDGET, GTK_ARG_READWRITE, ARG_ACCEL_WIDGET);
104
105  object_class->set_arg = gtk_accel_label_set_arg;
106  object_class->get_arg = gtk_accel_label_get_arg;
107  object_class->destroy = gtk_accel_label_destroy;
108  object_class->finalize = gtk_accel_label_finalize;
109 
110  widget_class->size_request = gtk_accel_label_size_request;
111  widget_class->expose_event = gtk_accel_label_expose_event;
112
113  class->signal_quote1 = g_strdup ("<:");
114  class->signal_quote2 = g_strdup (":>");
115  class->mod_name_shift = g_strdup ("Shft");
116  class->mod_name_control = g_strdup ("Ctl");
117  class->mod_name_alt = g_strdup ("Alt");
118  class->mod_separator = g_strdup ("+");
119  class->accel_seperator = g_strdup (" / ");
120  class->latin1_to_char = TRUE;
121}
122
123static void
124gtk_accel_label_set_arg (GtkObject      *object,
125                         GtkArg         *arg,
126                         guint           arg_id)
127{
128  GtkAccelLabel  *accel_label;
129
130  accel_label = GTK_ACCEL_LABEL (object);
131
132  switch (arg_id)
133    {
134    case ARG_ACCEL_WIDGET:
135      gtk_accel_label_set_accel_widget (accel_label, (GtkWidget*) GTK_VALUE_OBJECT (*arg));
136      break;
137    default:
138      break;
139    }
140}
141
142static void
143gtk_accel_label_get_arg (GtkObject      *object,
144                         GtkArg         *arg,
145                         guint           arg_id)
146{
147  GtkAccelLabel  *accel_label;
148
149  accel_label = GTK_ACCEL_LABEL (object);
150
151  switch (arg_id)
152    {
153    case ARG_ACCEL_WIDGET:
154      GTK_VALUE_OBJECT (*arg) = (GtkObject*) accel_label->accel_widget;
155      break;
156    default:
157      arg->type = GTK_TYPE_INVALID;
158      break;
159    }
160}
161
162static void
163gtk_accel_label_init (GtkAccelLabel *accel_label)
164{
165  accel_label->queue_id = 0;
166  accel_label->accel_padding = 3;
167  accel_label->accel_widget = NULL;
168  accel_label->accel_string = NULL;
169 
170  gtk_accel_label_refetch (accel_label);
171}
172
173GtkWidget*
174gtk_accel_label_new (const gchar *string)
175{
176  GtkAccelLabel *accel_label;
177 
178  g_return_val_if_fail (string != NULL, NULL);
179 
180  accel_label = gtk_type_new (GTK_TYPE_ACCEL_LABEL);
181 
182  gtk_label_set_text (GTK_LABEL (accel_label), string);
183 
184  return GTK_WIDGET (accel_label);
185}
186
187static void
188gtk_accel_label_destroy (GtkObject *object)
189{
190  GtkAccelLabel *accel_label;
191 
192  g_return_if_fail (object != NULL);
193  g_return_if_fail (GTK_IS_ACCEL_LABEL (object));
194 
195  accel_label = GTK_ACCEL_LABEL (object);
196
197  gtk_accel_label_set_accel_widget (accel_label, NULL);
198 
199  GTK_OBJECT_CLASS (parent_class)->destroy (object);
200}
201
202static void
203gtk_accel_label_finalize (GtkObject *object)
204{
205  GtkAccelLabel *accel_label;
206 
207  g_return_if_fail (object != NULL);
208  g_return_if_fail (GTK_IS_ACCEL_LABEL (object));
209 
210  accel_label = GTK_ACCEL_LABEL (object);
211 
212  g_free (accel_label->accel_string);
213 
214  GTK_OBJECT_CLASS (parent_class)->finalize (object);
215}
216
217guint
218gtk_accel_label_get_accel_width (GtkAccelLabel *accel_label)
219{
220  g_return_val_if_fail (accel_label != NULL, 0);
221  g_return_val_if_fail (GTK_IS_ACCEL_LABEL (accel_label), 0);
222 
223  return (accel_label->accel_string_width +
224          (accel_label->accel_string_width ? accel_label->accel_padding : 0));
225}
226
227static void
228gtk_accel_label_size_request (GtkWidget      *widget,
229                              GtkRequisition *requisition)
230{
231  GtkAccelLabel *accel_label;
232 
233  g_return_if_fail (widget != NULL);
234  g_return_if_fail (GTK_IS_ACCEL_LABEL (widget));
235  g_return_if_fail (requisition != NULL);
236 
237  accel_label = GTK_ACCEL_LABEL (widget);
238 
239  if (GTK_WIDGET_CLASS (parent_class)->size_request)
240    GTK_WIDGET_CLASS (parent_class)->size_request (widget, requisition);
241 
242  accel_label->accel_string_width = gdk_string_width (GTK_WIDGET (accel_label)->style->font,
243                                                      accel_label->accel_string);
244}
245
246static gint
247gtk_accel_label_expose_event (GtkWidget      *widget,
248                              GdkEventExpose *event)
249{
250  GtkMisc *misc;
251  GtkAccelLabel *accel_label;
252 
253  g_return_val_if_fail (widget != NULL, FALSE);
254  g_return_val_if_fail (GTK_IS_ACCEL_LABEL (widget), FALSE);
255  g_return_val_if_fail (event != NULL, FALSE);
256 
257  accel_label = GTK_ACCEL_LABEL (widget);
258  misc = GTK_MISC (accel_label);
259         
260  if (GTK_WIDGET_DRAWABLE (accel_label))
261    {
262      guint ac_width;
263     
264      ac_width = gtk_accel_label_get_accel_width (accel_label);
265     
266      if (widget->allocation.width >= widget->requisition.width + ac_width)
267        {
268          guint x;
269          guint y;
270         
271          widget->allocation.width -= ac_width;
272          if (GTK_WIDGET_CLASS (parent_class)->expose_event)
273            GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
274          widget->allocation.width += ac_width;
275         
276          x = widget->allocation.x + widget->allocation.width - misc->xpad - ac_width;
277         
278          y = (widget->allocation.y * (1.0 - misc->yalign) +
279               (widget->allocation.y + widget->allocation.height -
280                (widget->requisition.height - misc->ypad * 2)) *
281               misc->yalign + widget->style->font->ascent) + 1.5;
282         
283          if (GTK_WIDGET_STATE (accel_label) == GTK_STATE_INSENSITIVE)
284            gdk_draw_string (widget->window,
285                             widget->style->font,
286                             widget->style->white_gc,
287                             x + 1,
288                             y + 1,
289                             accel_label->accel_string);
290         
291          gdk_draw_string (widget->window,
292                           widget->style->font,
293                           widget->style->fg_gc[GTK_WIDGET_STATE (accel_label)],
294                           x,
295                           y,
296                           accel_label->accel_string);
297        }
298      else
299        {
300          if (GTK_WIDGET_CLASS (parent_class)->expose_event)
301            GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
302        }
303    }
304 
305  return TRUE;
306}
307
308static void
309gtk_accel_label_queue_refetch (GtkAccelLabel *accel_label)
310{
311  g_return_if_fail (accel_label != NULL);
312  g_return_if_fail (GTK_IS_ACCEL_LABEL (accel_label));
313
314  if (accel_label->queue_id == 0)
315    accel_label->queue_id = gtk_idle_add_priority (G_PRIORITY_HIGH_IDLE,
316                                                   (GtkFunction) gtk_accel_label_refetch_idle,
317                                                   accel_label);
318}
319
320void
321gtk_accel_label_set_accel_widget (GtkAccelLabel *accel_label,
322                                  GtkWidget     *accel_widget)
323{
324  g_return_if_fail (accel_label != NULL);
325  g_return_if_fail (GTK_IS_ACCEL_LABEL (accel_label));
326  if (accel_widget != NULL)
327    g_return_if_fail (GTK_IS_WIDGET (accel_widget));
328 
329  if (accel_widget != accel_label->accel_widget)
330    {
331      if (accel_label->accel_widget)
332        {
333          gtk_signal_disconnect_by_func (GTK_OBJECT (accel_label->accel_widget),
334                                         GTK_SIGNAL_FUNC (gtk_accel_label_queue_refetch),
335                                         accel_label);
336          gtk_widget_unref (accel_label->accel_widget);
337        }
338      if (accel_label->queue_id)
339        {
340          gtk_idle_remove (accel_label->queue_id);
341          accel_label->queue_id = 0;
342        }
343      accel_label->accel_widget = accel_widget;
344      if (accel_label->accel_widget)
345        {
346          gtk_widget_ref (accel_label->accel_widget);
347          gtk_signal_connect_object_after (GTK_OBJECT (accel_label->accel_widget),
348                                           "add-accelerator",
349                                           GTK_SIGNAL_FUNC (gtk_accel_label_queue_refetch),
350                                           GTK_OBJECT (accel_label));
351          gtk_signal_connect_object_after (GTK_OBJECT (accel_label->accel_widget),
352                                           "remove-accelerator",
353                                           GTK_SIGNAL_FUNC (gtk_accel_label_queue_refetch),
354                                           GTK_OBJECT (accel_label));
355        }
356    }
357}
358
359static gboolean
360gtk_accel_label_refetch_idle (GtkAccelLabel *accel_label)
361{
362  gboolean retval;
363
364  GDK_THREADS_ENTER ();
365  retval = gtk_accel_label_refetch (accel_label);
366  GDK_THREADS_LEAVE ();
367
368  return retval;
369}
370
371gboolean
372gtk_accel_label_refetch (GtkAccelLabel *accel_label)
373{
374  GtkAccelLabelClass *class;
375
376  g_return_val_if_fail (accel_label != NULL, FALSE);
377  g_return_val_if_fail (GTK_IS_ACCEL_LABEL (accel_label), FALSE);
378
379  class = GTK_ACCEL_LABEL_CLASS (GTK_OBJECT (accel_label)->klass);
380 
381  g_free (accel_label->accel_string);
382  accel_label->accel_string = NULL;
383 
384  if (accel_label->accel_widget)
385    {
386      GtkAccelEntry *entry = NULL;
387      GSList *slist;
388     
389      slist = gtk_accel_group_entries_from_object (GTK_OBJECT (accel_label->accel_widget));
390      for (; slist; slist = slist->next)
391        {
392          entry = slist->data;
393          if (entry->accel_flags & GTK_ACCEL_VISIBLE)
394            {
395              GString *gstring;
396              gboolean had_mod;
397             
398              gstring = g_string_new (accel_label->accel_string);
399              if (gstring->len)
400                g_string_append (gstring, class->accel_seperator);
401              else
402                g_string_append (gstring, "   ");
403
404              if (entry->accel_flags & GTK_ACCEL_SIGNAL_VISIBLE)
405                {
406                  g_string_append (gstring, class->signal_quote1);
407                  g_string_append (gstring, gtk_signal_name (entry->signal_id));
408                  g_string_append (gstring, class->signal_quote2);
409                }
410             
411              had_mod = FALSE;
412              if (entry->accelerator_mods & GDK_SHIFT_MASK)
413                {
414                  g_string_append (gstring, class->mod_name_shift);
415                  had_mod = TRUE;
416                }
417              if (entry->accelerator_mods & GDK_CONTROL_MASK)
418                {
419                  if (had_mod)
420                    g_string_append (gstring, class->mod_separator);
421                  g_string_append (gstring, class->mod_name_control);
422                  had_mod = TRUE;
423                }
424              if (entry->accelerator_mods & GDK_MOD1_MASK)
425                {
426                  if (had_mod)
427                    g_string_append (gstring, class->mod_separator);
428                  g_string_append (gstring, class->mod_name_alt);
429                  had_mod = TRUE;
430                }
431             
432              if (had_mod)
433                g_string_append (gstring, class->mod_separator);
434              if (entry->accelerator_key < 0x80 ||
435                  (entry->accelerator_key > 0x80 &&
436                   entry->accelerator_key <= 0xff &&
437                   class->latin1_to_char))
438                {
439                  switch (entry->accelerator_key)
440                    {
441                    case ' ':
442                      g_string_append (gstring, "Space");
443                      break;
444                    case '\\':
445                      g_string_append (gstring, "Backslash");
446                      break;
447                    default:
448                      g_string_append_c (gstring, toupper (entry->accelerator_key));
449                      break;
450                    }
451                }
452              else
453                {
454                  gchar *tmp;
455                 
456                  tmp = gtk_accelerator_name (entry->accelerator_key, 0);
457                  if (tmp[0] != 0 && tmp[1] == 0)
458                    tmp[0] = toupper (tmp[0]);
459                  g_string_append (gstring, tmp);
460                  g_free (tmp);
461                }
462
463              g_free (accel_label->accel_string);
464              accel_label->accel_string = gstring->str;
465              g_string_free (gstring, FALSE);
466            }
467        }
468    }
469
470  if (!accel_label->accel_string)
471    accel_label->accel_string = g_strdup ("");
472
473  if (accel_label->queue_id)
474    {
475      gtk_idle_remove (accel_label->queue_id);
476      accel_label->queue_id = 0;
477    }
478
479  gtk_widget_queue_resize (GTK_WIDGET (accel_label));
480
481  return FALSE;
482}
Note: See TracBrowser for help on using the repository browser.