LinuxQuestions.org
Download your favorite Linux distribution at LQ ISO.
Go Back   LinuxQuestions.org > Articles > Technical
User Name
Password

Notices


By AndrewKrause at 2007-07-20 16:10
This article is the second part of a series that will introduce you to widgets and APIs that were recently introduced into GTK+. The tutorial is taken from Chapter 8 of Foundations of GTK+ Development (published April 2007). You can find more information about the book at http://www.gtkbook.com.





Today, we will cover the GtkCellRendererAccel object, which was added in GTK+ 2.10. It allows the user to choose a keyboard accelerator in a GtkTreeView cell.

Keyboard Accelerator Renderers

GTK+ 2.10 introduced a new type of cell renderer called GtkCellRendererAccel, which displays a textual representation of a keyboard accelerator. An example of an accelerator cell renderer can be viewed in Figure 8-15.

Listing 8-16 creates a list of actions along with their keyboard accelerators. This type of tree view could be used to allow the user to edit the accelerators for an application. The accelerator is displayed as text, since the renderer is derived from GtkCellRendererText.

To edit the accelerator, the user needs to click the cell once. The cell will then show a string asking for a key. The new key code will be added, along with any mask keys such as Control and Shift into the cell. Basically, the first keyboard shortcut pressed will be displayed by the cell.

Listing 8-16. Keyboard Accelerator Cell Renderers (accelerators.c)
Code:
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>

enum
{
  ACTION = 0,
  MASK,
  VALUE,
  COLUMNS
};

typedef struct
{
  gchar *action;
  GdkModifierType mask;
  guint value;
} Accelerator;

const Accelerator list[] =
{
  {"Cut", GDK_CONTROL_MASK, GDK_X },
  { "Copy", GDK_CONTROL_MASK, GDK_C },
  { "Paste", GDK_CONTROL_MASK, GDK_V },
  { "New", GDK_CONTROL_MASK, GDK_N },
  { "Open", GDK_CONTROL_MASK, GDK_O },
  { "Print", GDK_CONTROL_MASK, GDK_P },
  { NULL, NULL, NULL }
};

static void setup_tree_view (GtkWidget*);
static void accel_edited (GtkCellRendererAccel*, gchar*, guint,
                          GdkModifierType, guint, GtkTreeView*);

int main (int argc,
          char *argv[])
{
  GtkWidget *window, *treeview, *scrolled_win;
  GtkListStore *store;
  GtkTreeIter iter;
  guint i = 0;

  gtk_init (&argc, &argv);

  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  gtk_window_set_title (GTK_WINDOW (window), "Accelerator Keys");
  gtk_container_set_border_width (GTK_CONTAINER (window), 10);
  gtk_widget_set_size_request (window, 250, 250);

  treeview = gtk_tree_view_new ();
  setup_tree_view (treeview);

  store = gtk_list_store_new (COLUMNS, G_TYPE_STRING, G_TYPE_INT, G_TYPE_UINT);
  /* Add all of the keyboard accelerators to the GtkListStore. */
  while (list[i].action != NULL)
  {
    gtk_list_store_append (store, &iter);
    gtk_list_store_set (store, &iter, ACTION, list[i].action,
                        MASK, (gint) list[i].mask, VALUE, list[i].value, -1);
    i++;
  }

  gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (store));
  g_object_unref (store);

  scrolled_win = gtk_scrolled_window_new (NULL, NULL);
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
                                  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
  gtk_container_add (GTK_CONTAINER (scrolled_win), treeview);
  gtk_container_add (GTK_CONTAINER (window), scrolled_win);
  gtk_widget_show_all (window);
  gtk_main ();
  return 0;
}

/* Create a tree view with two columns. The first is an action and the
 * second is a keyboard accelerator. */
