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