Menu e barre di pulsanti con GnomeUIInfo

È molto noioso creare grandi menu, specialmente se questi hanno icone e controlli da tastiera per ogni voce al loro interno. Gnome fornisce una soluzione molto semplice. Basta creare una struttura GnomeUIInfo come modello per ciascuna voce, elencando le caratteristiche: nome, icone, controllo da tastiera e così via. Le librerie di Gnome posso creare automaticamente menu da array di modelli GnomeUIInfo. Lo stesso metodo viene applicato per le barre di pulsanti.

Ecco la dichiarazione della struttura GnomeUIInfo.

typedef struct {
  GnomeUIInfoType type;
  gchar* label;
  gchar* hint;  
  gpointer moreinfo;    
  gpointer user_data;
  gpointer unused_data;
  GnomeUIPixmapType pixmap_type;
  gpointer pixmap_info;
  guint accelerator_key;
  GdkModifierType ac_mods;
  GtkWidget* widget;
} GnomeUIInfo;

Una inizializzazione statica si rivela spesso il metodo migliore per riempire la struttura (questa operazione può, ovviamente, essere eseguita dinamicamente). Le istruzioni di Gnome accettano un array di GnomeUIInfo, e sono fornite anche macro per semplificare e standardizzare gli oggetti più comuni. Ecco un esempio tipico, il menu File:

static GnomeUIInfo file_menu[] = {
  GNOMEUIINFO_MENU_NEW_ITEM(N_("_Nuova Finestra"),
                            N_("Crea una nuova finestre dell'editor"), 
                            new_app_cb, NULL),
  GNOMEUIINFO_MENU_OPEN_ITEM(open_cb,NULL),
  GNOMEUIINFO_MENU_SAVE_AS_ITEM(save_as_cb,NULL),
  GNOMEUIINFO_SEPARATOR,
  GNOMEUIINFO_MENU_CLOSE_ITEM(close_cb,NULL),
  GNOMEUIINFO_MENU_EXIT_ITEM(exit_cb,NULL),
  GNOMEUIINFO_END
};

Non sempre si trova la macro adatta alle proprie esigenze, quindi è necessario specificare manualmente ciascun elemento della struttura:

{ 
  GNOME_APP_UI_ITEM, N_("_Seleziona tutto"),
  N_("Seleziona tutte le celle del foglio di calcolo"), 
  select_all_cb, NULL,
  NULL, 0, 0, 'a', GDK_CONTROL_MASK 
}

In questo momento vi starete sicuramente chiedendo che cosa significhino tutti i membri della struttura. È molto semplice:

Vi starete sicuramente chiedendo perché le voci del menu contengano underscore: questi vengono utilizzati per creare la scorciatoia da tastiera per le voci del menu. I traduttori possono spostarlo a loro piacimento per rendere l'operazione più intuitiva possibile nella propria lingua. Gnome analizza la stringa alla ricerca della scorciatoia, rimuovendo successivamente l'underscore.

Tabella 1 elenca i possibili valori del campo type di una struttura GnomeUIInfo. Per maggiori informazioni si rimanda alla consultazione del file libgnomeui/gnome-app-helper.h. Esistono attualmente alcuni valori possibili, poiché gli altri vengono utilizzati internamente alla libreria. I valori in Tabella 1 dovrebbero comunque essere sufficienti per il codice di una applicazione.

Tabella 1. I valori di GnomeUIInfoType

