Christian Robottom Reis wrote:

> Why not post to the list and have James and us review and check it in?
>

OK. The patch is attached with an example of how to use it. The gnomeuimodule.c and
the gnome/uiconsts.py files are patched as follows:

- fix list_to_ui_info() to pass on widget data that is in the UIINFO lists
- add a function to update the UIINFO lists to add the widget data after a call to:

        - gnome_app_create_menus_custom()
        - gnome_app_create_toolbar_custom()
        - gnome_app_insert_menus_custom()
        - gnome_popup_menu_new90
- fix list_to_ui_info() to pass inc_uibd to recursive calls
- add code to list_to_ui_info() and free_ui_info() to allow use of inline pixmap
data
- enable use of inline pixmap data in gnome/uiconsts.py

The UIINFO widget changes allow you to install hints in a statusbar or appbar and
to directly access the menu widgets using the UIINFO lists.
In order to save the widget info in the UIINFO lists the list items must themselves
be lists instead of tuples. If the items are tuples the original behavior will
apply so existing code should still work with these changes.

John
--- gnome/uiconsts.py.orig      Tue Apr 20 07:27:54 1999
+++ gnome/uiconsts.py   Wed Nov  7 10:32:23 2001
@@ -12,7 +12,7 @@
 
 APP_PIXMAP_NONE     = 0
 APP_PIXMAP_STOCK    = 1
-#APP_PIXMAP_DATA     = 2 # not supported by pygnome
+APP_PIXMAP_DATA     = 2 # now supported by pygnome
 APP_PIXMAP_FILENAME = 3
 
 # UIInfo entries are (type, label, tooltip, callback, cbdata,
@@ -24,8 +24,12 @@
                    APP_PIXMAP_NONE, None, 0, 0)
 def UIINFO_ITEM(label, tip=None, cb=None, image=None):
        if image:
-               return (APP_UI_ITEM, label, tip, cb, None,
-                       APP_PIXMAP_FILENAME, image, 0, 0)
+               if type(image) == type([]):
+                       return (APP_UI_ITEM, label, tip, cb, None,
+                               APP_PIXMAP_DATA, image, 0, 0)
+               else:
+                       return (APP_UI_ITEM, label, tip, cb, None,
+                               APP_PIXMAP_FILENAME, image, 0, 0)
        else:
                return (APP_UI_ITEM, label, tip, cb, None,
                        APP_PIXMAP_NONE, None, 0, 0)
@@ -35,8 +39,12 @@
        
 def UIINFO_TOGGLEITEM(label, tip=None, cb=None, image=None):
        if image:
-               return (APP_UI_TOGGLEITEM, label, tip, cb, None,
-                       APP_PIXMAP_FILENAME, image, 0, 0)
+               if type(image) == type([]):
+                       return (APP_UI_TOGGLEITEM, label, tip, cb, None,
+                               APP_PIXMAP_DATA, image, 0, 0)
+               else:
+                       return (APP_UI_TOGGLEITEM, label, tip, cb, None,
+                               APP_PIXMAP_FILENAME, image, 0, 0)
        else:
                return (APP_UI_TOGGLEITEM, label, tip, cb, None,
                        APP_PIXMAP_NONE, None, 0, 0)
@@ -58,8 +66,12 @@
 def UIINFO_RADIOITEM(label, tip=None, cb=None, image=None):
        print "Deprecated -- just use UIINFO_ITEM for radio list items"
        if image:
-               return (APP_UI_ITEM, label, tip, cb, None,
-                       APP_PIXMAP_FILENAME, image, 0, 0)
+               if type(image) == type([]):
+                       return (APP_UI_ITEM, label, tip, cb, None,
+                               APP_PIXMAP_DATA, image, 0, 0)
+               else:
+                       return (APP_UI_ITEM, label, tip, cb, None,
+                               APP_PIXMAP_FILENAME, image, 0, 0)
        else:
                return (APP_UI_ITEM, label, tip, cb, None,
                        APP_PIXMAP_NONE, None, 0, 0)
