libyui-gtk  2.42.2
 All Classes
YGMenuButton.cc
1 /********************************************************************
2  * YaST2-GTK - http://en.opensuse.org/YaST2-GTK *
3  ********************************************************************/
4 
5 #define YUILogComponent "gtk"
6 #include <yui/Libyui_config.h>
7 #include "YGUI.h"
8 #include "YGUtils.h"
9 #include "YGWidget.h"
10 #include "YMenuButton.h"
11 #include "ygtkmenubutton.h"
12 
13 static void selected_item_cb (GtkMenuItem *menuitem, YItem *item)
14 {
15  // HACK: gtk_menu_get_active() doesn't work properly
16  GtkWidget *menu = gtk_widget_get_ancestor (GTK_WIDGET (menuitem), GTK_TYPE_MENU);
17  g_object_set_data (G_OBJECT (menu), "active", menuitem);
18 
19  YGUI::ui()->sendEvent (new YMenuEvent (item));
20 }
21 
22 static void doCreateMenu (GtkWidget *parent, YItemIterator begin, YItemIterator end)
23 {
24  for (YItemIterator it = begin; it != end; it++) {
25  GtkWidget *entry, *image = 0;
26  std::string str = YGUtils::mapKBAccel ((*it)->label());
27 
28  if ((*it)->hasIconName()) {
29  GdkPixbuf *pixbuf = YGUtils::loadPixbuf ((*it)->iconName());
30  if (pixbuf) {
31  image = gtk_image_new_from_pixbuf (pixbuf);
32  g_object_unref (G_OBJECT (pixbuf));
33  }
34  }
35  else {
36  const char *stock = YGUtils::mapStockIcon (str);
37  if (stock)
38  image = gtk_image_new_from_stock (stock, GTK_ICON_SIZE_MENU);
39  }
40 
41  if (image) {
42  entry = gtk_image_menu_item_new_with_mnemonic (str.c_str());
43  gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (entry), image);
44  }
45  else
46  entry = gtk_menu_item_new_with_mnemonic (str.c_str());
47 
48  gtk_menu_shell_append (GTK_MENU_SHELL (parent), entry);
49 
50  if ((*it)->hasChildren()) {
51  GtkWidget *submenu = gtk_menu_new();
52  doCreateMenu (submenu, (*it)->childrenBegin(), (*it)->childrenEnd());
53  gtk_menu_item_set_submenu (GTK_MENU_ITEM (entry), submenu);
54  }
55  else
56  g_signal_connect (G_OBJECT (entry), "activate",
57  G_CALLBACK (selected_item_cb), *it);
58  }
59 }
60 
61 class YGMenuButton : public YMenuButton, public YGWidget
62 {
63 public:
64  YGMenuButton (YWidget *parent, const std::string &label)
65  : YMenuButton (NULL, label),
66  YGWidget (this, parent, YGTK_TYPE_MENU_BUTTON, NULL)
67  { setLabel (label); }
68 
69  // YMenuButton
70  virtual void setLabel (const std::string &label)
71  {
72  std::string str = YGUtils::mapKBAccel (label.c_str());
73  ygtk_menu_button_set_label (YGTK_MENU_BUTTON (getWidget()), str.c_str());
74  YMenuButton::setLabel (label);
75  }
76 
77  virtual void rebuildMenuTree()
78  {
79  GtkWidget *menu = gtk_menu_new();
80  doCreateMenu (menu, itemsBegin(), itemsEnd());
81  gtk_widget_show_all (menu);
82  ygtk_menu_button_set_popup (YGTK_MENU_BUTTON (getWidget()), menu);
83  }
84 
85  YGWIDGET_IMPL_COMMON (YMenuButton)
86 };
87 
88 YMenuButton *YGWidgetFactory::createMenuButton (YWidget *parent, const std::string &label)
89 { return new YGMenuButton (parent, label); }
90 
91 #include <YContextMenu.h>
92 
93 class YGContextMenu : public YContextMenu, public YGWidget
94 {
95  int m_deactivateTimeout;
96 
97 public:
99  : YContextMenu(),
100  YGWidget (this, NULL, GTK_TYPE_MENU, NULL)
101  {
102  // "cancel" signal doesnt seem to work properly
103  m_deactivateTimeout = 0;
104  connect (getWidget(), "deactivate", G_CALLBACK (deactivate_cb), this);
105  }
106 
107  // YContextMenu
108  virtual void rebuildMenuTree()
109  {
110  GtkWidget *menu = getWidget();
111  doCreateMenu (menu, itemsBegin(), itemsEnd());
112  gtk_widget_show_all (menu);
113  gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 3, gtk_get_current_event_time());
114  }
115 
116  // callbacks
117  static void deactivate_cb (GtkMenuShell *menu, YGContextMenu *pThis)
118  { // ugly: we need to make sure a selection was made before this callback called
119  // we'll use a timeout because deactivate seems to be called more than once
120  if(pThis->m_deactivateTimeout == 0)
121  pThis->m_deactivateTimeout = g_timeout_add_full (G_PRIORITY_LOW, 50, cancel_cb, pThis, NULL);
122  //g_idle_add_full (G_PRIORITY_LOW, cancel_cb, pThis, NULL);
123  }
124 
125  static gboolean cancel_cb (gpointer data)
126  {
127  YGContextMenu *pThis = (YGContextMenu *) data;
128  if (!g_object_get_data (G_OBJECT (pThis->getWidget()), "active"))
129  YGUI::ui()->sendEvent (new YCancelEvent());
130  delete pThis;
131  return FALSE;
132  }
133 
134  YGWIDGET_IMPL_COMMON (YContextMenu)
135 };
136 
137 bool YGApplication::openContextMenu (const YItemCollection &itemCollection)
138 {
139  YGContextMenu *menu = new YGContextMenu();
140  menu->addItems (itemCollection);
141  return true;
142 }
143