libyui-gtk  2.49.0
YGWidget.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 <stdarg.h>
8 #include "YGWidget.h"
9 #include "YGUtils.h"
10 #include "ygtkratiobox.h"
11 #include "YGMacros.h"
12 
13 // default widgets border -- may be overlapped with a setBorder(..)
14 #define DEFAULT_BORDER 6
15 #define LABEL_WIDGET_SPACING 4
16 
17 /* Utilities */
18 
20 {
21  typedef std::pair <GObject *, gulong> Handler;
22  std::list <Handler> m_handlers;
23  void connectSignal (GObject *object, const char *name,
24  GCallback callback, gpointer data, bool after)
25  {
26  gulong handler;
27  if (after)
28  handler = g_signal_connect_after (object, name, callback, data);
29  else
30  handler = g_signal_connect (object, name, callback, data);
31 
32  Handler h (object, handler);
33  m_handlers.push_back (h);
34  }
35  void block()
36  {
37  for (std::list <Handler>::const_iterator it = m_handlers.begin();
38  it != m_handlers.end(); it++) {
39  const Handler &h = *it;
40  g_signal_handler_block (h.first, h.second);
41  }
42  }
43  void unblock()
44  {
45  for (std::list <Handler>::const_iterator it = m_handlers.begin();
46  it != m_handlers.end(); it++) {
47  const Handler &h = *it;
48  g_signal_handler_unblock (h.first, h.second);
49  }
50  }
51 };
52 
53 /* YGWidget follows */
54 
55 static void min_size_cb (guint *min_width, guint *min_height, gpointer pData);
56 
57 YGWidget::YGWidget(YWidget *ywidget, YWidget *yparent,
58  GType type, const char *property_name, ...)
59  : m_ywidget (ywidget)
60 {
61  va_list args;
62  va_start (args, property_name);
63  GtkWidget* gtkwidget = GTK_WIDGET (g_object_new_valist (type, property_name, args));
64  construct (ywidget, yparent, gtkwidget, property_name, args);
65  va_end (args);
66 }
67 
68 
69 YGWidget::YGWidget(YWidget *ywidget, YWidget *yparent,
70  GtkWidget *gtkwidget, const char *property_name, ...)
71  : m_ywidget (ywidget)
72 {
73  va_list args;
74  va_start (args, property_name);
75  construct (ywidget, yparent, gtkwidget, property_name, args);
76  va_end (args);
77 }
78 
79 
80 void YGWidget::construct (YWidget *ywidget, YWidget *yparent,
81  GtkWidget *gtkwidget, const char *property_name, va_list args)
82 {
83  m_widget = gtkwidget;
84 
85  m_adj_size = ygtk_adj_size_new();
86  g_object_ref_sink (G_OBJECT (m_adj_size));
87  gtk_widget_show (m_adj_size);
88  gtk_container_add (GTK_CONTAINER (m_adj_size), m_widget);
89  ygtk_adj_size_set_min_cb (YGTK_ADJ_SIZE (m_adj_size), min_size_cb, this);
90  gtk_widget_show (m_widget);
91 
92  // Split by two so that with another widget it will have full border...
93  setBorder (DEFAULT_BORDER / 2);
94 
95  ywidget->setWidgetRep ((void *) this);
96  if (yparent) {
97  ywidget->setParent (yparent);
98  yparent->addChild (ywidget);
99  }
100  m_signals = NULL;
101 }
102 
103 YGWidget::~YGWidget()
104 {
105  delete m_signals;
106  m_signals = 0;
107  if (YGUI::ui()->eventPendingFor (m_ywidget))
108  YGUI::ui()->m_event_handler.consumePendingEvent();
109  // remove children if container?
110 #if 0
111  struct inner {
112  static void foreach_child_cb (GtkWidget *child, GtkContainer *container)
113  { gtk_container_remove (container, child); }
114  };
115  if (GTK_IS_CONTAINER (m_widget))
116  gtk_container_foreach (GTK_CONTAINER (m_widget),
117  (GtkCallback) inner::foreach_child_cb, m_widget);
118 #endif
119  gtk_widget_destroy (m_adj_size);
120  g_object_unref (G_OBJECT (m_adj_size));
121 }
122 
123 YGWidget *YGWidget::get (YWidget *ywidget)
124 {
125  //g_assert (ywidget->widgetRep() != NULL);
126  return (YGWidget *) ywidget->widgetRep();
127 }
128 
129 bool YGWidget::doSetKeyboardFocus()
130 {
131  gtk_widget_grab_focus (getWidget());
132  return gtk_widget_is_focus (getWidget());
133 }
134 
135 void YGWidget::doSetEnabled (bool enabled)
136 {
137  gtk_widget_set_sensitive (getLayout(), enabled);
138 }
139 
140 void YGWidget::doSetUseBoldFont (bool useBold)
141 {
142  PangoWeight weight = useBold ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL;
143  YGUtils::setWidgetFont (getWidget(), PANGO_STYLE_NORMAL, weight, PANGO_SCALE_MEDIUM);
144 }
145 
146 void YGWidget::doAddChild (YWidget *ychild, GtkWidget *container)
147 {
148  GtkWidget *child = YGWidget::get (ychild)->getLayout();
149  gtk_container_add (GTK_CONTAINER (container), child);
150 }
151 
152 void YGWidget::doRemoveChild (YWidget *ychild, GtkWidget *container)
153 {
154  /* Note: removeChild() is generally a result of a widget being removed as it
155  will remove itself from the parent. But YGWidget deconstructor would run
156  before the YWidget one, as that's the order we have been using, so we
157  can't use it, we can't retrieve the GTK widget then. However, this is a
158  non-issue, as ~YGWidget will destroy the widget, and GTK will remove it
159  from the parent. */
160  if (!ychild->beingDestroyed()) {
161  GtkWidget *child = YGWidget::get (ychild)->getLayout();
162  gtk_container_remove (GTK_CONTAINER (container), child);
163  }
164 }
165 
166 int YGWidget::doPreferredSize (YUIDimension dimension)
167 {
168  // We might want to do some caching here..
169  GtkRequisition req;
170  gtk_widget_get_preferred_size (m_adj_size, &req, NULL);
171  return dimension == YD_HORIZ ? req.width : req.height;
172 }
173 
174 void min_size_cb (guint *min_width, guint *min_height, gpointer pData)
175 {
176  YGWidget *pThis = (YGWidget *) pData;
177  *min_width = pThis->getMinSize (YD_HORIZ);
178  *min_height = pThis->getMinSize (YD_VERT);
179 }
180 
181 #include "ygtkfixed.h"
182 
183 void YGWidget::doSetSize (int width, int height)
184 {
185  GtkWidget *parent = 0;
186  if (m_ywidget->parent())
187  parent = YGWidget::get (m_ywidget->parent())->getWidget();
188 
189  if (parent && YGTK_IS_FIXED (parent))
190  ygtk_fixed_set_child_size (YGTK_FIXED (parent), m_adj_size, width, height);
191 }
192 
193 void YGWidget::emitEvent (YEvent::EventReason reason, EventFlags flags)
194 {
195  struct inner
196  {
197  static gboolean dispatchEvent (gpointer data)
198  {
199  YWidgetEvent *event = (YWidgetEvent *) data;
200  if (!YGUI::ui()->eventPendingFor (event->widget()))
201  YGUI::ui()->sendEvent (event);
202  return FALSE;
203  }
204  };
205 
206  if (reason == YEvent::ContextMenuActivated && !m_ywidget->notifyContextMenu())
207  ; // cancel
208  if (flags & IGNORE_NOTIFY_EVENT || m_ywidget->notify()) {
209  YWidgetEvent *event = new YWidgetEvent (m_ywidget, reason);
210  if (flags & DELAY_EVENT)
211  g_timeout_add (250, inner::dispatchEvent, event);
212  else if (!(flags & IF_NOT_PENDING_EVENT) || !YGUI::ui()->eventPendingFor (m_ywidget))
213  YGUI::ui()->sendEvent (event);
214  }
215 }
216 
217 void YGWidget::connect (gpointer object, const char *name, GCallback callback, gpointer data,
218  bool after)
219 {
220  if (!m_signals)
221  m_signals = new YGWidget::Signals();
222  m_signals->connectSignal (G_OBJECT (object), name, callback, data, after);
223 }
224 
225 void YGWidget::blockSignals()
226 { if (m_signals) m_signals->block(); }
227 void YGWidget::unblockSignals()
228 { if (m_signals) m_signals->unblock(); }
229 
230 void YGWidget::setBorder (unsigned int border)
231 { gtk_container_set_border_width (GTK_CONTAINER (m_adj_size), border); }
232 
233 /* YGLabeledWidget follows */
234 
235 YGLabeledWidget::YGLabeledWidget (YWidget *ywidget, YWidget *parent,
236  const std::string &label_text, YUIDimension label_ori,
237  GtkWidget *gtkwidget, const char *property_name, ...)
238  : YGWidget (ywidget, parent,
239  gtkwidget, "spacing", LABEL_WIDGET_SPACING, NULL)
240 
241 {
242  // Create the field widget
243  va_list args;
244  va_start (args, property_name);
245  m_field = gtkwidget;
246  va_end (args);
247 
248  // Create the label
249  m_label = gtk_label_new ("");
250 
251 # if GTK_CHECK_VERSION (3, 14, 0)
252  gtk_widget_set_halign (m_label, GTK_ALIGN_START);
253  gtk_widget_set_valign (m_label, GTK_ALIGN_CENTER);
254 # else
255  gtk_misc_set_alignment (GTK_MISC (m_label), 0.0, 0.5);
256 # endif
257 
258 /* if (label_ori == YD_HORIZ)
259  gtk_label_set_line_wrap (GTK_LABEL (m_label), TRUE);*/
260  gtk_widget_show (m_label);
261  gtk_widget_show (m_field);
262 
263  setBuddy (m_field);
264  doSetLabel (label_text);
265 
266  // Set the container and show widgets
267  gtk_box_pack_start (GTK_BOX (m_widget), m_label, FALSE, TRUE, 0);
268  gtk_box_pack_start (GTK_BOX (m_widget), m_field, TRUE, TRUE, 0);
269  m_orientation = label_ori;
270 
271 }
272 
273 YGLabeledWidget::YGLabeledWidget (YWidget *ywidget, YWidget *parent,
274  const std::string &label_text, YUIDimension label_ori,
275  GType type, const char *property_name, ...)
276  : YGWidget (ywidget, parent,
277  YGTK_VBOX_NEW(0), "spacing", LABEL_WIDGET_SPACING, NULL)
278 {
279  // Create the field widget
280  va_list args;
281  va_start (args, property_name);
282  m_field = GTK_WIDGET (g_object_new_valist (type, property_name, args));
283  va_end (args);
284 
285  // Create the label
286  m_label = gtk_label_new ("");
287 
288 # if GTK_CHECK_VERSION (3, 14, 0)
289  gtk_widget_set_halign (m_label, GTK_ALIGN_START);
290  gtk_widget_set_valign (m_label, GTK_ALIGN_CENTER);
291 # else
292  gtk_misc_set_alignment (GTK_MISC (m_label), 0.0, 0.5);
293 # endif
294 
295 /* if (label_ori == YD_HORIZ)
296  gtk_label_set_line_wrap (GTK_LABEL (m_label), TRUE);*/
297  gtk_widget_show (m_label);
298  gtk_widget_show (m_field);
299 
300  setBuddy (m_field);
301  doSetLabel (label_text);
302 
303  // Set the container and show widgets
304  gtk_box_pack_start (GTK_BOX (m_widget), m_label, FALSE, TRUE, 0);
305  gtk_box_pack_start (GTK_BOX (m_widget), m_field, TRUE, TRUE, 0);
306  m_orientation = label_ori;
307 }
308 
309 void YGLabeledWidget::setLabelVisible (bool show)
310 {
311  if (show)
312  gtk_widget_show (m_label);
313  else
314  gtk_widget_hide (m_label);
315 }
316 
317 void YGLabeledWidget::setBuddy (GtkWidget *widget)
318 {
319  gtk_label_set_mnemonic_widget (GTK_LABEL (m_label), widget);
320 }
321 
322 void YGLabeledWidget::doSetLabel (const std::string &label)
323 {
324  if (!label.empty()) {
325  std::string str (YGUtils::mapKBAccel (label));
326 
327  // add a ':' at the end of the label, if not set
328  if (!str.empty()) {
329  const gchar *last = g_utf8_find_prev_char (str.c_str(), str.c_str() + str.length());
330  gunichar last_char = g_utf8_get_char (last);
331  if (g_unichar_isalpha (last_char)) { // append
332  bool reverse = false;
333  if (gtk_widget_get_direction (m_label) == GTK_TEXT_DIR_RTL &&
334  pango_find_base_dir (str.c_str(), -1) == PANGO_DIRECTION_LTR)
335  reverse = true;
336 
337  int i = reverse ? 0 : str.length();
338  str.insert (i, 1, ':');
339  }
340  }
341 
342  gtk_label_set_text (GTK_LABEL (m_label), str.c_str());
343  gtk_label_set_use_underline (GTK_LABEL (m_label), TRUE);
344  }
345  setLabelVisible (!label.empty());
346 }
347 
348 /* YGScrolledWidget follows */
349 #define MAX_SCROLL_WIDTH 120
350 
351 YGScrolledWidget::YGScrolledWidget (YWidget *ywidget, YWidget *parent,
352  GType type, const char *property_name, ...)
353  : YGLabeledWidget (ywidget, parent, std::string(), YD_VERT,
354  GTK_TYPE_SCROLLED_WINDOW, "shadow-type", GTK_SHADOW_IN, NULL)
355 {
356  va_list args;
357  va_start (args, property_name);
358  construct(type, property_name, args);
359  va_end (args);
360  setLabelVisible (false);
361 }
362 
363 YGScrolledWidget::YGScrolledWidget (YWidget *ywidget, YWidget *parent,
364  const std::string &label_text, YUIDimension label_ori,
365  GType type, const char *property_name, ...)
366  : YGLabeledWidget (ywidget, parent, label_text, label_ori,
367  GTK_TYPE_SCROLLED_WINDOW, "shadow-type", GTK_SHADOW_IN, NULL)
368 {
369  va_list args;
370  va_start (args, property_name);
371  construct(type, property_name, args);
372  va_end (args);
373 }
374 
375 void YGScrolledWidget::construct (GType type, const char *property_name,
376  va_list args)
377 {
378  m_widget = GTK_WIDGET (g_object_new_valist (type, property_name, args));
379  setBuddy (m_widget);
380 
381  setPolicy (GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
382  gtk_container_add (GTK_CONTAINER (YGLabeledWidget::getWidget()), m_widget);
383  gtk_widget_show (m_widget);
384 }
385 
386 void YGScrolledWidget::setPolicy (GtkPolicyType hpolicy, GtkPolicyType vpolicy)
387 {
388  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (YGLabeledWidget::getWidget()),
389  hpolicy, vpolicy);
390 }
391