libyui-gtk  2.44.9
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  // gtk_misc_set_alignment (GTK_MISC (m_label), 0.0, 0.5);
252  gtk_widget_set_halign (m_label, GTK_ALIGN_START);
253  gtk_widget_set_valign (m_label, GTK_ALIGN_CENTER);
254 
255 /* if (label_ori == YD_HORIZ)
256  gtk_label_set_line_wrap (GTK_LABEL (m_label), TRUE);*/
257  gtk_widget_show (m_label);
258  gtk_widget_show (m_field);
259 
260  setBuddy (m_field);
261  doSetLabel (label_text);
262 
263  // Set the container and show widgets
264  gtk_box_pack_start (GTK_BOX (m_widget), m_label, FALSE, TRUE, 0);
265  gtk_box_pack_start (GTK_BOX (m_widget), m_field, TRUE, TRUE, 0);
266  m_orientation = label_ori;
267 
268 }
269 
270 YGLabeledWidget::YGLabeledWidget (YWidget *ywidget, YWidget *parent,
271  const std::string &label_text, YUIDimension label_ori,
272  GType type, const char *property_name, ...)
273  : YGWidget (ywidget, parent,
274  YGTK_VBOX_NEW(0), "spacing", LABEL_WIDGET_SPACING, NULL)
275 {
276  // Create the field widget
277  va_list args;
278  va_start (args, property_name);
279  m_field = GTK_WIDGET (g_object_new_valist (type, property_name, args));
280  va_end (args);
281 
282  // Create the label
283  m_label = gtk_label_new ("");
284 
285  // gtk_misc_set_alignment (GTK_MISC (m_label), 0.0, 0.5);
286  gtk_widget_set_halign (m_label, GTK_ALIGN_START);
287  gtk_widget_set_valign (m_label, GTK_ALIGN_CENTER);
288 
289 /* if (label_ori == YD_HORIZ)
290  gtk_label_set_line_wrap (GTK_LABEL (m_label), TRUE);*/
291  gtk_widget_show (m_label);
292  gtk_widget_show (m_field);
293 
294  setBuddy (m_field);
295  doSetLabel (label_text);
296 
297  // Set the container and show widgets
298  gtk_box_pack_start (GTK_BOX (m_widget), m_label, FALSE, TRUE, 0);
299  gtk_box_pack_start (GTK_BOX (m_widget), m_field, TRUE, TRUE, 0);
300  m_orientation = label_ori;
301 }
302 
303 void YGLabeledWidget::setLabelVisible (bool show)
304 {
305  if (show)
306  gtk_widget_show (m_label);
307  else
308  gtk_widget_hide (m_label);
309 }
310 
311 void YGLabeledWidget::setBuddy (GtkWidget *widget)
312 {
313  gtk_label_set_mnemonic_widget (GTK_LABEL (m_label), widget);
314 }
315 
316 void YGLabeledWidget::doSetLabel (const std::string &label)
317 {
318  if (!label.empty()) {
319  std::string str (YGUtils::mapKBAccel (label));
320 
321  // add a ':' at the end of the label, if not set
322  if (!str.empty()) {
323  const gchar *last = g_utf8_find_prev_char (str.c_str(), str.c_str() + str.length());
324  gunichar last_char = g_utf8_get_char (last);
325  if (g_unichar_isalpha (last_char)) { // append
326  bool reverse = false;
327  if (gtk_widget_get_direction (m_label) == GTK_TEXT_DIR_RTL &&
328  pango_find_base_dir (str.c_str(), -1) == PANGO_DIRECTION_LTR)
329  reverse = true;
330 
331  int i = reverse ? 0 : str.length();
332  str.insert (i, 1, ':');
333  }
334  }
335 
336  gtk_label_set_text (GTK_LABEL (m_label), str.c_str());
337  gtk_label_set_use_underline (GTK_LABEL (m_label), TRUE);
338  }
339  setLabelVisible (!label.empty());
340 }
341 
342 /* YGScrolledWidget follows */
343 #define MAX_SCROLL_WIDTH 120
344 
345 YGScrolledWidget::YGScrolledWidget (YWidget *ywidget, YWidget *parent,
346  GType type, const char *property_name, ...)
347  : YGLabeledWidget (ywidget, parent, std::string(), YD_VERT,
348  GTK_TYPE_SCROLLED_WINDOW, "shadow-type", GTK_SHADOW_IN, NULL)
349 {
350  va_list args;
351  va_start (args, property_name);
352  construct(type, property_name, args);
353  va_end (args);
354  setLabelVisible (false);
355 }
356 
357 YGScrolledWidget::YGScrolledWidget (YWidget *ywidget, YWidget *parent,
358  const std::string &label_text, YUIDimension label_ori,
359  GType type, const char *property_name, ...)
360  : YGLabeledWidget (ywidget, parent, label_text, label_ori,
361  GTK_TYPE_SCROLLED_WINDOW, "shadow-type", GTK_SHADOW_IN, NULL)
362 {
363  va_list args;
364  va_start (args, property_name);
365  construct(type, property_name, args);
366  va_end (args);
367 }
368 
369 void YGScrolledWidget::construct (GType type, const char *property_name,
370  va_list args)
371 {
372  m_widget = GTK_WIDGET (g_object_new_valist (type, property_name, args));
373  setBuddy (m_widget);
374 
375  setPolicy (GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
376  gtk_container_add (GTK_CONTAINER (YGLabeledWidget::getWidget()), m_widget);
377  gtk_widget_show (m_widget);
378 }
379 
380 void YGScrolledWidget::setPolicy (GtkPolicyType hpolicy, GtkPolicyType vpolicy)
381 {
382  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (YGLabeledWidget::getWidget()),
383  hpolicy, vpolicy);
384 }
385