2015-10-11 20:39:18 +00:00
|
|
|
|
/* gtkshortcutlabel.c
|
|
|
|
|
*
|
|
|
|
|
* Copyright (C) 2015 Christian Hergert <christian@hergert.me>
|
|
|
|
|
*
|
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
|
* modify it under the terms of the GNU Library General Public License as
|
|
|
|
|
* published by the Free Software Foundation; either version 2 of the
|
|
|
|
|
* License, or (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
* Library General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU Library General Public
|
|
|
|
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
2016-07-26 19:00:47 +00:00
|
|
|
|
#include "gtkshortcutlabel.h"
|
2019-10-18 04:20:35 +00:00
|
|
|
|
#include "gtkboxlayout.h"
|
2015-10-11 20:39:18 +00:00
|
|
|
|
#include "gtklabel.h"
|
|
|
|
|
#include "gtkframe.h"
|
|
|
|
|
#include "gtkstylecontext.h"
|
|
|
|
|
#include "gtkprivate.h"
|
|
|
|
|
#include "gtkintl.h"
|
|
|
|
|
|
2016-07-26 19:00:47 +00:00
|
|
|
|
/**
|
|
|
|
|
* SECTION:gtkshortcutlabel
|
|
|
|
|
* @Title: GtkShortcutLabel
|
|
|
|
|
* @Short_description: Displays a keyboard shortcut
|
|
|
|
|
* @See_also: #GtkCellRendererAccel
|
|
|
|
|
*
|
|
|
|
|
* #GtkShortcutLabel is a widget that represents a single keyboard shortcut or gesture
|
|
|
|
|
* in the user interface.
|
|
|
|
|
*/
|
|
|
|
|
|
2015-10-11 20:39:18 +00:00
|
|
|
|
struct _GtkShortcutLabel
|
|
|
|
|
{
|
2019-10-18 04:20:35 +00:00
|
|
|
|
GtkWidget parent_instance;
|
2015-10-11 20:39:18 +00:00
|
|
|
|
gchar *accelerator;
|
2016-07-26 20:12:31 +00:00
|
|
|
|
gchar *disabled_text;
|
2015-10-11 20:39:18 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct _GtkShortcutLabelClass
|
|
|
|
|
{
|
2019-10-18 04:20:35 +00:00
|
|
|
|
GtkWidgetClass parent_class;
|
2015-10-11 20:39:18 +00:00
|
|
|
|
};
|
|
|
|
|
|
2019-10-18 04:20:35 +00:00
|
|
|
|
G_DEFINE_TYPE (GtkShortcutLabel, gtk_shortcut_label, GTK_TYPE_WIDGET)
|
2015-10-11 20:39:18 +00:00
|
|
|
|
|
|
|
|
|
enum {
|
|
|
|
|
PROP_0,
|
|
|
|
|
PROP_ACCELERATOR,
|
2016-07-26 20:12:31 +00:00
|
|
|
|
PROP_DISABLED_TEXT,
|
2015-10-11 20:39:18 +00:00
|
|
|
|
LAST_PROP
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static GParamSpec *properties[LAST_PROP];
|
|
|
|
|
|
2015-12-04 15:55:20 +00:00
|
|
|
|
static gchar *
|
|
|
|
|
get_modifier_label (guint key)
|
|
|
|
|
{
|
|
|
|
|
const gchar *subscript;
|
|
|
|
|
const gchar *label;
|
|
|
|
|
|
|
|
|
|
switch (key)
|
|
|
|
|
{
|
|
|
|
|
case GDK_KEY_Shift_L:
|
|
|
|
|
case GDK_KEY_Control_L:
|
|
|
|
|
case GDK_KEY_Alt_L:
|
|
|
|
|
case GDK_KEY_Meta_L:
|
|
|
|
|
case GDK_KEY_Super_L:
|
|
|
|
|
case GDK_KEY_Hyper_L:
|
2015-12-04 18:16:35 +00:00
|
|
|
|
/* Translators: This string is used to mark left/right variants of modifier
|
|
|
|
|
* keys in the shortcut window (e.g. Control_L vs Control_R). Please keep
|
|
|
|
|
* this string very short, ideally just a single character, since it will
|
|
|
|
|
* be rendered as part of the key.
|
|
|
|
|
*/
|
|
|
|
|
subscript = C_("keyboard side marker", "L");
|
2015-12-04 15:55:20 +00:00
|
|
|
|
break;
|
|
|
|
|
case GDK_KEY_Shift_R:
|
|
|
|
|
case GDK_KEY_Control_R:
|
|
|
|
|
case GDK_KEY_Alt_R:
|
|
|
|
|
case GDK_KEY_Meta_R:
|
|
|
|
|
case GDK_KEY_Super_R:
|
|
|
|
|
case GDK_KEY_Hyper_R:
|
2015-12-04 18:16:35 +00:00
|
|
|
|
/* Translators: This string is used to mark left/right variants of modifier
|
|
|
|
|
* keys in the shortcut window (e.g. Control_L vs Control_R). Please keep
|
|
|
|
|
* this string very short, ideally just a single character, since it will
|
|
|
|
|
* be rendered as part of the key.
|
|
|
|
|
*/
|
|
|
|
|
subscript = C_("keyboard side marker", "R");
|
2015-12-04 15:55:20 +00:00
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
g_assert_not_reached ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (key)
|
|
|
|
|
{
|
|
|
|
|
case GDK_KEY_Shift_L: case GDK_KEY_Shift_R:
|
|
|
|
|
label = C_("keyboard label", "Shift");
|
|
|
|
|
break;
|
|
|
|
|
case GDK_KEY_Control_L: case GDK_KEY_Control_R:
|
|
|
|
|
label = C_("keyboard label", "Ctrl");
|
|
|
|
|
break;
|
|
|
|
|
case GDK_KEY_Alt_L: case GDK_KEY_Alt_R:
|
|
|
|
|
label = C_("keyboard label", "Alt");
|
|
|
|
|
break;
|
|
|
|
|
case GDK_KEY_Meta_L: case GDK_KEY_Meta_R:
|
|
|
|
|
label = C_("keyboard label", "Meta");
|
|
|
|
|
break;
|
|
|
|
|
case GDK_KEY_Super_L: case GDK_KEY_Super_R:
|
|
|
|
|
label = C_("keyboard label", "Super");
|
|
|
|
|
break;
|
|
|
|
|
case GDK_KEY_Hyper_L: case GDK_KEY_Hyper_R:
|
|
|
|
|
label = C_("keyboard label", "Hyper");
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
g_assert_not_reached ();
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-04 18:16:35 +00:00
|
|
|
|
return g_strdup_printf ("%s <small><b>%s</b></small>", label, subscript);
|
2015-12-04 15:55:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-10-11 20:39:18 +00:00
|
|
|
|
static gchar **
|
|
|
|
|
get_labels (guint key, GdkModifierType modifier, guint *n_mods)
|
|
|
|
|
{
|
|
|
|
|
const gchar *labels[16];
|
2015-12-04 15:55:20 +00:00
|
|
|
|
GList *freeme = NULL;
|
2015-10-11 20:39:18 +00:00
|
|
|
|
gchar key_label[6];
|
|
|
|
|
gchar *tmp;
|
|
|
|
|
gunichar ch;
|
|
|
|
|
gint i = 0;
|
2015-12-04 15:55:20 +00:00
|
|
|
|
gchar **retval;
|
2015-10-11 20:39:18 +00:00
|
|
|
|
|
|
|
|
|
if (modifier & GDK_SHIFT_MASK)
|
|
|
|
|
labels[i++] = C_("keyboard label", "Shift");
|
|
|
|
|
if (modifier & GDK_CONTROL_MASK)
|
|
|
|
|
labels[i++] = C_("keyboard label", "Ctrl");
|
|
|
|
|
if (modifier & GDK_MOD1_MASK)
|
|
|
|
|
labels[i++] = C_("keyboard label", "Alt");
|
|
|
|
|
if (modifier & GDK_MOD2_MASK)
|
|
|
|
|
labels[i++] = "Mod2";
|
|
|
|
|
if (modifier & GDK_MOD3_MASK)
|
|
|
|
|
labels[i++] = "Mod3";
|
|
|
|
|
if (modifier & GDK_MOD4_MASK)
|
|
|
|
|
labels[i++] = "Mod4";
|
|
|
|
|
if (modifier & GDK_MOD5_MASK)
|
|
|
|
|
labels[i++] = "Mod5";
|
|
|
|
|
if (modifier & GDK_SUPER_MASK)
|
|
|
|
|
labels[i++] = C_("keyboard label", "Super");
|
|
|
|
|
if (modifier & GDK_HYPER_MASK)
|
|
|
|
|
labels[i++] = C_("keyboard label", "Hyper");
|
|
|
|
|
if (modifier & GDK_META_MASK)
|
|
|
|
|
labels[i++] = C_("keyboard label", "Meta");
|
|
|
|
|
|
|
|
|
|
*n_mods = i;
|
|
|
|
|
|
|
|
|
|
ch = gdk_keyval_to_unicode (key);
|
|
|
|
|
if (ch && ch < 0x80 && g_unichar_isgraph (ch))
|
|
|
|
|
{
|
|
|
|
|
switch (ch)
|
|
|
|
|
{
|
2016-06-19 21:49:03 +00:00
|
|
|
|
case '<':
|
|
|
|
|
labels[i++] = "<";
|
|
|
|
|
break;
|
|
|
|
|
case '>':
|
|
|
|
|
labels[i++] = ">";
|
|
|
|
|
break;
|
|
|
|
|
case '&':
|
|
|
|
|
labels[i++] = "&";
|
|
|
|
|
break;
|
|
|
|
|
case '"':
|
|
|
|
|
labels[i++] = """;
|
|
|
|
|
break;
|
|
|
|
|
case '\'':
|
|
|
|
|
labels[i++] = "'";
|
|
|
|
|
break;
|
2015-10-11 20:39:18 +00:00
|
|
|
|
case '\\':
|
|
|
|
|
labels[i++] = C_("keyboard label", "Backslash");
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
memset (key_label, 0, 6);
|
|
|
|
|
g_unichar_to_utf8 (g_unichar_toupper (ch), key_label);
|
|
|
|
|
labels[i++] = key_label;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
switch (key)
|
|
|
|
|
{
|
2015-12-04 15:55:20 +00:00
|
|
|
|
case GDK_KEY_Shift_L: case GDK_KEY_Shift_R:
|
|
|
|
|
case GDK_KEY_Control_L: case GDK_KEY_Control_R:
|
|
|
|
|
case GDK_KEY_Alt_L: case GDK_KEY_Alt_R:
|
|
|
|
|
case GDK_KEY_Meta_L: case GDK_KEY_Meta_R:
|
|
|
|
|
case GDK_KEY_Super_L: case GDK_KEY_Super_R:
|
|
|
|
|
case GDK_KEY_Hyper_L: case GDK_KEY_Hyper_R:
|
|
|
|
|
freeme = g_list_prepend (freeme, get_modifier_label (key));
|
|
|
|
|
labels[i++] = (const gchar*)freeme->data;
|
|
|
|
|
break;
|
2015-10-11 20:39:18 +00:00
|
|
|
|
case GDK_KEY_Left:
|
|
|
|
|
labels[i++] = "\xe2\x86\x90";
|
|
|
|
|
break;
|
|
|
|
|
case GDK_KEY_Up:
|
|
|
|
|
labels[i++] = "\xe2\x86\x91";
|
|
|
|
|
break;
|
|
|
|
|
case GDK_KEY_Right:
|
|
|
|
|
labels[i++] = "\xe2\x86\x92";
|
|
|
|
|
break;
|
|
|
|
|
case GDK_KEY_Down:
|
|
|
|
|
labels[i++] = "\xe2\x86\x93";
|
|
|
|
|
break;
|
|
|
|
|
case GDK_KEY_space:
|
|
|
|
|
labels[i++] = "\xe2\x90\xa3";
|
|
|
|
|
break;
|
|
|
|
|
case GDK_KEY_Return:
|
|
|
|
|
labels[i++] = "\xe2\x8f\x8e";
|
|
|
|
|
break;
|
|
|
|
|
case GDK_KEY_Page_Up:
|
|
|
|
|
labels[i++] = C_("keyboard label", "Page_Up");
|
|
|
|
|
break;
|
|
|
|
|
case GDK_KEY_Page_Down:
|
|
|
|
|
labels[i++] = C_("keyboard label", "Page_Down");
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
tmp = gdk_keyval_name (gdk_keyval_to_lower (key));
|
|
|
|
|
if (tmp != NULL)
|
|
|
|
|
{
|
|
|
|
|
if (tmp[0] != 0 && tmp[1] == 0)
|
|
|
|
|
{
|
|
|
|
|
key_label[0] = g_ascii_toupper (tmp[0]);
|
|
|
|
|
key_label[1] = '\0';
|
|
|
|
|
labels[i++] = key_label;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
labels[i++] = g_dpgettext2 (GETTEXT_PACKAGE, "keyboard label", tmp);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
labels[i] = NULL;
|
|
|
|
|
|
2015-12-04 15:55:20 +00:00
|
|
|
|
retval = g_strdupv ((gchar **)labels);
|
|
|
|
|
|
|
|
|
|
g_list_free_full (freeme, g_free);
|
|
|
|
|
|
|
|
|
|
return retval;
|
2015-10-11 20:39:18 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static GtkWidget *
|
|
|
|
|
dim_label (const gchar *text)
|
|
|
|
|
{
|
|
|
|
|
GtkWidget *label;
|
|
|
|
|
|
|
|
|
|
label = gtk_label_new (text);
|
2020-01-29 11:11:39 +00:00
|
|
|
|
gtk_widget_add_style_class (label, "dim-label");
|
2015-10-11 20:39:18 +00:00
|
|
|
|
|
|
|
|
|
return label;
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-22 18:31:06 +00:00
|
|
|
|
static void
|
2019-10-18 04:20:35 +00:00
|
|
|
|
display_shortcut (GtkWidget *self,
|
2015-10-22 18:31:06 +00:00
|
|
|
|
guint key,
|
|
|
|
|
GdkModifierType modifier)
|
|
|
|
|
{
|
|
|
|
|
gchar **keys = NULL;
|
|
|
|
|
gint i;
|
|
|
|
|
guint n_mods;
|
|
|
|
|
|
|
|
|
|
keys = get_labels (key, modifier, &n_mods);
|
|
|
|
|
for (i = 0; keys[i]; i++)
|
|
|
|
|
{
|
|
|
|
|
GtkWidget *disp;
|
|
|
|
|
|
|
|
|
|
if (i > 0)
|
2019-10-18 04:20:35 +00:00
|
|
|
|
gtk_widget_set_parent (dim_label ("+"), self);
|
2015-10-22 18:31:06 +00:00
|
|
|
|
|
2016-01-09 16:15:29 +00:00
|
|
|
|
disp = gtk_label_new (keys[i]);
|
2015-10-22 18:31:06 +00:00
|
|
|
|
if (i < n_mods)
|
2016-01-09 16:15:29 +00:00
|
|
|
|
gtk_widget_set_size_request (disp, 50, -1);
|
2015-10-22 18:31:06 +00:00
|
|
|
|
|
2020-01-29 11:11:39 +00:00
|
|
|
|
gtk_widget_add_style_class (disp, "keycap");
|
2015-12-04 15:55:20 +00:00
|
|
|
|
gtk_label_set_use_markup (GTK_LABEL (disp), TRUE);
|
|
|
|
|
|
2019-10-18 04:20:35 +00:00
|
|
|
|
gtk_widget_set_parent (disp, self);
|
2015-10-22 18:31:06 +00:00
|
|
|
|
}
|
|
|
|
|
g_strfreev (keys);
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-15 02:34:43 +00:00
|
|
|
|
static gboolean
|
2015-12-04 15:55:20 +00:00
|
|
|
|
parse_combination (GtkShortcutLabel *self,
|
|
|
|
|
const gchar *str)
|
2015-10-11 20:39:18 +00:00
|
|
|
|
{
|
2015-11-15 02:34:43 +00:00
|
|
|
|
gchar **accels;
|
|
|
|
|
gint k;
|
2015-10-11 20:39:18 +00:00
|
|
|
|
GdkModifierType modifier = 0;
|
|
|
|
|
guint key = 0;
|
2015-11-15 02:34:43 +00:00
|
|
|
|
gboolean retval = TRUE;
|
|
|
|
|
|
2015-12-04 15:55:20 +00:00
|
|
|
|
accels = g_strsplit (str, "&", 0);
|
2015-11-15 02:34:43 +00:00
|
|
|
|
for (k = 0; accels[k]; k++)
|
|
|
|
|
{
|
|
|
|
|
gtk_accelerator_parse (accels[k], &key, &modifier);
|
|
|
|
|
if (key == 0 && modifier == 0)
|
|
|
|
|
{
|
|
|
|
|
retval = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2015-12-04 15:55:20 +00:00
|
|
|
|
if (k > 0)
|
2019-10-18 04:20:35 +00:00
|
|
|
|
gtk_widget_set_parent (dim_label ("+"), GTK_WIDGET (self));
|
2015-12-04 15:55:20 +00:00
|
|
|
|
|
2019-10-18 04:20:35 +00:00
|
|
|
|
display_shortcut (GTK_WIDGET (self), key, modifier);
|
2015-11-15 02:34:43 +00:00
|
|
|
|
}
|
|
|
|
|
g_strfreev (accels);
|
|
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-04 15:55:20 +00:00
|
|
|
|
static gboolean
|
|
|
|
|
parse_sequence (GtkShortcutLabel *self,
|
|
|
|
|
const gchar *str)
|
|
|
|
|
{
|
|
|
|
|
gchar **accels;
|
|
|
|
|
gint k;
|
|
|
|
|
gboolean retval = TRUE;
|
|
|
|
|
|
|
|
|
|
accels = g_strsplit (str, "+", 0);
|
|
|
|
|
for (k = 0; accels[k]; k++)
|
|
|
|
|
{
|
|
|
|
|
if (!parse_combination (self, accels[k]))
|
|
|
|
|
{
|
|
|
|
|
retval = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_strfreev (accels);
|
|
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-15 02:34:43 +00:00
|
|
|
|
static gboolean
|
|
|
|
|
parse_range (GtkShortcutLabel *self,
|
|
|
|
|
const gchar *str)
|
|
|
|
|
{
|
|
|
|
|
gchar *dots;
|
|
|
|
|
|
|
|
|
|
dots = strstr (str, "...");
|
|
|
|
|
if (!dots)
|
|
|
|
|
return parse_sequence (self, str);
|
|
|
|
|
|
|
|
|
|
dots[0] = '\0';
|
|
|
|
|
if (!parse_sequence (self, str))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2019-10-18 04:20:35 +00:00
|
|
|
|
gtk_widget_set_parent (dim_label ("⋯"), GTK_WIDGET (self));
|
2015-12-04 15:55:20 +00:00
|
|
|
|
|
2015-11-15 02:34:43 +00:00
|
|
|
|
if (!parse_sequence (self, dots + 3))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-18 04:20:35 +00:00
|
|
|
|
static void
|
|
|
|
|
clear_children (GtkShortcutLabel *self)
|
|
|
|
|
{
|
|
|
|
|
GtkWidget *child;
|
|
|
|
|
|
|
|
|
|
child = gtk_widget_get_first_child (GTK_WIDGET (self));
|
|
|
|
|
|
|
|
|
|
while (child)
|
|
|
|
|
{
|
|
|
|
|
GtkWidget *next = gtk_widget_get_next_sibling (child);
|
|
|
|
|
|
|
|
|
|
gtk_widget_unparent (child);
|
|
|
|
|
|
|
|
|
|
child = next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-15 02:34:43 +00:00
|
|
|
|
static void
|
|
|
|
|
gtk_shortcut_label_rebuild (GtkShortcutLabel *self)
|
|
|
|
|
{
|
|
|
|
|
gchar **accels;
|
|
|
|
|
gint k;
|
2015-10-11 20:39:18 +00:00
|
|
|
|
|
2019-10-18 04:20:35 +00:00
|
|
|
|
clear_children (self);
|
2015-10-11 20:39:18 +00:00
|
|
|
|
|
2016-07-26 20:12:31 +00:00
|
|
|
|
if (self->accelerator == NULL || self->accelerator[0] == '\0')
|
|
|
|
|
{
|
|
|
|
|
GtkWidget *label;
|
|
|
|
|
|
|
|
|
|
label = dim_label (self->disabled_text);
|
|
|
|
|
|
2019-10-18 04:20:35 +00:00
|
|
|
|
gtk_widget_set_parent (label, GTK_WIDGET (self));
|
2016-07-26 20:12:31 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
2015-10-11 20:39:18 +00:00
|
|
|
|
|
|
|
|
|
accels = g_strsplit (self->accelerator, " ", 0);
|
|
|
|
|
for (k = 0; accels[k]; k++)
|
|
|
|
|
{
|
2015-11-15 02:34:43 +00:00
|
|
|
|
if (k > 0)
|
2019-10-18 04:20:35 +00:00
|
|
|
|
gtk_widget_set_parent (dim_label ("/"), GTK_WIDGET (self));
|
2015-10-22 18:31:06 +00:00
|
|
|
|
|
2015-11-15 02:34:43 +00:00
|
|
|
|
if (!parse_range (self, accels[k]))
|
2015-10-11 20:39:18 +00:00
|
|
|
|
{
|
2015-10-22 18:31:06 +00:00
|
|
|
|
g_warning ("Failed to parse %s, part of accelerator '%s'", accels[k], self->accelerator);
|
2015-11-15 02:34:43 +00:00
|
|
|
|
break;
|
2015-10-11 20:39:18 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
g_strfreev (accels);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gtk_shortcut_label_finalize (GObject *object)
|
|
|
|
|
{
|
|
|
|
|
GtkShortcutLabel *self = (GtkShortcutLabel *)object;
|
|
|
|
|
|
|
|
|
|
g_free (self->accelerator);
|
2016-07-26 20:12:31 +00:00
|
|
|
|
g_free (self->disabled_text);
|
2015-10-11 20:39:18 +00:00
|
|
|
|
|
2019-10-18 04:20:35 +00:00
|
|
|
|
clear_children (self);
|
|
|
|
|
|
2015-10-11 20:39:18 +00:00
|
|
|
|
G_OBJECT_CLASS (gtk_shortcut_label_parent_class)->finalize (object);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gtk_shortcut_label_get_property (GObject *object,
|
|
|
|
|
guint prop_id,
|
|
|
|
|
GValue *value,
|
|
|
|
|
GParamSpec *pspec)
|
|
|
|
|
{
|
|
|
|
|
GtkShortcutLabel *self = GTK_SHORTCUT_LABEL (object);
|
|
|
|
|
|
|
|
|
|
switch (prop_id)
|
|
|
|
|
{
|
|
|
|
|
case PROP_ACCELERATOR:
|
|
|
|
|
g_value_set_string (value, gtk_shortcut_label_get_accelerator (self));
|
|
|
|
|
break;
|
|
|
|
|
|
2016-07-26 20:12:31 +00:00
|
|
|
|
case PROP_DISABLED_TEXT:
|
|
|
|
|
g_value_set_string (value, gtk_shortcut_label_get_disabled_text (self));
|
|
|
|
|
break;
|
|
|
|
|
|
2015-10-11 20:39:18 +00:00
|
|
|
|
default:
|
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gtk_shortcut_label_set_property (GObject *object,
|
|
|
|
|
guint prop_id,
|
|
|
|
|
const GValue *value,
|
|
|
|
|
GParamSpec *pspec)
|
|
|
|
|
{
|
|
|
|
|
GtkShortcutLabel *self = GTK_SHORTCUT_LABEL (object);
|
|
|
|
|
|
|
|
|
|
switch (prop_id)
|
|
|
|
|
{
|
|
|
|
|
case PROP_ACCELERATOR:
|
|
|
|
|
gtk_shortcut_label_set_accelerator (self, g_value_get_string (value));
|
|
|
|
|
break;
|
|
|
|
|
|
2016-07-26 20:12:31 +00:00
|
|
|
|
case PROP_DISABLED_TEXT:
|
|
|
|
|
gtk_shortcut_label_set_disabled_text (self, g_value_get_string (value));
|
|
|
|
|
break;
|
|
|
|
|
|
2015-10-11 20:39:18 +00:00
|
|
|
|
default:
|
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gtk_shortcut_label_class_init (GtkShortcutLabelClass *klass)
|
|
|
|
|
{
|
|
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
2019-10-18 04:20:35 +00:00
|
|
|
|
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
2015-10-11 20:39:18 +00:00
|
|
|
|
|
|
|
|
|
object_class->finalize = gtk_shortcut_label_finalize;
|
|
|
|
|
object_class->get_property = gtk_shortcut_label_get_property;
|
|
|
|
|
object_class->set_property = gtk_shortcut_label_set_property;
|
|
|
|
|
|
2016-07-26 19:00:47 +00:00
|
|
|
|
/**
|
|
|
|
|
* GtkShortcutLabel:accelerator:
|
|
|
|
|
*
|
|
|
|
|
* The accelerator that @self displays. See #GtkShortcutsShortcut:accelerator
|
|
|
|
|
* for the accepted syntax.
|
|
|
|
|
*/
|
2015-10-11 20:39:18 +00:00
|
|
|
|
properties[PROP_ACCELERATOR] =
|
|
|
|
|
g_param_spec_string ("accelerator", P_("Accelerator"), P_("Accelerator"),
|
|
|
|
|
NULL,
|
|
|
|
|
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
|
|
|
|
|
2016-07-26 20:12:31 +00:00
|
|
|
|
/**
|
|
|
|
|
* GtkShortcutLabel:disabled-text:
|
|
|
|
|
*
|
|
|
|
|
* The text that is displayed when no accelerator is set.
|
|
|
|
|
*/
|
|
|
|
|
properties[PROP_DISABLED_TEXT] =
|
|
|
|
|
g_param_spec_string ("disabled-text", P_("Disabled text"), P_("Disabled text"),
|
|
|
|
|
NULL,
|
|
|
|
|
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
|
|
|
|
|
2015-10-11 20:39:18 +00:00
|
|
|
|
g_object_class_install_properties (object_class, LAST_PROP, properties);
|
2019-10-18 04:20:35 +00:00
|
|
|
|
|
|
|
|
|
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BOX_LAYOUT);
|
|
|
|
|
gtk_widget_class_set_css_name (widget_class, I_("shortcut"));
|
2015-10-11 20:39:18 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gtk_shortcut_label_init (GtkShortcutLabel *self)
|
|
|
|
|
{
|
2016-10-10 20:52:50 +00:00
|
|
|
|
/* Always use LTR so that modifiers are always left to the keyval */
|
|
|
|
|
gtk_widget_set_direction (GTK_WIDGET (self), GTK_TEXT_DIR_LTR);
|
2015-10-11 20:39:18 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-07-26 19:00:47 +00:00
|
|
|
|
/**
|
|
|
|
|
* gtk_shortcut_label_new:
|
|
|
|
|
* @accelerator: the initial accelerator
|
|
|
|
|
*
|
|
|
|
|
* Creates a new #GtkShortcutLabel with @accelerator set.
|
|
|
|
|
*
|
|
|
|
|
* Returns: (transfer full): a newly-allocated #GtkShortcutLabel
|
|
|
|
|
*/
|
2015-10-11 20:39:18 +00:00
|
|
|
|
GtkWidget *
|
|
|
|
|
gtk_shortcut_label_new (const gchar *accelerator)
|
|
|
|
|
{
|
|
|
|
|
return g_object_new (GTK_TYPE_SHORTCUT_LABEL,
|
|
|
|
|
"accelerator", accelerator,
|
|
|
|
|
NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-26 19:00:47 +00:00
|
|
|
|
/**
|
|
|
|
|
* gtk_shortcut_label_get_accelerator:
|
|
|
|
|
* @self: a #GtkShortcutLabel
|
|
|
|
|
*
|
|
|
|
|
* Retrieves the current accelerator of @self.
|
|
|
|
|
*
|
|
|
|
|
* Returns: (transfer none)(nullable): the current accelerator.
|
|
|
|
|
*/
|
2015-10-11 20:39:18 +00:00
|
|
|
|
const gchar *
|
|
|
|
|
gtk_shortcut_label_get_accelerator (GtkShortcutLabel *self)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail (GTK_IS_SHORTCUT_LABEL (self), NULL);
|
|
|
|
|
|
|
|
|
|
return self->accelerator;
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-26 19:00:47 +00:00
|
|
|
|
/**
|
|
|
|
|
* gtk_shortcut_label_set_accelerator:
|
|
|
|
|
* @self: a #GtkShortcutLabel
|
|
|
|
|
* @accelerator: the new accelerator
|
|
|
|
|
*
|
|
|
|
|
* Sets the accelerator to be displayed by @self.
|
|
|
|
|
*/
|
2015-10-11 20:39:18 +00:00
|
|
|
|
void
|
|
|
|
|
gtk_shortcut_label_set_accelerator (GtkShortcutLabel *self,
|
|
|
|
|
const gchar *accelerator)
|
|
|
|
|
{
|
|
|
|
|
g_return_if_fail (GTK_IS_SHORTCUT_LABEL (self));
|
|
|
|
|
|
|
|
|
|
if (g_strcmp0 (accelerator, self->accelerator) != 0)
|
|
|
|
|
{
|
|
|
|
|
g_free (self->accelerator);
|
|
|
|
|
self->accelerator = g_strdup (accelerator);
|
|
|
|
|
gtk_shortcut_label_rebuild (self);
|
|
|
|
|
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ACCELERATOR]);
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-07-26 20:12:31 +00:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* gtk_shortcut_label_get_disabled_text:
|
|
|
|
|
* @self: a #GtkShortcutLabel
|
|
|
|
|
*
|
|
|
|
|
* Retrieves the text that is displayed when no accelerator is set.
|
|
|
|
|
*
|
|
|
|
|
* Returns: (transfer none)(nullable): the current text displayed when no
|
|
|
|
|
* accelerator is set.
|
|
|
|
|
*/
|
|
|
|
|
const gchar *
|
|
|
|
|
gtk_shortcut_label_get_disabled_text (GtkShortcutLabel *self)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail (GTK_IS_SHORTCUT_LABEL (self), NULL);
|
|
|
|
|
|
|
|
|
|
return self->disabled_text;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* gtk_shortcut_label_set_disabled_text:
|
|
|
|
|
* @self: a #GtkShortcutLabel
|
|
|
|
|
* @disabled_text: the text to be displayed when no accelerator is set
|
|
|
|
|
*
|
|
|
|
|
* Sets the text to be displayed by @self when no accelerator is set.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
gtk_shortcut_label_set_disabled_text (GtkShortcutLabel *self,
|
|
|
|
|
const gchar *disabled_text)
|
|
|
|
|
{
|
|
|
|
|
g_return_if_fail (GTK_IS_SHORTCUT_LABEL (self));
|
|
|
|
|
|
|
|
|
|
if (g_strcmp0 (disabled_text, self->disabled_text) != 0)
|
|
|
|
|
{
|
|
|
|
|
g_free (self->disabled_text);
|
|
|
|
|
self->disabled_text = g_strdup (disabled_text);
|
|
|
|
|
gtk_shortcut_label_rebuild (self);
|
|
|
|
|
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DISABLED_TEXT]);
|
|
|
|
|
}
|
|
|
|
|
}
|