libyui-gtk  2.46.0
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;
26  std::string str = YGUtils::mapKBAccel ((*it)->label());
27 
28  entry = gtk_menu_item_new_with_mnemonic (str.c_str());
29 
30  gtk_menu_shell_append (GTK_MENU_SHELL (parent), entry);
31 
32  if ((*it)->hasChildren()) {
33  GtkWidget *submenu = gtk_menu_new();
34  doCreateMenu (submenu, (*it)->childrenBegin(), (*it)->childrenEnd());
35  gtk_menu_item_set_submenu (GTK_MENU_ITEM (entry), submenu);
36  }
37  else
38  g_signal_connect (G_OBJECT (entry), "activate",
39  G_CALLBACK (selected_item_cb), *it);
40  }
41 }
42 
43 class YGMenuButton : public YMenuButton, public YGWidget
44 {
45 public:
46  YGMenuButton (YWidget *parent, const std::string &label)
47  : YMenuButton (NULL, label),
48  YGWidget (this, parent, YGTK_TYPE_MENU_BUTTON, NULL)
49  { setLabel (label); }
50 
51  // YMenuButton
52  virtual void setLabel (const std::string &label)
53  {
54  std::string str = YGUtils::mapKBAccel (label.c_str());
55  ygtk_menu_button_set_label (YGTK_MENU_BUTTON (getWidget()), str.c_str());
56  YMenuButton::setLabel (label);
57  }
58 
59  virtual void rebuildMenuTree()
60  {
61  GtkWidget *menu = gtk_menu_new();
62  doCreateMenu (menu, itemsBegin(), itemsEnd());
63  gtk_widget_show_all (menu);
64  ygtk_menu_button_set_popup (YGTK_MENU_BUTTON (getWidget()), menu);
65  }
66 
67  // NOTE copy of Qt one
68  void activateItem( YMenuItem * item )
69  {
70  if ( item )
71  YGUI::ui()->sendEvent( new YMenuEvent( item ) );
72  }
73 
74 
75  YGWIDGET_IMPL_COMMON (YMenuButton)
76 };
77 
78 YMenuButton *YGWidgetFactory::createMenuButton (YWidget *parent, const std::string &label)
79 { return new YGMenuButton (parent, label); }
80 
81 #include <YContextMenu.h>
82 
83 class YGContextMenu : public YContextMenu, public YGWidget
84 {
85  int m_deactivateTimeout;
86 
87 public:
89  : YContextMenu(),
90  YGWidget (this, NULL, GTK_TYPE_MENU, NULL)
91  {
92  // "cancel" signal doesnt seem to work properly
93  m_deactivateTimeout = 0;
94  connect (getWidget(), "deactivate", G_CALLBACK (deactivate_cb), this);
95  }
96 
97  // YContextMenu
98  virtual void rebuildMenuTree()
99  {
100  GtkWidget *menu = getWidget();
101  doCreateMenu (menu, itemsBegin(), itemsEnd());
102  gtk_widget_show_all (menu);
103  gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 3, gtk_get_current_event_time());
104  }
105 
106  // callbacks
107  static void deactivate_cb (GtkMenuShell *menu, YGContextMenu *pThis)
108  { // ugly: we need to make sure a selection was made before this callback called
109  // we'll use a timeout because deactivate seems to be called more than once
110  if(pThis->m_deactivateTimeout == 0)
111  pThis->m_deactivateTimeout = g_timeout_add_full (G_PRIORITY_LOW, 50, cancel_cb, pThis, NULL);
112  //g_idle_add_full (G_PRIORITY_LOW, cancel_cb, pThis, NULL);
113  }
114 
115  static gboolean cancel_cb (gpointer data)
116  {
117  YGContextMenu *pThis = (YGContextMenu *) data;
118  if (!g_object_get_data (G_OBJECT (pThis->getWidget()), "active"))
119  YGUI::ui()->sendEvent (new YCancelEvent());
120  delete pThis;
121  return FALSE;
122  }
123 
124  YGWIDGET_IMPL_COMMON (YContextMenu)
125 };
126 
127 bool YGApplication::openContextMenu (const YItemCollection &itemCollection)
128 {
129  YGContextMenu *menu = new YGContextMenu();
130  menu->addItems (itemCollection);
131  return true;
132 }
133