URI:
       titemfactory.c - vaccinewars - be a doctor and try to vaccinate the world
  HTML git clone git://src.adamsgaard.dk/vaccinewars
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       titemfactory.c (8647B)
       ---
            1 /************************************************************************
            2  * itemfactory.c  GtkItemFactory and friends for Unix/Win32             *
            3  * Copyright (C)  1998-2021  Ben Webb                                   *
            4  *                Email: benwebb@users.sf.net                           *
            5  *                WWW: https://dopewars.sourceforge.io/                 *
            6  *                                                                      *
            7  * This program is free software; you can redistribute it and/or        *
            8  * modify it under the terms of the GNU General Public License          *
            9  * as published by the Free Software Foundation; either version 2       *
           10  * of the License, or (at your option) any later version.               *
           11  *                                                                      *
           12  * This program is distributed in the hope that it will be useful,      *
           13  * but WITHOUT ANY WARRANTY; without even the implied warranty of       *
           14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *
           15  * GNU General Public License for more details.                         *
           16  *                                                                      *
           17  * You should have received a copy of the GNU General Public License    *
           18  * along with this program; if not, write to the Free Software          *
           19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston,               *
           20  *                   MA  02111-1307, USA.                               *
           21  ************************************************************************/
           22 
           23 #ifdef HAVE_CONFIG_H
           24 #include <config.h>
           25 #endif
           26 
           27 #include "gtkport.h"
           28 
           29 /* No need to reimplement functions if we have GTK+2 */
           30 #if GTK_MAJOR_VERSION == 2
           31 GtkItemFactory *dp_gtk_item_factory_new(const gchar *path,
           32                                         GtkAccelGroup *accel_group)
           33 {
           34   return gtk_item_factory_new(GTK_TYPE_MENU_BAR, path, accel_group);
           35 }
           36 #endif
           37 
           38 #if defined(CYGWIN) || GTK_MAJOR_VERSION > 2
           39 
           40 #ifdef CYGWIN
           41 
           42 #define OurAccel ACCEL
           43 
           44 #else
           45 typedef struct _OurAccel OurAccel;
           46 struct _OurAccel {
           47   guint key;
           48   GdkModifierType mods;
           49   GtkAccelFlags flags;
           50 };
           51 #endif
           52 
           53 typedef struct _DPGtkItemFactoryChild DPGtkItemFactoryChild;
           54 
           55 struct _DPGtkItemFactoryChild {
           56   gchar *path;
           57   GtkWidget *widget;
           58 };
           59 
           60 DPGtkItemFactory *dp_gtk_item_factory_new(const gchar *path,
           61                                           GtkAccelGroup *accel_group)
           62 {
           63   DPGtkItemFactory *new_fac;
           64 
           65   new_fac = g_new0(DPGtkItemFactory, 1);
           66   new_fac->path = g_strdup(path);
           67   new_fac->accel_group = accel_group;
           68   new_fac->top_widget = gtk_menu_bar_new();
           69   new_fac->translate_func = NULL;
           70   return new_fac;
           71 }
           72 
           73 static gint PathCmp(const gchar *path1, const gchar *path2)
           74 {
           75   gint Match = 1;
           76 
           77   if (!path1 || !path2)
           78     return 0;
           79 
           80   while (*path1 && *path2 && Match) {
           81     while (*path1 == '_')
           82       path1++;
           83     while (*path2 == '_')
           84       path2++;
           85     if (*path1 == *path2) {
           86       path1++;
           87       path2++;
           88     } else
           89       Match = 0;
           90   }
           91   if (*path1 || *path2)
           92     Match = 0;
           93   return Match;
           94 }
           95 
           96 static gchar *TransPath(DPGtkItemFactory *ifactory, gchar *path)
           97 {
           98   gchar *transpath = NULL;
           99 
          100   if (ifactory->translate_func) {
          101     transpath =
          102         (*ifactory->translate_func) (path, ifactory->translate_data);
          103   }
          104 
          105   return transpath ? transpath : path;
          106 }
          107 
          108 static void gtk_item_factory_parse_path(DPGtkItemFactory *ifactory,
          109                                         gchar *path,
          110                                         DPGtkItemFactoryChild **parent,
          111                                         GString *menu_title)
          112 {
          113   GSList *list;
          114   DPGtkItemFactoryChild *child;
          115   gchar *root, *pt, *transpath;
          116 
          117   transpath = TransPath(ifactory, path);
          118   pt = strrchr(transpath, '/');
          119   if (pt)
          120     g_string_assign(menu_title, pt + 1);
          121 
          122   pt = strrchr(path, '/');
          123   if (!pt)
          124     return;
          125   root = g_strdup(path);
          126   root[pt - path] = '\0';
          127 
          128   for (list = ifactory->children; list; list = g_slist_next(list)) {
          129     child = (DPGtkItemFactoryChild *)list->data;
          130     if (PathCmp(child->path, root) == 1) {
          131       *parent = child;
          132       break;
          133     }
          134   }
          135   g_free(root);
          136 }
          137 
          138 static gboolean gtk_item_factory_parse_accel(DPGtkItemFactory *ifactory,
          139                                              gchar *accelerator,
          140                                              GString *menu_title,
          141                                              OurAccel *accel)
          142 {
          143   gchar *apt;
          144 
          145   if (!accelerator)
          146     return FALSE;
          147 
          148   apt = accelerator;
          149 #ifdef CYGWIN
          150   accel->fVirt = 0;
          151   accel->key = 0;
          152   accel->cmd = 0;
          153   g_string_append(menu_title, "\t");
          154 #else
          155   accel->key = 0;
          156   accel->mods = 0;
          157   accel->flags = GTK_ACCEL_VISIBLE;
          158 #endif
          159 
          160   if (strncmp(apt, "<control>", 9) == 0) {
          161 #ifdef CYGWIN
          162     accel->fVirt |= FCONTROL;
          163     g_string_append(menu_title, "Ctrl+");
          164 #else
          165     accel->mods |= GDK_CONTROL_MASK;
          166 #endif
          167     apt += 9;
          168   }
          169 
          170   if (strlen(apt) == 1) {
          171     accel->key = *apt;
          172 #ifdef CYGWIN
          173     g_string_append_c(menu_title, *apt);
          174     accel->fVirt |= FVIRTKEY;
          175 #endif
          176   } else if (strcmp(apt, "F1") == 0) {
          177 #ifdef CYGWIN
          178     g_string_append(menu_title, apt);
          179     accel->fVirt |= FVIRTKEY;
          180     accel->key = VK_F1;
          181 #else
          182     accel->key = GDK_KEY_F1;
          183 #endif
          184   }
          185   return (accel->key != 0);
          186 }
          187 
          188 void dp_gtk_item_factory_create_item(DPGtkItemFactory *ifactory,
          189                                      DPGtkItemFactoryEntry *entry,
          190                                      gpointer callback_data,
          191                                      guint callback_type)
          192 {
          193   DPGtkItemFactoryChild *new_child, *parent = NULL;
          194   GString *menu_title;
          195   GtkWidget *menu_item, *menu;
          196   OurAccel accel;
          197   gboolean haveaccel;
          198 
          199   new_child = g_new0(DPGtkItemFactoryChild, 1);
          200 
          201   new_child->path = g_strdup(entry->path);
          202 
          203   menu_title = g_string_new("");
          204 
          205   gtk_item_factory_parse_path(ifactory, new_child->path, &parent,
          206                               menu_title);
          207   haveaccel =
          208       gtk_item_factory_parse_accel(ifactory, entry->accelerator,
          209                                    menu_title, &accel);
          210 
          211   if (entry->item_type && strcmp(entry->item_type, "<CheckItem>") == 0) {
          212     menu_item = gtk_check_menu_item_new_with_mnemonic(menu_title->str);
          213     gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_item), TRUE);
          214   } else {
          215     menu_item = gtk_menu_item_new_with_mnemonic(menu_title->str);
          216   }
          217   new_child->widget = menu_item;
          218   if (entry->callback) {
          219     g_signal_connect(G_OBJECT(menu_item), "activate",
          220                      entry->callback, callback_data);
          221   }
          222 
          223   if (parent) {
          224     menu = GTK_WIDGET(gtk_menu_item_get_submenu(GTK_MENU_ITEM(parent->widget)));
          225     if (!menu) {
          226       menu = gtk_menu_new();
          227       gtk_menu_item_set_submenu(GTK_MENU_ITEM(parent->widget), menu);
          228     }
          229     gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
          230   } else {
          231     gtk_menu_shell_append(GTK_MENU_SHELL(ifactory->top_widget), menu_item);
          232   }
          233 
          234   if (haveaccel && ifactory->accel_group) {
          235 #ifdef CYGWIN
          236     GTK_MENU_ITEM(menu_item)->accelind =
          237         gtk_accel_group_add(ifactory->accel_group, &accel);
          238 #else
          239     gtk_widget_add_accelerator(menu_item, "activate", ifactory->accel_group,
          240                                accel.key, accel.mods, accel.flags);
          241 #endif
          242   }
          243 
          244   g_string_free(menu_title, TRUE);
          245 
          246   ifactory->children = g_slist_append(ifactory->children, new_child);
          247 }
          248 
          249 void dp_gtk_item_factory_create_items(DPGtkItemFactory *ifactory,
          250                                       guint n_entries,
          251                                       DPGtkItemFactoryEntry *entries,
          252                                       gpointer callback_data)
          253 {
          254   gint i;
          255 
          256   for (i = 0; i < n_entries; i++) {
          257     dp_gtk_item_factory_create_item(ifactory, &entries[i], callback_data, 0);
          258   }
          259 }
          260 
          261 GtkWidget *dp_gtk_item_factory_get_widget(DPGtkItemFactory *ifactory,
          262                                           const gchar *path)
          263 {
          264   gint root_len;
          265   GSList *list;
          266   DPGtkItemFactoryChild *child;
          267 
          268   root_len = strlen(ifactory->path);
          269   if (!path || strlen(path) < root_len)
          270     return NULL;
          271 
          272   if (strncmp(ifactory->path, path, root_len) != 0)
          273     return NULL;
          274   if (strlen(path) == root_len)
          275     return ifactory->top_widget;
          276 
          277   for (list = ifactory->children; list; list = g_slist_next(list)) {
          278     child = (DPGtkItemFactoryChild *)list->data;
          279     if (PathCmp(child->path, &path[root_len]) == 1)
          280       return child->widget;
          281   }
          282   return NULL;
          283 }
          284 
          285 void dp_gtk_item_factory_set_translate_func(DPGtkItemFactory *ifactory,
          286                                             DPGtkTranslateFunc func,
          287                                             gpointer data,
          288                                             GDestroyNotify notify)
          289 {
          290   ifactory->translate_func = func;
          291   ifactory->translate_data = data;
          292 }
          293 
          294 #endif   /* defined(CYGWIN) || GTK_MAJOR_VERSION > 2 */