@@ -100,6 +112,9 @@
 def UIINFO_MENU_NEW_ITEM(label, tip, cb=None, data=None):
        return (APP_UI_ITEM_CONFIGURABLE, label, tip, cb, data,
                APP_PIXMAP_NONE, None, _APP_CONFIGURABLE_ITEM_NEW, 0)
+def UIINFO_MENU_NEW_SUBTREE(tree):
+        return (APP_UI_ITEM_SUBTREE_STOCK, "_New", None, tree, None,
+               APP_PIXMAP_STOCK, STOCK_MENU_NEW, 0, 0 )
 def UIINFO_MENU_OPEN_ITEM(cb=None, data=None):
        return (APP_UI_ITEM_CONFIGURABLE, None, None, cb, data,
                APP_PIXMAP_NONE, None, _APP_CONFIGURABLE_ITEM_OPEN, 0)
@@ -303,6 +318,7 @@
 STOCK_PIXMAP_TABLE_FILL    = "Table Fill"
 STOCK_PIXMAP_TEXT_BULLETED_LIST = "Text Bulleted List"
 STOCK_PIXMAP_TEXT_NUMBERED_LIST = "Text Numbered List"
+STOCK_PIXMAP_COLORSELECTOR = "Color Select"
 
 STOCK_PIXMAP_EXIT        = STOCK_PIXMAP_QUIT
 
