1 /*
2 * Copyright (C) 2009 - 2011 Vivien Malerba <malerba@gnome-db.org>
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19 #include "gdaui-bar.h"
20
21 struct _GdauiBarPrivate
22 {
23 GtkWidget *content_area;
24 GtkWidget *action_area;
25
26 GtkWidget *icon;
27 gboolean show_icon;
28 GtkWidget *label;
29 };
30
31 /* Properties */
32 enum {
33 PROP_0,
34 PROP_TEXT,
35 PROP_SHOW_ICON
36 };
37
38 static GObjectClass *parent_class = NULL;
39 static GtkStyleProvider *css_provider = NULL;
40
41 #define ACTION_AREA_DEFAULT_BORDER 2
42 #define ACTION_AREA_DEFAULT_SPACING 2
43 #define CONTENT_AREA_DEFAULT_BORDER 5
44 #define CONTENT_AREA_DEFAULT_SPACING 2
45
46 static void gdaui_bar_class_init (GdauiBarClass *klass);
47 static void gdaui_bar_init (GdauiBar *bar);
48 static void gdaui_bar_set_property (GObject *object,
49 guint prop_id,
50 const GValue *value,
51 GParamSpec *pspec);
52 static void gdaui_bar_get_property (GObject *object,
53 guint prop_id,
54 GValue *value,
55 GParamSpec *pspec);
56 static void gdaui_bar_get_preferred_width (GtkWidget *widget,
57 gint *minimum_width,
58 gint *natural_width);
59 static void gdaui_bar_get_preferred_height (GtkWidget *widget,
60 gint *minimum_height,
61 gint *natural_height);
62 static gboolean gdaui_bar_draw (GtkWidget *widget, cairo_t *cr);
63 static void gdaui_bar_dispose (GObject *object);
64
65 GType
gdaui_bar_get_type(void)66 gdaui_bar_get_type (void)
67 {
68 static GType type = 0;
69
70 if (G_UNLIKELY (type == 0)) {
71 static const GTypeInfo info = {
72 sizeof (GdauiBarClass),
73 (GBaseInitFunc) NULL,
74 (GBaseFinalizeFunc) NULL,
75 (GClassInitFunc) gdaui_bar_class_init,
76 NULL,
77 NULL,
78 sizeof (GdauiBar),
79 0,
80 (GInstanceInitFunc) gdaui_bar_init,
81 0
82 };
83 type = g_type_register_static (GTK_TYPE_BOX, "GdauiBar", &info, 0);
84 }
85 return type;
86 }
87
88 static void
gdaui_bar_class_init(GdauiBarClass * klass)89 gdaui_bar_class_init (GdauiBarClass *klass)
90 {
91 GtkWidgetClass *widget_class;
92 GObjectClass *object_class;
93
94 parent_class = g_type_class_peek_parent (klass);
95 widget_class = GTK_WIDGET_CLASS (klass);
96 object_class = G_OBJECT_CLASS (klass);
97
98 object_class->get_property = gdaui_bar_get_property;
99 object_class->set_property = gdaui_bar_set_property;
100 object_class->dispose = gdaui_bar_dispose;
101
102 widget_class->get_preferred_width = gdaui_bar_get_preferred_width;
103 widget_class->get_preferred_height = gdaui_bar_get_preferred_height;
104 widget_class->draw = gdaui_bar_draw;
105
106 /* add class properties */
107 g_object_class_install_property (object_class, PROP_TEXT,
108 g_param_spec_string ("text", NULL,
109 "Text showed inside the widget.", NULL,
110 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
111 g_object_class_install_property (object_class, PROP_SHOW_ICON,
112 g_param_spec_boolean ("show_icon", NULL, NULL, FALSE,
113 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
114 }
115
116 static void
gdaui_bar_init(GdauiBar * bar)117 gdaui_bar_init (GdauiBar *bar)
118 {
119 GtkWidget *widget = GTK_WIDGET (bar);
120 GtkWidget *content_area;
121 GtkWidget *action_area;
122
123 bar->priv = g_new0 (GdauiBarPrivate, 1);
124
125 content_area = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
126 gtk_widget_show (content_area);
127 gtk_box_pack_start (GTK_BOX (bar), content_area, TRUE, TRUE, 0);
128
129 action_area = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
130 gtk_widget_show (action_area);
131 gtk_box_pack_start (GTK_BOX (bar), action_area, FALSE, TRUE, 0);
132
133 gtk_widget_set_app_paintable (widget, TRUE);
134 gtk_widget_set_redraw_on_allocate (widget, TRUE);
135
136 bar->priv->content_area = content_area;
137 bar->priv->action_area = action_area;
138
139 /* set default spacings */
140 gtk_box_set_spacing (GTK_BOX (bar->priv->action_area), ACTION_AREA_DEFAULT_SPACING);
141 gtk_container_set_border_width (GTK_CONTAINER (bar->priv->action_area), ACTION_AREA_DEFAULT_BORDER);
142 gtk_box_set_spacing (GTK_BOX (bar->priv->content_area), CONTENT_AREA_DEFAULT_SPACING);
143 gtk_container_set_border_width (GTK_CONTAINER (bar->priv->content_area), CONTENT_AREA_DEFAULT_BORDER);
144
145 bar->priv->show_icon = FALSE;
146 bar->priv->icon = gtk_image_new ();
147 gtk_misc_set_alignment (GTK_MISC (bar->priv->icon), 1., 0.5);
148 gtk_widget_hide (bar->priv->icon);
149 gtk_box_pack_end (GTK_BOX (bar->priv->content_area), bar->priv->icon,
150 FALSE, TRUE, 0);
151
152 bar->priv->label = gtk_label_new ("");
153 gtk_label_set_selectable (GTK_LABEL (bar->priv->label), FALSE);
154 gtk_misc_set_alignment (GTK_MISC (bar->priv->label), 0., 0.5);
155 gtk_box_pack_end (GTK_BOX (bar->priv->content_area), bar->priv->label,
156 TRUE, TRUE, 0);
157 gtk_widget_show (bar->priv->label);
158
159 /* CSS theming */
160 GtkStyleContext *context;
161 if (!css_provider) {
162 #define CSS ".gdauibar {\n" \
163 "background-color: #b3b3b3;\n" \
164 "padding: 5px;\n" \
165 "}" \
166 ".gdauibar_button {\n" \
167 "-GtkButton-default-border : 0px;\n" \
168 "-GtkButton-default-outside-border : 0px;\n" \
169 "-GtkWidget-focus-line-width : 0px;\n" \
170 "-GtkWidget-focus-padding : 0px;\n" \
171 "padding: 0px;\n" \
172 "-GtkButtonBox-child-internal-pad-x : 1px;\n" \
173 "-GtkButtonBox-child-min-width : 0px;\n" \
174 "border-style: none;\n" \
175 "}" \
176 ".gdauibar_entry {\n" \
177 "-GtkWidget-focus-line-width : 0px;\n" \
178 "-GtkWidget-focus-padding : 0px;\n" \
179 "padding: 1px;\n" \
180 "-GtkButtonBox-child-internal-pad-x : 1px;\n" \
181 "-GtkButtonBox-child-min-width : 0px;\n" \
182 "border-style: solid;\n" \
183 "border-radius: 5px;\n" \
184 "}"
185 css_provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ());
186 gtk_css_provider_load_from_data (GTK_CSS_PROVIDER (css_provider), CSS, -1, NULL);
187 }
188 context = gtk_widget_get_style_context (GTK_WIDGET (bar));
189 gtk_style_context_add_provider (context, css_provider, G_MAXUINT);
190 gtk_style_context_add_class (context, "gdauibar");
191 }
192
193 static void
gdaui_bar_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)194 gdaui_bar_set_property (GObject *object,
195 guint prop_id,
196 const GValue *value,
197 GParamSpec *pspec)
198 {
199 GdauiBar *bar = GDAUI_BAR (object);
200
201 switch (prop_id) {
202 case PROP_TEXT:
203 gdaui_bar_set_text (bar, g_value_get_string (value));
204 break;
205 case PROP_SHOW_ICON:
206 gdaui_bar_set_show_icon (bar, g_value_get_boolean (value));
207 break;
208 default:
209 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
210 break;
211 }
212 }
213
214 static void
gdaui_bar_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)215 gdaui_bar_get_property (GObject *object,
216 guint prop_id,
217 GValue *value,
218 GParamSpec *pspec)
219 {
220 GdauiBar *bar = GDAUI_BAR (object);
221
222 switch (prop_id) {
223 case PROP_TEXT:
224 g_value_set_string (value, gdaui_bar_get_text (bar));
225 break;
226 case PROP_SHOW_ICON:
227 g_value_set_boolean (value, gdaui_bar_get_show_icon (bar));
228 break;
229 default:
230 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
231 break;
232 }
233 }
234
235 static void
gdaui_bar_dispose(GObject * object)236 gdaui_bar_dispose (GObject *object)
237 {
238 GdauiBar *bar = (GdauiBar*) object;
239 if (bar->priv) {
240 g_free (bar->priv);
241 bar->priv = NULL;
242 }
243 G_OBJECT_CLASS (parent_class)->dispose (object);
244 }
245
246
247 static void
get_padding_and_border(GtkWidget * widget,GtkBorder * border)248 get_padding_and_border (GtkWidget *widget,
249 GtkBorder *border)
250 {
251 GtkStyleContext *context;
252 GtkStateFlags state;
253 GtkBorder tmp;
254
255 context = gtk_widget_get_style_context (widget);
256 state = gtk_widget_get_state_flags (widget);
257
258 gtk_style_context_get_padding (context, state, border);
259 gtk_style_context_get_border (context, state, &tmp);
260 border->top += tmp.top;
261 border->right += tmp.right;
262 border->bottom += tmp.bottom;
263 border->left += tmp.left;
264 }
265
266 static void
gdaui_bar_get_preferred_width(GtkWidget * widget,gint * minimum_width,gint * natural_width)267 gdaui_bar_get_preferred_width (GtkWidget *widget,
268 gint *minimum_width,
269 gint *natural_width)
270 {
271 GtkBorder border;
272
273 get_padding_and_border (widget, &border);
274
275 GTK_WIDGET_CLASS (parent_class)->get_preferred_width (widget,
276 minimum_width,
277 natural_width);
278
279 if (minimum_width)
280 *minimum_width += border.left + border.right;
281 if (natural_width)
282 *natural_width += border.left + border.right;
283 }
284
285 static void
gdaui_bar_get_preferred_height(GtkWidget * widget,gint * minimum_height,gint * natural_height)286 gdaui_bar_get_preferred_height (GtkWidget *widget,
287 gint *minimum_height,
288 gint *natural_height)
289 {
290 GtkBorder border;
291
292 get_padding_and_border (widget, &border);
293
294 GTK_WIDGET_CLASS (parent_class)->get_preferred_height (widget,
295 minimum_height,
296 natural_height);
297
298 if (minimum_height)
299 *minimum_height += border.top + border.bottom;
300 if (natural_height)
301 *natural_height += border.top + border.bottom;
302 }
303
304 static gboolean
gdaui_bar_draw(GtkWidget * widget,cairo_t * cr)305 gdaui_bar_draw (GtkWidget *widget,
306 cairo_t *cr)
307 {
308 GtkStyleContext *context;
309
310 context = gtk_widget_get_style_context (widget);
311
312 gtk_render_background (context, cr, 0, 0,
313 gtk_widget_get_allocated_width (widget),
314 gtk_widget_get_allocated_height (widget));
315 gtk_render_frame (context, cr, 0, 0,
316 gtk_widget_get_allocated_width (widget),
317 gtk_widget_get_allocated_height (widget));
318
319 GTK_WIDGET_CLASS (parent_class)->draw (widget, cr);
320
321 return FALSE;
322 }
323
324 /**
325 * gdaui_bar_new:
326 *
327 * Creates a new #GdauiBar object.
328 *
329 * Returns: a new #GdauiBar object
330 */
331 GtkWidget *
gdaui_bar_new(const gchar * text)332 gdaui_bar_new (const gchar *text)
333 {
334 return g_object_new (GDAUI_TYPE_BAR, "text", text, NULL);
335 }
336
337 /**
338 * gdaui_bar_get_text:
339 * @bar: a #GdauiBar widget.
340 *
341 * Get the text being displayed in the given gray bar widget. This
342 * does not include any embedded underlines indicating mnemonics or
343 * Pango markup.
344 *
345 * Returns: the text in the widget.
346 */
347 const gchar *
gdaui_bar_get_text(GdauiBar * bar)348 gdaui_bar_get_text (GdauiBar *bar)
349 {
350 g_return_val_if_fail (GDAUI_IS_BAR (bar), NULL);
351
352 return gtk_label_get_text (GTK_LABEL (bar->priv->label));
353 }
354
355 /**
356 * gdaui_bar_set_text
357 * @bar: a #GdauiBar widget
358 * @text: a string
359 *
360 * Set the text displayed in the given gray bar widget. This can include
361 * embedded underlines indicating mnemonics or Pango markup.
362 *
363 */
364 void
gdaui_bar_set_text(GdauiBar * bar,const gchar * text)365 gdaui_bar_set_text (GdauiBar *bar, const gchar *text)
366 {
367 g_return_if_fail (GDAUI_IS_BAR (bar));
368
369 gtk_label_set_markup (GTK_LABEL (bar->priv->label), text);
370 }
371
372 /**
373 * gdaui_set_icon_from_file
374 * @bar: a #GdauiBar widget.
375 * @file: filename.
376 *
377 * Set the icon displayed in the given gray bar widget. This can include
378 * embedded underlines indicating mnemonics or Pango markup.
379 *
380 */
381 void
gdaui_bar_set_icon_from_file(GdauiBar * bar,const gchar * file)382 gdaui_bar_set_icon_from_file (GdauiBar *bar, const gchar *file)
383 {
384 g_return_if_fail (GDAUI_IS_BAR (bar));
385
386 gtk_image_set_from_file (GTK_IMAGE (bar->priv->icon), file);
387 gdaui_bar_set_show_icon (bar, TRUE);
388 }
389
390 /**
391 * gdaui_set_icon_from_stock
392 * @bar: a #GdauiBar widget.
393 * @stock_id: a stock icon name.
394 * @size: a tock icon size.
395 *
396 * Set the icon using a stock icon for the given gray bar.
397 */
398 void
gdaui_bar_set_icon_from_stock(GdauiBar * bar,const gchar * stock_id,GtkIconSize size)399 gdaui_bar_set_icon_from_stock (GdauiBar *bar, const gchar *stock_id, GtkIconSize size)
400 {
401 g_return_if_fail (GDAUI_IS_BAR (bar));
402
403 gtk_image_set_from_stock (GTK_IMAGE (bar->priv->icon), stock_id, size);
404 gdaui_bar_set_show_icon (bar, TRUE);
405 }
406
407 /**
408 * gdaui_set_icon_from_pixbuf
409 * @bar: a #GdauiBar widget.
410 * @pixbuf: a #GdkPixbuf
411 *
412 * Set the icon using a stock icon for the given gray bar.
413 */
414 void
gdaui_bar_set_icon_from_pixbuf(GdauiBar * bar,GdkPixbuf * pixbuf)415 gdaui_bar_set_icon_from_pixbuf (GdauiBar *bar, GdkPixbuf *pixbuf)
416 {
417 g_return_if_fail (GDAUI_IS_BAR (bar));
418
419 gtk_image_set_from_pixbuf (GTK_IMAGE (bar->priv->icon), pixbuf);
420 gdaui_bar_set_show_icon (bar, TRUE);
421 }
422
423 /**
424 * gdaui_bar_set_show_icon
425 * @bar: a #GdauiBar widget.
426 * @show: whether to show the icon or not.
427 *
428 * Set the icon displaying mode for the given grid.
429 */
430 void
gdaui_bar_set_show_icon(GdauiBar * bar,gboolean show)431 gdaui_bar_set_show_icon (GdauiBar *bar, gboolean show)
432 {
433 g_return_if_fail (GDAUI_IS_BAR (bar));
434
435 if (show) {
436 gtk_widget_show (bar->priv->icon);
437 bar->priv->show_icon = TRUE;
438 } else {
439 gtk_widget_hide (bar->priv->icon);
440 bar->priv->show_icon = FALSE;
441 }
442 }
443
444 /**
445 * gdaui_bar_get_show_icon
446 * @bar: a #GdauiBar widget.
447 *
448 * Get whether the icon is being shown for the given gray bar.
449 *
450 * Returns: TRUE if the icon is shown, FALSE if not.
451 */
452 gboolean
gdaui_bar_get_show_icon(GdauiBar * bar)453 gdaui_bar_get_show_icon (GdauiBar *bar)
454 {
455 g_return_val_if_fail (GDAUI_IS_BAR (bar), FALSE);
456
457 return bar->priv->show_icon;
458 }
459
460 /**
461 * gdaui_bar_add_button_from_stock:
462 * @bar: a #GdauiBar
463 * @stock_id: the stock name of the button to add
464 *
465 * Returns: (transfer none): the created #GtkButton
466 */
467 GtkWidget *
gdaui_bar_add_button_from_stock(GdauiBar * bar,const gchar * stock_id)468 gdaui_bar_add_button_from_stock (GdauiBar *bar, const gchar *stock_id)
469 {
470 g_return_val_if_fail (GDAUI_IS_BAR (bar), NULL);
471 g_return_val_if_fail (stock_id && *stock_id, NULL);
472
473 GtkWidget *vb, *button, *img;
474
475 vb = gtk_button_box_new (GTK_ORIENTATION_VERTICAL);
476 gtk_button_box_set_layout (GTK_BUTTON_BOX (vb), GTK_BUTTONBOX_CENTER);
477 gtk_box_pack_start (GTK_BOX (bar->priv->action_area), vb, FALSE, FALSE, 0);
478
479 button = gtk_button_new ();
480 img = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_BUTTON);
481 gtk_container_add (GTK_CONTAINER (button), img);
482 gtk_box_pack_start (GTK_BOX (vb), button, FALSE, FALSE, 0);
483 g_object_set (G_OBJECT (button), "label", NULL, NULL);
484
485 /* CSS theming */
486 GtkStyleContext *context;
487 context = gtk_widget_get_style_context (vb);
488 gtk_style_context_add_provider (context, css_provider, G_MAXUINT);
489 gtk_style_context_add_class (context, "gdauibar_button");
490
491 context = gtk_widget_get_style_context (button);
492 gtk_style_context_add_provider (context, css_provider, G_MAXUINT);
493 gtk_style_context_add_class (context, "gdauibar_button");
494
495 context = gtk_widget_get_style_context (img);
496 gtk_style_context_add_provider (context, css_provider, G_MAXUINT);
497 gtk_style_context_add_class (context, "gdauibar_button");
498
499 gtk_widget_show_all (vb);
500 return button;
501 }
502
503 static void
find_icon_pressed_cb(GtkEntry * entry,G_GNUC_UNUSED GtkEntryIconPosition icon_pos,G_GNUC_UNUSED GdkEvent * event,G_GNUC_UNUSED gpointer data)504 find_icon_pressed_cb (GtkEntry *entry, G_GNUC_UNUSED GtkEntryIconPosition icon_pos,
505 G_GNUC_UNUSED GdkEvent *event, G_GNUC_UNUSED gpointer data)
506 {
507 if (icon_pos == GTK_ENTRY_ICON_SECONDARY)
508 gtk_entry_set_text (entry, "");
509 }
510
511 /**
512 * gdaui_bar_add_search_entry:
513 * @bar: a #GdauiBar
514 *
515 * Returns: (transfer none): the created #GtkEntry
516 */
517 GtkWidget *
gdaui_bar_add_search_entry(GdauiBar * bar)518 gdaui_bar_add_search_entry (GdauiBar *bar)
519 {
520 g_return_val_if_fail (GDAUI_IS_BAR (bar), NULL);
521
522 GtkWidget *vb, *entry;
523
524 vb = gtk_button_box_new (GTK_ORIENTATION_VERTICAL);
525 gtk_button_box_set_layout (GTK_BUTTON_BOX (vb), GTK_BUTTONBOX_CENTER);
526 gtk_box_pack_start (GTK_BOX (bar->priv->action_area), vb, FALSE, FALSE, 0);
527
528 entry = gtk_entry_new ();
529 gtk_box_pack_start (GTK_BOX (vb), entry, FALSE, FALSE, 0);
530
531 /* CSS theming */
532 GtkStyleContext *context;
533 context = gtk_widget_get_style_context (vb);
534 gtk_style_context_add_provider (context, css_provider, G_MAXUINT);
535 gtk_style_context_add_class (context, "gdauibar_entry");
536
537 context = gtk_widget_get_style_context (entry);
538 gtk_style_context_add_provider (context, css_provider, G_MAXUINT);
539 gtk_style_context_add_class (context, "gdauibar_entry");
540
541 gtk_entry_set_icon_from_stock (GTK_ENTRY (entry),
542 GTK_ENTRY_ICON_SECONDARY,
543 GTK_STOCK_CLEAR);
544 g_signal_connect (entry, "icon-press",
545 G_CALLBACK (find_icon_pressed_cb), NULL);
546
547 gtk_widget_show_all (vb);
548 return entry;
549 }
550