00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #include <config.h>
00035 #include "metaaccellabel.h"
00036 #include <gtk/gtkmain.h>
00037 #include <gtk/gtkaccelmap.h>
00038 #include <string.h>
00039 #include "util.h"
00040
00041 static void meta_accel_label_class_init (MetaAccelLabelClass *klass);
00042 static void meta_accel_label_init (MetaAccelLabel *accel_label);
00043 static void meta_accel_label_destroy (GtkObject *object);
00044 static void meta_accel_label_finalize (GObject *object);
00045 static void meta_accel_label_size_request (GtkWidget *widget,
00046 GtkRequisition *requisition);
00047 static gboolean meta_accel_label_expose_event (GtkWidget *widget,
00048 GdkEventExpose *event);
00049
00050 static void meta_accel_label_update (MetaAccelLabel *accel_label);
00051 static int meta_accel_label_get_accel_width (MetaAccelLabel *accel_label);
00052
00053
00054 static GtkLabelClass *parent_class = NULL;
00055
00056
00057 GtkType
00058 meta_accel_label_get_type (void)
00059 {
00060 static GtkType accel_label_type = 0;
00061
00062 if (!accel_label_type)
00063 {
00064 static const GtkTypeInfo accel_label_info =
00065 {
00066 "MetaAccelLabel",
00067 sizeof (MetaAccelLabel),
00068 sizeof (MetaAccelLabelClass),
00069 (GtkClassInitFunc) meta_accel_label_class_init,
00070 (GtkObjectInitFunc) meta_accel_label_init,
00071 NULL,
00072 NULL,
00073 (GtkClassInitFunc) NULL,
00074 };
00075
00076 accel_label_type = gtk_type_unique (GTK_TYPE_LABEL, &accel_label_info);
00077 }
00078
00079 return accel_label_type;
00080 }
00081
00082 static void
00083 meta_accel_label_class_init (MetaAccelLabelClass *class)
00084 {
00085 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
00086 GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
00087 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
00088
00089 parent_class = g_type_class_peek_parent (class);
00090
00091 gobject_class->finalize = meta_accel_label_finalize;
00092
00093 object_class->destroy = meta_accel_label_destroy;
00094
00095 widget_class->size_request = meta_accel_label_size_request;
00096 widget_class->expose_event = meta_accel_label_expose_event;
00097
00098 class->signal_quote1 = g_strdup ("<:");
00099 class->signal_quote2 = g_strdup (":>");
00100
00101
00102
00103
00104
00105 class->mod_name_shift = g_strdup (_("Shift"));
00106
00107
00108
00109
00110
00111 class->mod_name_control = g_strdup (_("Ctrl"));
00112
00113
00114
00115
00116
00117 class->mod_name_alt = g_strdup (_("Alt"));
00118
00119
00120
00121
00122
00123 class->mod_name_meta = g_strdup (_("Meta"));
00124
00125
00126
00127
00128
00129 class->mod_name_super = g_strdup (_("Super"));
00130
00131
00132
00133
00134
00135 class->mod_name_hyper = g_strdup (_("Hyper"));
00136
00137
00138
00139
00140
00141 class->mod_name_mod2 = g_strdup (_("Mod2"));
00142
00143
00144
00145
00146
00147 class->mod_name_mod3 = g_strdup (_("Mod3"));
00148
00149
00150
00151
00152
00153 class->mod_name_mod4 = g_strdup (_("Mod4"));
00154
00155
00156
00157
00158
00159 class->mod_name_mod5 = g_strdup (_("Mod5"));
00160
00161 class->mod_separator = g_strdup ("+");
00162 class->accel_seperator = g_strdup (" / ");
00163 class->latin1_to_char = TRUE;
00164 }
00165
00166 static void
00167 meta_accel_label_init (MetaAccelLabel *accel_label)
00168 {
00169 accel_label->accel_padding = 3;
00170 accel_label->accel_string = NULL;
00171
00172 meta_accel_label_update (accel_label);
00173 }
00174
00175 GtkWidget*
00176 meta_accel_label_new_with_mnemonic (const gchar *string)
00177 {
00178 MetaAccelLabel *accel_label;
00179
00180 g_return_val_if_fail (string != NULL, NULL);
00181
00182 accel_label = g_object_new (META_TYPE_ACCEL_LABEL, NULL);
00183
00184 gtk_label_set_text_with_mnemonic (GTK_LABEL (accel_label), string);
00185
00186 return GTK_WIDGET (accel_label);
00187 }
00188
00189 static void
00190 meta_accel_label_destroy (GtkObject *object)
00191 {
00192 MetaAccelLabel *accel_label = META_ACCEL_LABEL (object);
00193
00194
00195 g_free (accel_label->accel_string);
00196 accel_label->accel_string = NULL;
00197
00198 accel_label->accel_mods = 0;
00199 accel_label->accel_key = 0;
00200
00201 GTK_OBJECT_CLASS (parent_class)->destroy (object);
00202 }
00203
00204 static void
00205 meta_accel_label_finalize (GObject *object)
00206 {
00207 MetaAccelLabel *accel_label = META_ACCEL_LABEL (object);
00208
00209 g_free (accel_label->accel_string);
00210
00211 G_OBJECT_CLASS (parent_class)->finalize (object);
00212 }
00213
00214 void
00215 meta_accel_label_set_accelerator (MetaAccelLabel *accel_label,
00216 guint accelerator_key,
00217 MetaVirtualModifier accelerator_mods)
00218 {
00219 g_return_if_fail (META_IS_ACCEL_LABEL (accel_label));
00220
00221 if (accelerator_key != accel_label->accel_key ||
00222 accelerator_mods != accel_label->accel_mods)
00223 {
00224 accel_label->accel_mods = accelerator_mods;
00225 accel_label->accel_key = accelerator_key;
00226
00227 meta_accel_label_update (accel_label);
00228 }
00229 }
00230
00231 static int
00232 meta_accel_label_get_accel_width (MetaAccelLabel *accel_label)
00233 {
00234 g_return_val_if_fail (META_IS_ACCEL_LABEL (accel_label), 0);
00235
00236 return (accel_label->accel_string_width +
00237 (accel_label->accel_string_width ? accel_label->accel_padding : 0));
00238 }
00239
00240 static void
00241 meta_accel_label_size_request (GtkWidget *widget,
00242 GtkRequisition *requisition)
00243 {
00244 MetaAccelLabel *accel_label = META_ACCEL_LABEL (widget);
00245 PangoLayout *layout;
00246 gint width;
00247
00248 if (GTK_WIDGET_CLASS (parent_class)->size_request)
00249 GTK_WIDGET_CLASS (parent_class)->size_request (widget, requisition);
00250
00251 layout = gtk_widget_create_pango_layout (widget, accel_label->accel_string);
00252 pango_layout_get_pixel_size (layout, &width, NULL);
00253 accel_label->accel_string_width = width;
00254
00255 g_object_unref (G_OBJECT (layout));
00256 }
00257
00258 static gboolean
00259 meta_accel_label_expose_event (GtkWidget *widget,
00260 GdkEventExpose *event)
00261 {
00262 MetaAccelLabel *accel_label = META_ACCEL_LABEL (widget);
00263 GtkMisc *misc = GTK_MISC (accel_label);
00264 PangoLayout *layout;
00265
00266 if (GTK_WIDGET_DRAWABLE (accel_label))
00267 {
00268 int ac_width;
00269
00270 ac_width = meta_accel_label_get_accel_width (accel_label);
00271
00272 if (widget->allocation.width >= widget->requisition.width + ac_width)
00273 {
00274 GtkTextDirection direction = gtk_widget_get_direction (widget);
00275 gint x;
00276 gint y;
00277
00278 if (direction == GTK_TEXT_DIR_RTL)
00279 {
00280 widget->allocation.x += ac_width;
00281 }
00282 widget->allocation.width -= ac_width;
00283
00284 if (GTK_WIDGET_CLASS (parent_class)->expose_event)
00285 GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
00286
00287 if (direction == GTK_TEXT_DIR_RTL)
00288 {
00289 widget->allocation.x -= ac_width;
00290 }
00291 widget->allocation.width += ac_width;
00292
00293 if (direction == GTK_TEXT_DIR_RTL)
00294 {
00295 x = widget->allocation.x + misc->xpad;
00296 }
00297 else
00298 {
00299 x = widget->allocation.x + widget->allocation.width - misc->xpad - ac_width;
00300 }
00301
00302 y = (widget->allocation.y * (1.0 - misc->yalign) +
00303 (widget->allocation.y + widget->allocation.height -
00304 (widget->requisition.height - misc->ypad * 2)) *
00305 misc->yalign) + 1.5;
00306
00307 layout = gtk_widget_create_pango_layout (widget, accel_label->accel_string);
00308
00309 gtk_paint_layout (widget->style,
00310 widget->window,
00311 GTK_WIDGET_STATE (widget),
00312 FALSE,
00313 &event->area,
00314 widget,
00315 "accellabel",
00316 x, y,
00317 layout);
00318
00319 g_object_unref (G_OBJECT (layout));
00320 }
00321 else
00322 {
00323 if (GTK_WIDGET_CLASS (parent_class)->expose_event)
00324 GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
00325 }
00326 }
00327
00328 return FALSE;
00329 }
00330
00331 static void
00332 meta_accel_label_update (MetaAccelLabel *accel_label)
00333 {
00334 MetaAccelLabelClass *class;
00335 GString *gstring;
00336 gboolean seen_mod = FALSE;
00337 gunichar ch;
00338
00339 g_return_if_fail (META_IS_ACCEL_LABEL (accel_label));
00340
00341 class = META_ACCEL_LABEL_GET_CLASS (accel_label);
00342
00343 g_free (accel_label->accel_string);
00344 accel_label->accel_string = NULL;
00345
00346 gstring = g_string_new (accel_label->accel_string);
00347 g_string_append (gstring, gstring->len ? class->accel_seperator : " ");
00348
00349 if (accel_label->accel_mods & META_VIRTUAL_SHIFT_MASK)
00350 {
00351 g_string_append (gstring, class->mod_name_shift);
00352 seen_mod = TRUE;
00353 }
00354 if (accel_label->accel_mods & META_VIRTUAL_CONTROL_MASK)
00355 {
00356 if (seen_mod)
00357 g_string_append (gstring, class->mod_separator);
00358 g_string_append (gstring, class->mod_name_control);
00359 seen_mod = TRUE;
00360 }
00361 if (accel_label->accel_mods & META_VIRTUAL_ALT_MASK)
00362 {
00363 if (seen_mod)
00364 g_string_append (gstring, class->mod_separator);
00365 g_string_append (gstring, class->mod_name_alt);
00366 seen_mod = TRUE;
00367 }
00368 if (accel_label->accel_mods & META_VIRTUAL_META_MASK)
00369 {
00370 if (seen_mod)
00371 g_string_append (gstring, class->mod_separator);
00372 g_string_append (gstring, class->mod_name_meta);
00373 seen_mod = TRUE;
00374 }
00375 if (accel_label->accel_mods & META_VIRTUAL_SUPER_MASK)
00376 {
00377 if (seen_mod)
00378 g_string_append (gstring, class->mod_separator);
00379 g_string_append (gstring, class->mod_name_super);
00380 seen_mod = TRUE;
00381 }
00382 if (accel_label->accel_mods & META_VIRTUAL_HYPER_MASK)
00383 {
00384 if (seen_mod)
00385 g_string_append (gstring, class->mod_separator);
00386 g_string_append (gstring, class->mod_name_hyper);
00387 seen_mod = TRUE;
00388 }
00389 if (accel_label->accel_mods & META_VIRTUAL_MOD2_MASK)
00390 {
00391 if (seen_mod)
00392 g_string_append (gstring, class->mod_separator);
00393 g_string_append (gstring, class->mod_name_mod2);
00394 seen_mod = TRUE;
00395 }
00396 if (accel_label->accel_mods & META_VIRTUAL_MOD3_MASK)
00397 {
00398 if (seen_mod)
00399 g_string_append (gstring, class->mod_separator);
00400 g_string_append (gstring, class->mod_name_mod3);
00401 seen_mod = TRUE;
00402 }
00403 if (accel_label->accel_mods & META_VIRTUAL_MOD4_MASK)
00404 {
00405 if (seen_mod)
00406 g_string_append (gstring, class->mod_separator);
00407 g_string_append (gstring, class->mod_name_mod4);
00408 seen_mod = TRUE;
00409 }
00410 if (accel_label->accel_mods & META_VIRTUAL_MOD5_MASK)
00411 {
00412 if (seen_mod)
00413 g_string_append (gstring, class->mod_separator);
00414 g_string_append (gstring, class->mod_name_mod5);
00415 seen_mod = TRUE;
00416 }
00417
00418 if (seen_mod)
00419 g_string_append (gstring, class->mod_separator);
00420
00421 ch = gdk_keyval_to_unicode (accel_label->accel_key);
00422 if (ch && (g_unichar_isgraph (ch) || ch == ' ') &&
00423 (ch < 0x80 || class->latin1_to_char))
00424 {
00425 switch (ch)
00426 {
00427 case ' ':
00428 g_string_append (gstring, "Space");
00429 break;
00430 case '\\':
00431 g_string_append (gstring, "Backslash");
00432 break;
00433 default:
00434 g_string_append_unichar (gstring, g_unichar_toupper (ch));
00435 break;
00436 }
00437 }
00438 else
00439 {
00440 gchar *tmp;
00441
00442 tmp = gtk_accelerator_name (accel_label->accel_key, 0);
00443 if (tmp[0] != 0 && tmp[1] == 0)
00444 tmp[0] = g_ascii_toupper (tmp[0]);
00445 g_string_append (gstring, tmp);
00446 g_free (tmp);
00447 }
00448
00449 g_free (accel_label->accel_string);
00450 accel_label->accel_string = gstring->str;
00451 g_string_free (gstring, FALSE);
00452
00453 g_assert (accel_label->accel_string);
00454
00455
00456 gtk_widget_queue_resize (GTK_WIDGET (accel_label));
00457 }