libyui-gtk  2.49.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 
104 # if GTK_CHECK_VERSION (3, 22, 0)
105  gtk_menu_popup_at_pointer (GTK_MENU (menu), NULL);
106 # else
107  gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 3, gtk_get_current_event_time());
108 # endif
109  }
110 
111  // callbacks
112  static void deactivate_cb (GtkMenuShell *menu, YGContextMenu *pThis)
113  { // ugly: we need to make sure a selection was made before this callback called
114  // we'll use a timeout because deactivate seems to be called more than once
115  if(pThis->m_deactivateTimeout == 0)
116  pThis->m_deactivateTimeout = g_timeout_add_full (G_PRIORITY_LOW, 50, cancel_cb, pThis, NULL);
117  //g_idle_add_full (G_PRIORITY_LOW, cancel_cb, pThis, NULL);
118  }
119 
120  static gboolean cancel_cb (gpointer data)
121  {
122  YGContextMenu *pThis = (YGContextMenu *) data;
123  if (!g_object_get_data (G_OBJECT (pThis->getWidget()), "active"))
124  YGUI::ui()->sendEvent (new YCancelEvent());
125  delete pThis;
126  return FALSE;
127  }
128 
129  YGWIDGET_IMPL_COMMON (YContextMenu)
130 };
131 
132 bool YGApplication::openContextMenu (const YItemCollection &itemCollection)
133 {
134  YGContextMenu *menu = new YGContextMenu();
135  menu->addItems (itemCollection);
136  return true;
137 }
138