GnomeUIInfoTypeDescrizioneCampo moreinfo
GNOME_APP_UI_ENDOFINFOTermina una tabella di GnomeUIInfoNessuno
GNOME_APP_UI_ITEMOggetto normale (oppure pulsante radio all'interno di un gruppo radio)Funzione callback
GNOME_APP_UI_TOGGLEITEMOggetto Toggle/CheckFunzione Callback
GNOME_APP_UI_RADIOITEMSGruppo pulsanti RadioArray di pulsanti radio all'interno del gruppo
GNOME_APP_UI_SUBTREESottomenuArray di GnomeUIInfo del sottomenu
GNOME_APP_UI_SEPARATORSeparatoreNessuno
GNOME_APP_UI_HELPOggetto di aiutoNodo di aiuto da visualizzare

Per creare un intero albero di menu, dovete includere i puntatori alle tabelle dei menu utilizzando la macro GNOMEUIINFO_SUBTREE() :

static GnomeUIInfo main_menu[] = {
  GNOMEUIINFO_SUBTREE(N_("_File"), file_menu),
  GNOMEUIINFO_END
};

In questo caso particolare esiste una macro più conveniente da utilizzare:

static GnomeUIInfo main_menu[] = {
  GNOMEUIINFO_MENU_FILE_TREE(file_menu),
  GNOMEUIINFO_END
};

Il principale vantaggio derivante dall'uso di questa macro è la standardizzazione. Questa assicura che tutti i menu file di Gnome utilizzino la stessa scorciatoia da tastiera e abbiamo lo stesso nome. Esistono svariate macro analoghe offerte da Gnome, la lista completa è reperibile in libgnomeui/gnome-app-helper.h.

Convertire GnomeUIInfo in un Widget

Una volta creta la tabella dei menu, questa verrà processata da Gnome e convertira in un widget. Le funzioni per questa operazione sono elencate in Figura 4

#include <libgnomeui/gnome-app-helper.h>

void gnome_app_create_menus(GnomeApp* app, GnomeUIInfo* uiinfo);

void gnome_app_create_menus_with_data(GnomeApp* app, GnomeUIInfo* uiinfo, gpointer user_data);

void gnome_app_create_toolbar(GnomeApp* app, GnomeUIInfo* uiinfo);

void gnome_app_create_toolbar_with_data(GnomeApp* app, GnomeUIInfo* uiinfo, gpointer user_data);

void gnome_app_fill_toolbar(GtkToolbar* toolbar, GnomeUIInfo* uiinfo, GtkAccelGroup* accel_group);

void gnome_app_fill_toolbar_with_data(GtkToolbar* toolbar, GnomeUIInfo* uiinfo, GtkAccelGroup* accel_group, gpointer data);

void gnome_app_fill_menu(GtkMenuShell* menushell, GnomeUIInfo* uiinfo, GtkAccelGroup* accel_group, gboolean uline_accels, gint pos);

void gnome_app_fill_menu_with_data(GtkMenuShell* menushell, GnomeUIInfo* uiinfo, GtkAccelGroup* accel_group, gboolean uline_accels, gint pos, gpointer user_data);

Figura 4. Creare widget da GnomeUIInfo

Se state utilizzando il widget GnomeApp widget, gnome_app_create_menus() e gnome_app_create_toolbar() creano un menu o una barra di pulsanti dalla tabella GnomeUIInfo fornita da voi, successivamente li inseriscono all'interno di GnomeApp. Queste sono le funzioni che vengono utilizzate nella maggior parte dei casi: tutto viene eseguito automaticamente. Esiste la variante _with_data() di ciascuna funzione che sostituisce il membro user_data della struttura GnomeUIInfo.

Se le vostre esigenze sono molto particolari, potete creare manualmente la barra di menu o di pulsanti e inserirle in un contenitore di vostro piacimento. Le funzioni fill richiedono di specificare il gruppo di scorciatoie per tastiera in cui inserire le singole scorciatoie. In GnomeApp esiste un gruppo di scorciatoie nelle struttura del widget stesso (il membro accel_group). Le funzioni fill per i menu richiedono due ulteriori argomenti: potete scegliere se far analizzare la stringa della voce del menu alla ricerca di un underscore per estrarre la scorciatoia, e potete specificare la posizione in GtkMenuShell da dove la funzione inizierà a inserire voci del menu.

(GtkMenuShell è semplicemente la classe di base per GtkMenuBar e GtkMenu, ad esempio è un widget che contiene le voci del menu. Un gruppo di scorciatoie è semplicemente una raccolta di queste, associato normalmente a un GtkWindow. Utilizzate GNOME_APP(widget)->accel_group in questo caso.)

Quando viene utilizzata una tabella GnomeUIInfo per creare una barra di menu o pulsanti, i puntatori ai widget delle singole voci del menu o pulsanti della barra sono presenti nel membro widget di ciascuna struttura GnomeUIInfo. È possibile quindi utilizzare questi puntatori per accedere ai singoli widget. Ad esempio, se create un oggetto check all'interno del menu è possibile accedervi per controllarne lo stato. Il puntatore è inoltre utile per creare manualmente alcune parti del menu: potete creare un sottomenu vuoto, e quindi manualmente crearne il contenuto.

GnomeHello: un esempio

L'applicazione GnomeHello crea le barre di menu e pulsanti utilizzando il metodo GnomeUIInfo. Il codice relativo è contenuto in un file separato, menus.c. L'Appendice E mostra questo file nella sua interezza.