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