--- gnomeuimodule.c.orig        Thu Apr  6 08:19:48 2000
+++ gnomeuimodule.c     Wed Nov  7 11:44:20 2001
@@ -64,10 +64,10 @@
 
 static GnomeUIInfo *list_to_ui_info(PyObject *list, gboolean inc_uibd) {
   GnomeUIInfo *ret, *inf, *sub;
-  PyObject *item, *moreinfo, *ac_mods;
-  int len, i;
+  PyObject *item, *moreinfo, *ac_mods, *pixmapinfo, *widget = NULL;
+  int len, i, j, pmlen;
   int type, pix_type;
-  char buf[100];
+  char buf[100], **data;
 
   if (!PyList_Check(list)) {
     PyErr_SetString(PyExc_TypeError, "object not a list");
@@ -86,22 +86,40 @@
   ret[len].type = GNOME_APP_UI_ENDOFINFO; /* set terminator */
   
   for (i = 0; i < len; i++) {
+    PyObject * savlist = NULL;
     item = PyList_GetItem(list, i);
-    if (!PyTuple_Check(item) || !PyArg_ParseTuple(item, "izzOOiziO",
+    if (PyList_Check(item)) {
+      savlist = item;
+      item = PySequence_Tuple(savlist);
+    }
+    if (!PyTuple_Check(item) || !PyArg_ParseTuple(item, "izzOOiOiO|O",
                                                  &(ret[i].type),
                                                  &(ret[i].label),
                                                  &(ret[i].hint),
                                                  &moreinfo,
                                                  &(ret[i].user_data),
                                                  &(ret[i].pixmap_type),
-                                                 &(ret[i].pixmap_info),
+                                                 &pixmapinfo,
                                                  &(ret[i].accelerator_key),
-                                                 &ac_mods) ||
+                                                 &ac_mods, &widget) ||
        PyGtkFlag_get_value(GTK_TYPE_GDK_MODIFIER_TYPE, ac_mods,
                            (gint *)&(ret[i].ac_mods))) {
       g_free(inf);
       return NULL;
     }
+    if (savlist) {
+      Py_DECREF(item);
+      item = savlist;
+      savlist = NULL;
+    }
+    if (widget == NULL || widget == Py_None) {
+      ret[i].widget = NULL;
+    } else {
+      if (PyGtk_Check(widget))
+        ret[i].widget = GTK_WIDGET(PyGtk_Get(widget));
+      else
+        ret[i].widget = NULL;
+    }
     if ((PyObject *)ret[i].user_data == Py_None)
       ret[i].user_data = NULL;
     else
@@ -111,13 +129,49 @@
        type == GNOME_APP_UI_BUILDER_DATA ||
        type > GNOME_APP_UI_SUBTREE_STOCK ||
        pix_type < GNOME_APP_PIXMAP_NONE ||
-       pix_type > GNOME_APP_PIXMAP_FILENAME ||
-       pix_type == GNOME_APP_PIXMAP_DATA) {
-      sprintf(buf, "bad info or pixmap type for label \"%s\"", ret[i].label);
+       pix_type > GNOME_APP_PIXMAP_FILENAME) {
+      g_snprintf(buf, 100, "bad info or pixmap type for label \"%s\"", ret[i].label);
       PyErr_SetString(PyExc_TypeError, buf);
       g_free(inf);
       return NULL;
     }
+    switch(pix_type) {
+    case GNOME_APP_PIXMAP_NONE:
+      ret[i].pixmap_info = NULL;
+      break;
+    case GNOME_APP_PIXMAP_STOCK:
+    case GNOME_APP_PIXMAP_FILENAME:
+      if (!PyString_Check(pixmapinfo)) {
+       PyErr_SetString(PyExc_TypeError,
+                       "pixmap info must be None, string or XPM data list");
+       g_free(inf);
+       return NULL;
+      }
+      ret[i].pixmap_info = PyString_AsString(pixmapinfo);
+      break;
+    case GNOME_APP_PIXMAP_DATA:
+      if (!PyList_Check(pixmapinfo)) {
+       PyErr_SetString(PyExc_TypeError,
+                       "pixmap info must be None, string or XPM data list");
+       g_free(inf);
+       return NULL;
+      }
+      pmlen = PyList_Size(pixmapinfo);
+      data = g_new(char *, pmlen);
+      for (j = 0; j < pmlen; j++) {
+       PyObject *item = PyList_GetItem(pixmapinfo, j);
+       if (!PyString_Check(item)) {
+         PyErr_SetString(PyExc_TypeError,
+                         "XPM data list items must be strings");
+         g_free(data);
+         g_free(inf);
+         return NULL;
+       }
+       data[j] = PyString_AsString(item);
+      }
+      ret[i].pixmap_info = data;
+      break;
+    }
     switch(type) {
     case GNOME_APP_UI_ENDOFINFO:
     case GNOME_APP_UI_SEPARATOR:
@@ -130,7 +184,7 @@
         break;
       }
       if (!PyCallable_Check(moreinfo)) {
-       sprintf(buf, "additional info not callable (label \"%s\")",
+       g_snprintf(buf, 100, "additional info not callable (label \"%s\")",
                ret[i].label);
        PyErr_SetString(PyExc_TypeError, buf);
        g_free(inf);
@@ -140,7 +194,7 @@
       Py_INCREF(moreinfo);
       break;
     case GNOME_APP_UI_RADIOITEMS:
-      sub = list_to_ui_info(moreinfo, FALSE);
+      sub = list_to_ui_info(moreinfo, inc_uibd);
       if (sub == NULL) {
        g_free(inf);
        return NULL;
@@ -149,7 +203,7 @@
       break;
     case GNOME_APP_UI_SUBTREE:
     case GNOME_APP_UI_SUBTREE_STOCK:
-      sub = list_to_ui_info(moreinfo, FALSE);
+      sub = list_to_ui_info(moreinfo, inc_uibd);
       if (sub == NULL) {
        g_free(inf);
        return NULL;
@@ -173,7 +227,7 @@
         break;
       }
       if (!PyCallable_Check(moreinfo)) {
-       sprintf(buf, "additional info not callable (label \"%s\")",
+       g_snprintf(buf, 100, "additional info not callable (label \"%s\")",
                ret[i].label);
        PyErr_SetString(PyExc_TypeError, buf);
        g_free(inf);
@@ -187,6 +241,52 @@
   return inf;
 }
 
+/* This function assumes that the GnomeUIInfo was constructed from the list
+   info.
+*/
+#define UIINFO_WIDGET_POS 9
+
+static void update_list_from_ui_info(PyObject *list, GnomeUIInfo *inf) {
+  PyObject *item, * widget, *sub;
+  int len, i, j;
+
+  if (!PyList_Check(list)) {
+    return;
+  }
+  len = PyList_Size(list);
+  for (i = 0, j = 0; i < len; i++, j++) {
+    item = PyList_GetItem(list, i);
+    if (!PyList_Check(item) || PyList_Size(item) < UIINFO_WIDGET_POS) {
+      continue;
+    }
+    sub = PyList_GetItem(item, 1);
+    if (inf[j].type == GNOME_APP_UI_BUILDER_DATA)
+      j++;
+    if (!inf[j].widget) {
+      Py_INCREF(Py_None);
+      widget = Py_None;
+    } else {
+      widget = PyGtk_New((GtkObject *)inf[j].widget);
+    }
+    if (PyList_Size(item) == UIINFO_WIDGET_POS) {
+      PyList_Append(item, widget);
+      Py_DECREF(widget);
+    } else {
+      PyList_SetItem(item, UIINFO_WIDGET_POS, widget);
+    }
+    if (inf[j].type == GNOME_APP_UI_RADIOITEMS ||
+       inf[j].type == GNOME_APP_UI_SUBTREE) {
+      if (inf[i].moreinfo !=  NULL) {
+       sub = PyList_GetItem(item, 3);
+       update_list_from_ui_info(sub, inf[i].moreinfo);
+      }
+      else if (inf[j].type == GNOME_APP_UI_ENDOFINFO)
+        break;
+    }
+  }
+  return;
+}
+
 static void free_ui_info(GnomeUIInfo *inf) {
   int i = 0;
   
@@ -202,6 +302,10 @@
       Py_DECREF((PyObject *)inf[i].moreinfo);
     if (inf[i].user_data != NULL)
       Py_DECREF((PyObject *)inf[i].user_data);
+    if (inf[i].pixmap_type == GNOME_APP_PIXMAP_DATA) {
+      g_free((char **)inf[i].pixmap_info);
+      inf[i].pixmap_info = NULL;
+    }
     i++;
   }
   g_free(inf);
@@ -338,6 +442,9 @@
     return NULL;
   gnome_app_create_menus_custom(GNOME_APP(PyGtk_Get(app)), uiinfo,
                                &PyGnome_UIBuilder);
+  Py_INCREF(list);
+  update_list_from_ui_info(list, uiinfo);
+  Py_DECREF(list);
   free_ui_info(uiinfo);
   Py_INCREF(Py_None);
   return Py_None;
@@ -354,6 +461,9 @@
     return NULL;
   gnome_app_create_toolbar_custom(GNOME_APP(PyGtk_Get(app)), uiinfo,
                                  &PyGnome_UIBuilder);
+  Py_INCREF(list);
+  update_list_from_ui_info(list, uiinfo);
+  Py_DECREF(list);
   free_ui_info(uiinfo);
   Py_INCREF(Py_None);
   return Py_None;
@@ -371,6 +481,9 @@
     return NULL;
   gnome_app_insert_menus_custom(GNOME_APP(PyGtk_Get(app)), path, uiinfo,
                                &PyGnome_UIBuilder);
+  Py_INCREF(list);
+  update_list_from_ui_info(list, uiinfo);
+  Py_DECREF(list);
   free_ui_info(uiinfo);
   Py_INCREF(Py_None);
   return Py_None;
@@ -1071,6 +1184,9 @@
   if ((uiinfo = list_to_ui_info(list, TRUE)) == NULL)
     return NULL;
   ret = PyGtk_New((GtkObject *)gnome_popup_menu_new(uiinfo));
+  Py_INCREF(list);
+  update_list_from_ui_info(list, uiinfo);
+  Py_DECREF(list);
   free_ui_info(uiinfo);
   return ret;
 }
#!/usr/bin/env python

# gnomeappbarmenu.py

from gtk import *
from gnome.ui import *

def fileOpen(object, data=None):
    GnomeOkDialog("\"File/Open\" selected.")

def fileClose(object, data=None):
    GnomeOkDialog("\"File/Close\" selected.")

def fileExit(object, data=None):
    mainquit()

def editCut(object, data=None):
    GnomeOkDialog("\"Edit/Cut\" selected.")

def editCopy(object, data=None):
    GnomeOkDialog("\"Edit/Copy\" selected.")

def editPaste(object, data=None):
    GnomeOkDialog("\"Edit/Paste\" selected.")

def editDelete(object, data=None):
    GnomeOkDialog("\"Edit/Delete\" selected.")

def editMoveUp(object, data=None):
    GnomeOkDialog("\"Edit/Move/Up\" selected.")

def editMoveDown(object, data=None):
    GnomeOkDialog("\"Edit/Move/Down\" selected.")

fileMenu = [
    [ APP_UI_ITEM,"_Open",
      "Open an existing file",
      fileOpen,None,
      APP_PIXMAP_NONE,
      None,0,0 ],
    [ APP_UI_ITEM,"_Close",
      "Close the current file",
      fileClose,None,
      APP_PIXMAP_NONE,
      None,0,0 ],
    UIINFO_SEPARATOR,
    [ APP_UI_ITEM,"E_xit",
      "Close the window and cease",
      fileExit,None,
      APP_PIXMAP_NONE,
      None,0,0 ],
]

editMoveMenu = [
    [ APP_UI_ITEM,"_Up",
      "Move selection up",
      editMoveUp,None,
      APP_PIXMAP_NONE,
      None,0,0 ],
    [ APP_UI_ITEM,"D_own",
      "Move selection down",
      editMoveDown,None,
      APP_PIXMAP_NONE,
      None,0,0 ],
]

editMenu = [
    [ APP_UI_ITEM,"_Cut",
      "Delete and copy selection to clipboard",
      editCut,None,
      APP_PIXMAP_NONE,
      None,0,0 ],
    [ APP_UI_ITEM,"Cop_y",
      "Copy selection to clipboard",
      editCopy,None,
      APP_PIXMAP_NONE,
      None,0,0 ],
    [ APP_UI_ITEM,"_Paste",
      "Paste selection from clipboard",
      editPaste,None,
      APP_PIXMAP_NONE,
      None,0,0, None ],
    list(UIINFO_SUBTREE_HINT("_Move", "Move Actions", editMoveMenu)),
    [ APP_UI_ITEM,"_Delete",
      "Delete the current selection",
      editDelete,None,
      APP_PIXMAP_NONE,
      None,0,0 ],
]

mainMenu = [
    list(UIINFO_SUBTREE_HINT("_File", "File Actions", fileMenu)),
    list(UIINFO_SUBTREE("_Edit", editMenu)),
]

def eventDelete(widget, event, data=None):
    return FALSE

def eventDestroy(widget, data=None):
    mainquit()
    return 0

def main():
    app = GnomeApp("gnomebase","Gnome Appbar Menu")
    app.set_default_size(200, 200)
    app.connect("delete_event", eventDelete)
    app.connect("destroy", eventDestroy)
    appbar = GnomeAppBar(FALSE,TRUE, PREFERENCES_USER)
    app.set_statusbar(appbar)
    app.create_menus(mainMenu)
    app.install_menu_hints(mainMenu)
    app.show_all()
    mainloop()

if __name__ =="__main__":
    main()

Reply via email to