libyui-gtk  2.49.0
YGPushButton.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 <YPushButton.h>
9 #include "YGUtils.h"
10 #include "YGWidget.h"
11 #include <string.h>
12 #include <libgen.h>
13 
14 #include <YLayoutBox.h>
15 #include "ygtkratiobox.h"
16 
17 class YGPushButton : public YPushButton, public YGWidget
18 {
19 bool m_customIcon, m_labelIcon;
20 
21 public:
22  YGPushButton (YWidget *parent, const std::string &label)
23  : YPushButton (NULL, label),
24  YGWidget (this, parent, GTK_TYPE_BUTTON, "can-default", TRUE, NULL)
25  {
26  m_customIcon = m_labelIcon = false;
27  gtk_button_set_use_underline (GTK_BUTTON (getWidget()), TRUE);
28  setLabel (label);
29  connect (getWidget(), "clicked", G_CALLBACK (clicked_cb), this);
30  g_signal_connect (getWidget(), "realize", G_CALLBACK (realize_cb), this);
31  }
32 
33  void setStockIcon (const std::string &label)
34  {
35  if (!m_customIcon) {
36  const char *icon = NULL;
37  switch (functionKey()) {
38  case 1: icon = "help-contents"; break;
39  case 2: icon = "dialog-information"; break; // Info
40  case 3: icon = "list-add"; break;
41  case 4: icon = "edit-copy"; break;
42  case 5: icon = "edit-delete"; break;
43  case 6: icon = "system-run"; break; // Test
44  case 7: icon = "edit-copy"; break; // Expert
45  // old expert icon: GTK_STOCK_PREFERENCES
46  // case 8: icon = "go-previous"; break;
47  case 9: icon = "application-exit"; break;
48  case 10: icon = "application-exit"; break; // Next/Finish/OK
49  default: break;
50  }
51  switch (role()) {
52  case YOKButton: icon = "document-save"; break;
53  case YApplyButton: icon = "document-save"; break;
54  case YCancelButton: icon = "document-revert"; break;
55  case YHelpButton: icon = "help-contents"; break;
56  case YCustomButton: case YMaxButtonRole: case YRelNotesButton: break;
57  }
58  m_labelIcon = YGUtils::setStockIcon (getWidget(), label, icon);
59  }
60  }
61 
62  // YPushButton
63  virtual void setLabel (const std::string &label)
64  {
65  YPushButton::setLabel (label);
66  std::string str = YGUtils::mapKBAccel (label);
67  gtk_button_set_label (GTK_BUTTON (getWidget()), str.c_str());
68  setStockIcon (str);
69  }
70 
71  virtual void setRole (YButtonRole role)
72  {
73  YPushButton::setRole (role);
74  if (!m_labelIcon && role != YCustomButton) // to avoid duplications
75  setStockIcon (label());
76  }
77 
78  virtual void setFunctionKey (int key)
79  {
80  YPushButton::setFunctionKey (key);
81  if (!m_labelIcon && hasFunctionKey())
82  setStockIcon (label());
83  }
84 
85  virtual void setHelpButton (bool helpButton)
86  {
87  YPushButton::setHelpButton (helpButton);
88  if (!m_labelIcon && helpButton)
89  setStockIcon (label());
90  }
91 
92  virtual void setIcon (const std::string &icon)
93  {
94  GtkButton *button = GTK_BUTTON (getWidget());
95  if (icon.empty()) {
96  m_customIcon = false;
97  // no need to worry about freeing the image, let it live with button
98  GtkWidget *image = gtk_button_get_image (button);
99  if (image)
100  gtk_widget_hide (image);
101  }
102  else {
103  m_customIcon = true;
104  std::string path (icon);
105  if (path[0] != '/')
106  path = std::string (THEMEDIR) + "/" + path;
107 
108  char *p = strdup(path.c_str());
109  char *p1 = strdup(path.c_str());
110  char *dname = dirname(p);
111  char *fname = basename(p1);
112  char *name = strtok (fname, ".");
113  GtkIconTheme * theme = gtk_icon_theme_get_default ();
114  gtk_icon_theme_add_resource_path (theme, dname);
115  gtk_icon_theme_prepend_search_path (theme, dname);
116  gtk_icon_theme_rescan_if_needed (theme);
117  GError *error = 0;
118  GdkPixbuf *pixbuf = gtk_icon_theme_load_icon (theme,
119  name, // icon name
120  16, // icon size (default button size)
121  GTK_ICON_LOOKUP_FORCE_SIZE, // flags
122  &error);
123  free (p);
124  free (p1);
125  if (pixbuf) {
126  GtkWidget *image = gtk_image_new_from_pixbuf (pixbuf);
127  gtk_button_set_image (button, image);
128  // disregard gtk-button-images setting for explicitly set icons
129  gtk_button_set_always_show_image (button, TRUE);
130  g_object_unref (G_OBJECT (pixbuf));
131  }
132  else
133  yuiWarning() << "YGPushButton: Couldn't load icon image: " << path << std::endl
134  << "Reason: " << error->message << std::endl;
135  }
136  }
137 
138  virtual void setDefaultButton (bool isDefault)
139  {
140  struct inner {
141  static void realize_cb (GtkWidget *widget)
142  {
143  gtk_widget_grab_default (widget);
144  gtk_widget_grab_focus (widget);
145  }
146  };
147 
148  YPushButton::setDefaultButton (isDefault);
149  if (isDefault) {
150  GtkWidget *button = getWidget();
151  gtk_widget_set_can_default(button, TRUE);
152  if (gtk_widget_get_realized (button))
153  inner::realize_cb (button);
154  g_signal_connect (G_OBJECT (button), "realize",
155  G_CALLBACK (inner::realize_cb), this);
156  }
157  }
158 
159  virtual void activate()
160  {
161  gtk_button_clicked(GTK_BUTTON (getWidget()));
162  }
163 
164  static bool hasIcon (YWidget *ywidget)
165  {
166  if (dynamic_cast <YPushButton *> (ywidget)) {
167  GtkWidget *button = YGWidget::get (ywidget)->getWidget();
168  GtkWidget *icon = gtk_button_get_image (GTK_BUTTON (button));
169  return icon && gtk_widget_get_visible (icon);
170  }
171  return true;
172  }
173 
174 #if 0
175  static gboolean treat_icon_cb (GtkWidget *widget, GdkEventExpose *event,
176  YGPushButton *pThis)
177  {
178  YLayoutBox *ybox = dynamic_cast <YLayoutBox *> (pThis->parent());
179  if (ybox && !pThis->m_customIcon) {
180  if (ybox->primary() == YD_HORIZ) {
181  // only set stock icons if all to the left have them
182  YWidget *ylast = 0;
183  for (YWidgetListConstIterator it = ybox->childrenBegin();
184  it != ybox->childrenEnd(); it++) {
185  if ((YWidget *) pThis == *it) {
186  if (ylast && !hasIcon (ylast))
187  pThis->setIcon ("");
188  break;
189  }
190  ylast = *it;
191  if (!dynamic_cast <YPushButton *> (ylast))
192  ylast = NULL;
193  }
194  }
195  else { // YD_VERT
196  // different strategy: set icons for all or none
197  bool disableIcons = false;
198  for (YWidgetListConstIterator it = ybox->childrenBegin();
199  it != ybox->childrenEnd(); it++)
200  if (!hasIcon (*it))
201  disableIcons = true;
202  if (disableIcons)
203  for (YWidgetListConstIterator it = ybox->childrenBegin();
204  it != ybox->childrenEnd(); it++)
205  if (dynamic_cast <YPushButton *> (*it)) {
206  YGPushButton *button = (YGPushButton *)
207  YGWidget::get (*it);
208  if (!button->m_customIcon)
209  button->setIcon ("");
210  }
211  }
212  }
213  g_signal_handlers_disconnect_by_func (widget, (gpointer) treat_icon_cb, pThis);
214  return FALSE;
215  }
216 #endif
217 
218  // callbacks
219  static void clicked_cb (GtkButton *button, YGPushButton *pThis)
220  { pThis->emitEvent (YEvent::Activated, IGNORE_NOTIFY_EVENT); }
221 
222 // default values from gtkbbox.c; can vary from style to style, but no way to query those
223 #define DEFAULT_CHILD_MIN_WIDTH 85
224 #define DEFAULT_CHILD_MIN_HEIGHT 27
225 
226  static void realize_cb (GtkWidget *widget, YGPushButton *pThis)
227  { // enlarge button if parent is ButtonBox
228  YWidget *yparent = pThis->m_ywidget->parent();
229  if (yparent && !strcmp (yparent->widgetClass(), "YButtonBox"))
230  ygtk_adj_size_set_min (YGTK_ADJ_SIZE(pThis->getLayout()),
231  DEFAULT_CHILD_MIN_WIDTH, DEFAULT_CHILD_MIN_HEIGHT);
232  }
233 
234  YGWIDGET_IMPL_COMMON (YPushButton)
235 };
236 
237 YPushButton *YGWidgetFactory::createPushButton (YWidget *parent, const std::string &label)
238 { return new YGPushButton (parent, label); }
239