static void
setup_tree_view (GtkWidget *treeview)
{
  GtkCellRenderer *renderer;
  GtkTreeViewColumn *column;

  renderer = gtk_cell_renderer_text_new ();
  column = gtk_tree_view_column_new_with_attributes
                          ("Buy", renderer, "text", ACTION, NULL);
  gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);

  renderer = gtk_cell_renderer_accel_new ();
  g_object_set (renderer, "accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_GTK,
                   "editable", TRUE, NULL);
  column = gtk_tree_view_column_new_with_attributes ("Buy", renderer,
                                       "accel-mods", MASK, "accel-key", VALUE, NULL);

  gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
  g_signal_connect (G_OBJECT (renderer), "accel_edited",
                    G_CALLBACK (accel_edited),
                    (gpointer) treeview);
}

/* Apply the new keyboard accelerator key and mask to the cell. */
static void
accel_edited (GtkCellRendererAccel *renderer,
              gchar *path,
              guint accel_key,
              GdkModifierType mask,
              guint hardware_keycode,
              GtkTreeView *treeview)
{
  GtkTreeModel *model;
  GtkTreeIter iter;

  model = gtk_tree_view_get_model (treeview);
  if (gtk_tree_model_get_iter_from_string (model, &iter, path))
    gtk_list_store_set (GTK_LIST_STORE (model), &iter,
                        MASK, (gint) mask, VALUE, accel_key, -1);
}
You can use gtk_cell_renderer_accel_new() to create new GtkCellRendererAccel objects. GtkCellRendererAccel provides the following four properties that can be accessed with
g_object_get():
  • accel-key: The key value that corresponds to the accelerator. A full list of key values can be found in <gdk/gdkkeysyms.h>.
  • accel-mode: A GtkCellRendererAccelMode value—GTK_CELL_RENDERER_ACCEL_MODE_GTK or GTK_CELL_RENDERER_ACCEL_MODE_OTHER. This defines how the accelerators are rendered within the cell. You should usually use GTK+’s version of rendering.
  • accel-mods: An accelerator modifier of the type GdkModifierType. This allows you to detect Shift, Ctrl, Alt, and other masking keys.
  • keycode: The hardware keycode of the accelerator, which is not usually used. This is only necessary if you do not define a key value.

The accel-mods value allows you to detect keys that usually do not cause any immediate action from an application by themselves. These values are defined by the GdkModifierType enumeration, although not all values can occur when dealing with keyboard accelerators. A list of important values follows:
  • GDK_SHIFT_MASK: The Shift key.
  • GDK_CONTROL_MASK: The Ctrl key.
  • GDK_MOD_MASK, GDK_MOD2_MASK, GDK_MOD3_MASK, GDK_MOD4_MASK, GDK_MOD5_MASK: The first modifier usually represents the Alt key, but these are interpreted based on your X server mapping of the keys. They can also correspond to the Meta, Super, or Hyper key.
  • GDK_SUPER_MASK: Introduced in 2.10, this allows you to explicitly state the Super modifier. This modifier may not be available on all systems!
  • GDK_HYPER_MASK: Introduced in 2.10, this allows you to explicitly state the Hyper modifier. This modifier may not be available on all systems!
  • GDK_META_MODIFIER: Introduced in 2.10, this allows you to explicitly state the Meta modifier. This modifier may not be available on all systems!

In most cases, you will want to set the modifier mask (acel-mods) and the accelerator key value (accel-key) as two attributes of the tree view column using GtkCellRendererAccel. In this case, the modifier mask will be of they type G_TYPE_INT, and the accelerator key value G_TYPE_UINT. Because of this, you will want to make sure to case the GdkModifierType value to a gint when setting the content of the modifier mask column.

store = gtk_list_store_new (COLUMNS, G_TYPE_STRING, G_TYPE_INT, G_TYPE_UINT);

GtkCellRendererAccel provides two signals. The first, accel-cleared, allows you to reset the accelerator when the user removes the current value. In most cases, you will not need to do this unless you have a default value that you want the accelerator to revert to.

Of greater importance, accel-edited allows you to apply changes that the user makes to the keyboard accelerator, as long as you set the editable property to TRUE. The callback function receives a path string to the row in question along with the accelerator key code, mask and hardware key code. In the callback function, you can apply the changes with gtk_list_store_set(), as you would with any other editable type of cell.


  



All times are GMT -5. The time now is 04:49 PM.

Main Menu
Advertisement
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration