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