[gnome-control-center/wip/gbsneto/new-keyboard-panel: 7/15] keyboard: add CcShortcutLabel
- From: Georges Basile Stavracas Neto <gbsneto src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-control-center/wip/gbsneto/new-keyboard-panel: 7/15] keyboard: add CcShortcutLabel
- Date: Thu, 21 Jul 2016 21:40:55 +0000 (UTC)
commit afb42b57896818a6eba48efaf4e6b15ccebcbc6f
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date: Wed Jul 13 23:30:49 2016 -0300
keyboard: add CcShortcutLabel
In order to properly implement the mockups,
the shortcut accelerators must match the
visuals of Gtk+.
To make that happen, copy GtkShortcutLabel to
the tree and adapt whatever is needed to make
it work here.
panels/keyboard/Makefile.am | 2 +
panels/keyboard/cc-shortcut-label.c | 526 +++++++++++++++++++++++++++++++++++
panels/keyboard/cc-shortcut-label.h | 45 +++
3 files changed, 573 insertions(+), 0 deletions(-)
---
diff --git a/panels/keyboard/Makefile.am b/panels/keyboard/Makefile.am
index 636fed5..3f9a86b 100644
--- a/panels/keyboard/Makefile.am
+++ b/panels/keyboard/Makefile.am
@@ -15,6 +15,8 @@ libkeyboard_la_SOURCES = \
cc-keyboard-item.h \
cc-keyboard-option.c \
cc-keyboard-option.h \
+ cc-shortcut-label.c \
+ cc-shortcut-label.h \
wm-common.c \
wm-common.h \
keyboard-shortcuts.c \
diff --git a/panels/keyboard/cc-shortcut-label.c b/panels/keyboard/cc-shortcut-label.c
new file mode 100644
index 0000000..3f75c8b
--- /dev/null
+++ b/panels/keyboard/cc-shortcut-label.c
@@ -0,0 +1,526 @@
+/* cc-shortcut-label.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"
+#include "cc-shortcut-label.h"
+
+#include <glib/gi18n-lib.h>
+
+struct _CcShortcutLabel
+{
+ GtkBox parent_instance;
+ gchar *accelerator;
+ gchar *placeholder;
+};
+
+G_DEFINE_TYPE (CcShortcutLabel, cc_shortcut_label, GTK_TYPE_BOX)
+
+enum {
+ PROP_0,
+ PROP_ACCELERATOR,
+ PROP_PLACEHOLDER_LABEL,
+ LAST_PROP
+};
+
+static GParamSpec *properties[LAST_PROP];
+
+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:
+ /* 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");
+ 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:
+ /* 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");
+ 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 ();
+ }
+
+ return g_strdup_printf ("%s <small><b>%s</b></small>", label, subscript);
+}
+
+static gchar **
+get_labels (guint key, GdkModifierType modifier, guint *n_mods)
+{
+ const gchar *labels[16];
+ GList *freeme = NULL;
+ gchar key_label[6];
+ gchar *tmp;
+ gunichar ch;
+ gint i = 0;
+ gchar **retval;
+
+ 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)
+ {
+ case '<':
+ labels[i++] = "<";
+ break;
+ case '>':
+ labels[i++] = ">";
+ break;
+ case '&':
+ labels[i++] = "&";
+ break;
+ case '"':
+ labels[i++] = """;
+ break;
+ case '\'':
+ labels[i++] = "'";
+ break;
+ 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)
+ {
+ 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;
+ 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;
+
+ retval = g_strdupv ((gchar **)labels);
+
+ g_list_free_full (freeme, g_free);
+
+ return retval;
+}
+
+static GtkWidget *
+dim_label (const gchar *text)
+{
+ GtkWidget *label;
+
+ label = gtk_label_new (text);
+ gtk_widget_show (label);
+ gtk_style_context_add_class (gtk_widget_get_style_context (label), "dim-label");
+
+ return label;
+}
+
+static void
+display_shortcut (GtkContainer *self,
+ 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)
+ gtk_container_add (self, dim_label ("+"));
+
+ disp = gtk_label_new (keys[i]);
+ if (i < n_mods)
+ gtk_widget_set_size_request (disp, 50, -1);
+
+ gtk_style_context_add_class (gtk_widget_get_style_context (disp), "keycap");
+ gtk_label_set_use_markup (GTK_LABEL (disp), TRUE);
+
+ gtk_widget_show (disp);
+ gtk_container_add (self, disp);
+ }
+ g_strfreev (keys);
+}
+
+static gboolean
+parse_combination (CcShortcutLabel *self,
+ const gchar *str)
+{
+ gchar **accels;
+ gint k;
+ GdkModifierType modifier = 0;
+ guint key = 0;
+ gboolean retval = TRUE;
+
+ accels = g_strsplit (str, "&", 0);
+ for (k = 0; accels[k]; k++)
+ {
+ gtk_accelerator_parse (accels[k], &key, &modifier);
+ if (key == 0 && modifier == 0)
+ {
+ retval = FALSE;
+ break;
+ }
+ if (k > 0)
+ gtk_container_add (GTK_CONTAINER (self), dim_label ("+"));
+
+ display_shortcut (GTK_CONTAINER (self), key, modifier);
+ }
+ g_strfreev (accels);
+
+ return retval;
+}
+
+static gboolean
+parse_sequence (CcShortcutLabel *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;
+}
+
+static gboolean
+parse_range (CcShortcutLabel *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;
+
+ gtk_container_add (GTK_CONTAINER (self), dim_label ("⋯"));
+
+ if (!parse_sequence (self, dots + 3))
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+cc_shortcut_label_rebuild (CcShortcutLabel *self)
+{
+ gchar **accels;
+ gint k;
+
+ gtk_container_foreach (GTK_CONTAINER (self), (GtkCallback)gtk_widget_destroy, NULL);
+
+ if (!self->accelerator || self->accelerator[0] == '\0')
+ {
+ gtk_container_add (GTK_CONTAINER (self), dim_label (self->placeholder));
+ gtk_widget_show_all (GTK_WIDGET (self));
+ return;
+ }
+
+ accels = g_strsplit (self->accelerator, " ", 0);
+ for (k = 0; accels[k]; k++)
+ {
+ if (k > 0)
+ gtk_container_add (GTK_CONTAINER (self), dim_label ("/"));
+
+ if (!parse_range (self, accels[k]))
+ {
+ g_warning ("Failed to parse %s, part of accelerator '%s'", accels[k], self->accelerator);
+ break;
+ }
+ }
+ g_strfreev (accels);
+}
+
+static void
+cc_shortcut_label_finalize (GObject *object)
+{
+ CcShortcutLabel *self = (CcShortcutLabel *)object;
+
+ g_free (self->accelerator);
+ g_free (self->placeholder);
+
+ G_OBJECT_CLASS (cc_shortcut_label_parent_class)->finalize (object);
+}
+
+static void
+cc_shortcut_label_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ CcShortcutLabel *self = CC_SHORTCUT_LABEL (object);
+
+ switch (prop_id)
+ {
+ case PROP_ACCELERATOR:
+ g_value_set_string (value, cc_shortcut_label_get_accelerator (self));
+ break;
+
+ case PROP_PLACEHOLDER_LABEL:
+ g_value_set_string (value, cc_shortcut_label_get_placeholder_label (self));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+cc_shortcut_label_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ CcShortcutLabel *self = CC_SHORTCUT_LABEL (object);
+
+ switch (prop_id)
+ {
+ case PROP_ACCELERATOR:
+ cc_shortcut_label_set_accelerator (self, g_value_get_string (value));
+ break;
+
+ case PROP_PLACEHOLDER_LABEL:
+ cc_shortcut_label_set_placeholder_label (self, g_value_get_string (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+cc_shortcut_label_class_init (CcShortcutLabelClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = cc_shortcut_label_finalize;
+ object_class->get_property = cc_shortcut_label_get_property;
+ object_class->set_property = cc_shortcut_label_set_property;
+
+ properties[PROP_ACCELERATOR] =
+ g_param_spec_string ("accelerator",
+ "Accelerator",
+ "Accelerator",
+ NULL,
+ (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ properties[PROP_PLACEHOLDER_LABEL] =
+ g_param_spec_string ("placeholder",
+ "Placeholder",
+ "Placeholder",
+ NULL,
+ (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_properties (object_class, LAST_PROP, properties);
+}
+
+static void
+cc_shortcut_label_init (CcShortcutLabel *self)
+{
+ gtk_box_set_spacing (GTK_BOX (self), 6);
+}
+
+GtkWidget*
+cc_shortcut_label_new (const gchar *accelerator)
+{
+ return g_object_new (CC_TYPE_SHORTCUT_LABEL,
+ "accelerator", accelerator,
+ NULL);
+}
+
+const gchar *
+cc_shortcut_label_get_accelerator (CcShortcutLabel *self)
+{
+ g_return_val_if_fail (CC_IS_SHORTCUT_LABEL (self), NULL);
+
+ return self->accelerator;
+}
+
+void
+cc_shortcut_label_set_accelerator (CcShortcutLabel *self,
+ const gchar *accelerator)
+{
+ g_return_if_fail (CC_IS_SHORTCUT_LABEL (self));
+
+ if (g_strcmp0 (accelerator, self->accelerator) != 0)
+ {
+ g_free (self->accelerator);
+ self->accelerator = g_strdup (accelerator);
+
+ cc_shortcut_label_rebuild (self);
+
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ACCELERATOR]);
+ }
+}
+
+const gchar *
+cc_shortcut_label_get_placeholder_label (CcShortcutLabel *self)
+{
+ g_return_val_if_fail (CC_IS_SHORTCUT_LABEL (self), NULL);
+
+ return self->placeholder;
+}
+
+void
+cc_shortcut_label_set_placeholder_label (CcShortcutLabel *self,
+ const gchar *placeholder)
+{
+ g_return_if_fail (CC_IS_SHORTCUT_LABEL (self));
+
+ if (g_strcmp0 (placeholder, self->placeholder) != 0)
+ {
+ g_free (self->placeholder);
+ self->placeholder = g_strdup (placeholder);
+
+ cc_shortcut_label_rebuild (self);
+
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ACCELERATOR]);
+ }
+}
diff --git a/panels/keyboard/cc-shortcut-label.h b/panels/keyboard/cc-shortcut-label.h
new file mode 100644
index 0000000..74c5c3c
--- /dev/null
+++ b/panels/keyboard/cc-shortcut-label.h
@@ -0,0 +1,45 @@
+/* gtkshortcutlabelprivate.h
+ *
+ * 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/>.
+ */
+
+#ifndef CC_SHORTCUT_LABEL_H
+#define CC_SHORTCUT_LABEL_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define CC_TYPE_SHORTCUT_LABEL (cc_shortcut_label_get_type())
+
+G_DECLARE_FINAL_TYPE (CcShortcutLabel, cc_shortcut_label, CC, SHORTCUT_LABEL, GtkBox)
+
+GtkWidget* cc_shortcut_label_new (const gchar *accelerator);
+
+const gchar* cc_shortcut_label_get_accelerator (CcShortcutLabel *self);
+void cc_shortcut_label_set_accelerator (CcShortcutLabel *self,
+ const gchar *accelerator);
+
+const gchar* cc_shortcut_label_get_placeholder_label (CcShortcutLabel *self);
+
+void cc_shortcut_label_set_placeholder_label (CcShortcutLabel *self,
+ const gchar *placeholder);
+
+G_END_DECLS
+
+#endif /* CC_SHORTCUT_LABEL_H */
+
+
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]