1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
3 /*
4 * GThumb
5 *
6 * Copyright (C) 2008 The Free Software Foundation, Inc.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "gth-empty-list.h"
23
24 /* Properties */
25 enum {
26 PROP_0,
27 PROP_TEXT
28 };
29
30 struct _GthEmptyListPrivate {
31 char *text;
32 PangoLayout *layout;
33 };
34
35
G_DEFINE_TYPE_WITH_CODE(GthEmptyList,gth_empty_list,GTK_TYPE_WIDGET,G_ADD_PRIVATE (GthEmptyList))36 G_DEFINE_TYPE_WITH_CODE (GthEmptyList,
37 gth_empty_list,
38 GTK_TYPE_WIDGET,
39 G_ADD_PRIVATE (GthEmptyList))
40
41
42 static void
43 gth_empty_list_finalize (GObject *obj)
44 {
45 g_free (GTH_EMPTY_LIST (obj)->priv->text);
46 G_OBJECT_CLASS (gth_empty_list_parent_class)->finalize (obj);
47 }
48
49
50 static void
gth_empty_list_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)51 gth_empty_list_set_property (GObject *object,
52 guint property_id,
53 const GValue *value,
54 GParamSpec *pspec)
55 {
56 GthEmptyList *self;
57
58 self = GTH_EMPTY_LIST (object);
59
60 switch (property_id) {
61 case PROP_TEXT:
62 g_free (self->priv->text);
63 self->priv->text = g_value_dup_string (value);
64 gtk_widget_queue_resize (GTK_WIDGET (self));
65 g_object_notify (object, "text");
66 break;
67
68 default:
69 break;
70 }
71 }
72
73
74 static void
gth_empty_list_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)75 gth_empty_list_get_property (GObject *object,
76 guint property_id,
77 GValue *value,
78 GParamSpec *pspec)
79 {
80 GthEmptyList *self;
81
82 self = GTH_EMPTY_LIST (object);
83
84 switch (property_id) {
85 case PROP_TEXT:
86 g_value_set_string (value, self->priv->text);
87 break;
88
89 default:
90 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
91 break;
92 }
93 }
94
95
96 static void
gth_empty_list_realize(GtkWidget * widget)97 gth_empty_list_realize (GtkWidget *widget)
98 {
99 GthEmptyList *self;
100 GtkAllocation allocation;
101 GdkWindowAttr attributes;
102 int attributes_mask;
103 GdkWindow *window;
104 GtkStyleContext *style_context;
105
106 g_return_if_fail (GTH_IS_EMPTY_LIST (widget));
107 self = (GthEmptyList*) widget;
108
109 gtk_widget_set_realized (widget, TRUE);
110
111 /**/
112
113 gtk_widget_get_allocation (widget, &allocation);
114
115 attributes.window_type = GDK_WINDOW_CHILD;
116 attributes.x = allocation.x;
117 attributes.y = allocation.y;
118 attributes.width = allocation.width;
119 attributes.height = allocation.height;
120 attributes.wclass = GDK_INPUT_OUTPUT;
121 attributes.visual = gtk_widget_get_visual (widget);
122 attributes.event_mask = (GDK_EXPOSURE_MASK
123 | GDK_SCROLL_MASK
124 | GDK_POINTER_MOTION_MASK
125 | GDK_ENTER_NOTIFY_MASK
126 | GDK_LEAVE_NOTIFY_MASK
127 | GDK_BUTTON_PRESS_MASK
128 | GDK_BUTTON_RELEASE_MASK
129 | gtk_widget_get_events (widget));
130 attributes_mask = (GDK_WA_X
131 | GDK_WA_Y
132 | GDK_WA_VISUAL);
133 window = gdk_window_new (gtk_widget_get_parent_window (widget),
134 &attributes,
135 attributes_mask);
136 gtk_widget_register_window (widget, window);
137 gtk_widget_set_window (widget, window);
138
139 /* Style */
140
141 style_context = gtk_widget_get_style_context (widget);
142 gtk_style_context_set_background (style_context, window);
143
144 /* 'No Image' message Layout */
145
146 if (self->priv->layout != NULL)
147 g_object_unref (self->priv->layout);
148
149 self->priv->layout = gtk_widget_create_pango_layout (widget, NULL);
150 pango_layout_set_wrap (self->priv->layout, PANGO_WRAP_WORD_CHAR);
151 pango_layout_set_alignment (self->priv->layout, PANGO_ALIGN_CENTER);
152 }
153
154
155 static void
gth_empty_list_unrealize(GtkWidget * widget)156 gth_empty_list_unrealize (GtkWidget *widget)
157 {
158 GthEmptyList *self;
159
160 g_return_if_fail (GTH_IS_EMPTY_LIST (widget));
161
162 self = (GthEmptyList*) widget;
163
164 if (self->priv->layout != NULL) {
165 g_object_unref (self->priv->layout);
166 self->priv->layout = NULL;
167 }
168
169 GTK_WIDGET_CLASS (gth_empty_list_parent_class)->unrealize (widget);
170 }
171
172
173 static void
gth_empty_list_map(GtkWidget * widget)174 gth_empty_list_map (GtkWidget *widget)
175 {
176 gtk_widget_set_mapped (widget, TRUE);
177 gdk_window_show (gtk_widget_get_window (widget));
178 }
179
180
181 static void
gth_empty_list_unmap(GtkWidget * widget)182 gth_empty_list_unmap (GtkWidget *widget)
183 {
184 gtk_widget_set_mapped (widget, FALSE);
185 gdk_window_hide (gtk_widget_get_window (widget));
186 }
187
188
189 static void
gth_empty_list_size_allocate(GtkWidget * widget,GtkAllocation * allocation)190 gth_empty_list_size_allocate (GtkWidget *widget,
191 GtkAllocation *allocation)
192 {
193 gtk_widget_set_allocation (widget, allocation);
194
195 if (gtk_widget_get_realized (widget))
196 gdk_window_move_resize (gtk_widget_get_window (widget),
197 allocation->x,
198 allocation->y,
199 allocation->width,
200 allocation->height);
201 }
202
203
204 static gboolean
gth_empty_list_draw(GtkWidget * widget,cairo_t * cr)205 gth_empty_list_draw (GtkWidget *widget,
206 cairo_t *cr)
207 {
208 GthEmptyList *self = (GthEmptyList*) widget;
209 GtkStyleContext *style_context;
210 GtkAllocation allocation;
211
212 if (! gtk_cairo_should_draw_window (cr, gtk_widget_get_window (widget)))
213 return FALSE;
214
215 style_context = gtk_widget_get_style_context (widget);
216
217 gtk_widget_get_allocation (widget, &allocation);
218
219 gtk_render_background (style_context, cr,
220 0,
221 0,
222 allocation.width,
223 allocation.height);
224
225 gtk_render_frame (style_context, cr,
226 0,
227 0,
228 allocation.width,
229 allocation.height);
230
231 if (self->priv->text != NULL) {
232 PangoRectangle bounds;
233 GdkRGBA color;
234 PangoFontDescription *font;
235
236 pango_layout_set_width (self->priv->layout, allocation.width * PANGO_SCALE);
237 pango_layout_set_text (self->priv->layout, self->priv->text, strlen (self->priv->text));
238 pango_layout_get_pixel_extents (self->priv->layout, NULL, &bounds);
239 gtk_style_context_get (style_context, gtk_widget_get_state_flags (widget), "font", &font, NULL);
240 pango_layout_set_font_description (self->priv->layout, font);
241 gtk_style_context_get_color (style_context, gtk_widget_get_state_flags (widget), &color);
242 gdk_cairo_set_source_rgba (cr, &color);
243 gtk_render_layout (style_context, cr, 0, (allocation.height - bounds.height) / 2, self->priv->layout);
244 cairo_fill (cr);
245
246 pango_font_description_free (font);
247 }
248
249 return FALSE;
250 }
251
252
253 static void
gth_empty_list_class_init(GthEmptyListClass * klass)254 gth_empty_list_class_init (GthEmptyListClass *klass)
255 {
256 GObjectClass *object_class;
257 GtkWidgetClass *widget_class;
258
259 object_class = (GObjectClass*) (klass);
260 object_class->set_property = gth_empty_list_set_property;
261 object_class->get_property = gth_empty_list_get_property;
262 object_class->finalize = gth_empty_list_finalize;
263
264 widget_class = (GtkWidgetClass*) klass;
265 widget_class->realize = gth_empty_list_realize;
266 widget_class->unrealize = gth_empty_list_unrealize;
267 widget_class->map = gth_empty_list_map;
268 widget_class->unmap = gth_empty_list_unmap;
269 widget_class->size_allocate = gth_empty_list_size_allocate;
270 widget_class->draw = gth_empty_list_draw;
271
272 /* properties */
273
274 g_object_class_install_property (object_class,
275 PROP_TEXT,
276 g_param_spec_string ("text",
277 "Text",
278 "The text to display",
279 NULL,
280 G_PARAM_READABLE | G_PARAM_WRITABLE));
281 }
282
283
284 static void
gth_empty_list_init(GthEmptyList * self)285 gth_empty_list_init (GthEmptyList *self)
286 {
287 GtkStyleContext *style_context;
288
289 gtk_widget_set_has_window (GTK_WIDGET (self), TRUE);
290 gtk_widget_set_can_focus (GTK_WIDGET (self), FALSE);
291
292 self->priv = gth_empty_list_get_instance_private (self);
293 self->priv->layout = NULL;
294 self->priv->text = NULL;
295
296 style_context = gtk_widget_get_style_context (GTK_WIDGET (self));
297 gtk_style_context_add_class (style_context, GTK_STYLE_CLASS_VIEW);
298 gtk_style_context_add_class (style_context, GTK_STYLE_CLASS_FRAME);
299 }
300
301
302 GtkWidget *
gth_empty_list_new(const char * text)303 gth_empty_list_new (const char *text)
304 {
305 return g_object_new (GTH_TYPE_EMPTY_LIST, "text", text, NULL);
306 }
307
308
309 void
gth_empty_list_set_text(GthEmptyList * self,const char * text)310 gth_empty_list_set_text (GthEmptyList *self,
311 const char *text)
312 {
313 g_object_set (self, "text", text, NULL);
314 }
315