]> Pileus Git - ~andy/gtk/blob - gtk/gtkimagemenuitem.c
228e8c111cb0e3fdb1e8534c360f9ce5d5e45f44
[~andy/gtk] / gtk / gtkimagemenuitem.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 2001 Red Hat, Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library 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 GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include "gtkimagemenuitem.h"
28 #include "gtkaccellabel.h"
29 #include "gtksignal.h"
30 #include "gtkintl.h"
31
32 static void gtk_image_menu_item_class_init           (GtkImageMenuItemClass *klass);
33 static void gtk_image_menu_item_init                 (GtkImageMenuItem      *image_menu_item);
34 static void gtk_image_menu_item_size_request         (GtkWidget        *widget,
35                                                       GtkRequisition   *requisition);
36 static void gtk_image_menu_item_size_allocate        (GtkWidget        *widget,
37                                                       GtkAllocation    *allocation);
38 static void gtk_image_menu_item_remove               (GtkContainer          *container,
39                                                       GtkWidget             *child);
40 static void gtk_image_menu_item_toggle_size_request  (GtkMenuItem           *menu_item,
41                                                       gint                  *requisition);
42
43 static void gtk_image_menu_item_map        (GtkWidget      *widget);
44 static void gtk_image_menu_item_unmap      (GtkWidget      *widget);
45 static void gtk_image_menu_item_forall     (GtkContainer   *container,
46                                             gboolean        include_internals,
47                                             GtkCallback     callback,
48                                             gpointer        callback_data);
49
50 static void gtk_image_menu_item_set_property (GObject         *object,
51                                               guint            prop_id,
52                                               const GValue    *value,
53                                               GParamSpec      *pspec);
54 static void gtk_image_menu_item_get_property (GObject         *object,
55                                               guint            prop_id,
56                                               GValue          *value,
57                                               GParamSpec      *pspec);
58
59
60 enum {
61   PROP_ZERO,
62   PROP_IMAGE
63 };
64
65 static GtkMenuItemClass *parent_class = NULL;
66
67 GtkType
68 gtk_image_menu_item_get_type (void)
69 {
70   static GtkType image_menu_item_type = 0;
71
72   if (!image_menu_item_type)
73     {
74       static const GtkTypeInfo image_menu_item_info =
75       {
76         "GtkImageMenuItem",
77         sizeof (GtkImageMenuItem),
78         sizeof (GtkImageMenuItemClass),
79         (GtkClassInitFunc) gtk_image_menu_item_class_init,
80         (GtkObjectInitFunc) gtk_image_menu_item_init,
81         /* reserved_1 */ NULL,
82         /* reserved_2 */ NULL,
83         (GtkClassInitFunc) NULL,
84       };
85
86       image_menu_item_type = gtk_type_unique (GTK_TYPE_MENU_ITEM, &image_menu_item_info);
87     }
88
89   return image_menu_item_type;
90 }
91
92 static void
93 gtk_image_menu_item_class_init (GtkImageMenuItemClass *klass)
94 {
95   GObjectClass *gobject_class;
96   GtkObjectClass *object_class;
97   GtkWidgetClass *widget_class;
98   GtkMenuItemClass *menu_item_class;
99   GtkContainerClass *container_class;
100
101   gobject_class = (GObjectClass*) klass;
102   object_class = (GtkObjectClass*) klass;
103   widget_class = (GtkWidgetClass*) klass;
104   menu_item_class = (GtkMenuItemClass*) klass;
105   container_class = (GtkContainerClass*) klass;
106   
107   parent_class = gtk_type_class (GTK_TYPE_MENU_ITEM);
108   
109   widget_class->size_request = gtk_image_menu_item_size_request;
110   widget_class->size_allocate = gtk_image_menu_item_size_allocate;
111   widget_class->map = gtk_image_menu_item_map;
112   widget_class->unmap = gtk_image_menu_item_unmap;
113
114   container_class->forall = gtk_image_menu_item_forall;
115   container_class->remove = gtk_image_menu_item_remove;
116   
117   menu_item_class->toggle_size_request = gtk_image_menu_item_toggle_size_request;
118
119   gobject_class->set_property = gtk_image_menu_item_set_property;
120   gobject_class->get_property = gtk_image_menu_item_get_property;
121   
122   g_object_class_install_property (gobject_class,
123                                    PROP_IMAGE,
124                                    g_param_spec_object ("image",
125                                                         _("Image widget"),
126                                                         _("Child widget to appear next to the menu text"),
127                                                         GTK_TYPE_WIDGET,
128                                                         G_PARAM_READABLE | G_PARAM_WRITABLE));
129 }
130
131 static void
132 gtk_image_menu_item_init (GtkImageMenuItem *image_menu_item)
133 {
134   image_menu_item->image = NULL;
135 }
136
137 static void
138 gtk_image_menu_item_set_property (GObject         *object,
139                                   guint            prop_id,
140                                   const GValue    *value,
141                                   GParamSpec      *pspec)
142 {
143   GtkImageMenuItem *image_menu_item = GTK_IMAGE_MENU_ITEM (object);
144   
145   switch (prop_id)
146     {
147     case PROP_IMAGE:
148       {
149         GtkWidget *child;
150
151         child = (GtkWidget*) g_value_get_object (value);
152
153         if (child != image_menu_item->image)
154           {
155             if (image_menu_item->image)
156               gtk_container_remove (GTK_CONTAINER (image_menu_item),
157                                     image_menu_item->image);
158             
159             if (child)
160               {
161                 gtk_image_menu_item_add_image (image_menu_item,
162                                                child);
163               }
164           }
165       }
166       break;
167     default:
168       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
169       break;
170     }
171 }
172 static void
173 gtk_image_menu_item_get_property (GObject         *object,
174                                   guint            prop_id,
175                                   GValue          *value,
176                                   GParamSpec      *pspec)
177 {
178   GtkImageMenuItem *image_menu_item = GTK_IMAGE_MENU_ITEM (object);
179   
180   switch (prop_id)
181     {
182     case PROP_IMAGE:
183       g_value_set_object (value,
184                           (GObject*) image_menu_item->image);
185       break;
186     default:
187       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
188       break;
189     }
190 }
191
192
193 static void
194 gtk_image_menu_item_toggle_size_request (GtkMenuItem *menu_item,
195                                          gint        *requisition)
196 {
197   GtkImageMenuItem *image_menu_item;
198   
199   g_return_if_fail (menu_item != NULL);
200   g_return_if_fail (GTK_IS_IMAGE_MENU_ITEM (menu_item));
201
202   image_menu_item = GTK_IMAGE_MENU_ITEM (menu_item);
203
204   if (image_menu_item->image)
205     *requisition = image_menu_item->image->requisition.width;
206   else
207     *requisition = 0;
208 }
209
210
211 static void
212 gtk_image_menu_item_size_request (GtkWidget      *widget,
213                                   GtkRequisition *requisition)
214 {
215   GtkImageMenuItem *image_menu_item;
216   gint child_height = 0;
217   
218   image_menu_item = GTK_IMAGE_MENU_ITEM (widget);
219   
220   if (image_menu_item->image && GTK_WIDGET_VISIBLE (image_menu_item->image))
221     {
222       GtkRequisition child_requisition;
223       
224       gtk_widget_size_request (image_menu_item->image,
225                                &child_requisition);
226
227       child_height = child_requisition.height;
228     }
229   
230   (* GTK_WIDGET_CLASS (parent_class)->size_request) (widget, requisition);
231
232   /* not done with height since that happens via the
233    * toggle_size_request
234    */
235   requisition->height = MAX (requisition->height, child_height);
236   
237   /* Note that GtkMenuShell always size requests before
238    * toggle_size_request, so toggle_size_request will be able to use
239    * image_menu_item->image->requisition
240    */
241 }
242
243 static void
244 gtk_image_menu_item_size_allocate (GtkWidget     *widget,
245                                    GtkAllocation *allocation)
246 {
247   GtkImageMenuItem *image_menu_item;
248   
249   image_menu_item = GTK_IMAGE_MENU_ITEM (widget);  
250   
251   (* GTK_WIDGET_CLASS (parent_class)->size_allocate) (widget, allocation);
252
253   if (image_menu_item->image)
254     {
255       gint width, height, x, y;
256       GtkAllocation child_allocation;
257       
258       /* Man this is lame hardcoding action, but I can't
259        * come up with a solution that's really better.
260        */
261       
262       width = image_menu_item->image->requisition.width;
263       height = image_menu_item->image->requisition.height;
264
265       x = (GTK_CONTAINER (image_menu_item)->border_width +
266            widget->style->xthickness) +
267         (GTK_MENU_ITEM (image_menu_item)->toggle_size - width) / 2;
268       y = (widget->allocation.height - height) / 2;
269
270       child_allocation.width = width;
271       child_allocation.height = height;
272       child_allocation.x = MAX (x, 0);
273       child_allocation.y = MAX (y, 0);
274
275       gtk_widget_size_allocate (image_menu_item->image, &child_allocation);
276     }
277 }
278
279 static void
280 gtk_image_menu_item_map (GtkWidget *widget)
281 {
282   GtkImageMenuItem *image_menu_item;
283
284   g_return_if_fail (GTK_IS_IMAGE_MENU_ITEM (widget));
285
286   image_menu_item = GTK_IMAGE_MENU_ITEM (widget);
287   
288   (* GTK_WIDGET_CLASS (parent_class)->map) (widget);
289
290   if (image_menu_item->image &&
291       GTK_WIDGET_VISIBLE (image_menu_item->image) &&
292       !GTK_WIDGET_MAPPED (image_menu_item->image))
293     gtk_widget_map (image_menu_item->image);
294
295   if (!GTK_WIDGET_NO_WINDOW (widget))
296     gdk_window_show (widget->window);  
297 }
298
299 static void
300 gtk_image_menu_item_unmap (GtkWidget *widget)
301 {
302   GtkImageMenuItem *image_menu_item;
303
304   g_return_if_fail (GTK_IS_IMAGE_MENU_ITEM (widget));
305
306   image_menu_item = GTK_IMAGE_MENU_ITEM (widget);
307   
308   (* GTK_WIDGET_CLASS (parent_class)->unmap) (widget);
309   
310   if (!GTK_WIDGET_NO_WINDOW (widget))
311     gdk_window_hide (widget->window);
312   
313   if (image_menu_item->image && GTK_WIDGET_MAPPED (image_menu_item->image))
314     gtk_widget_unmap (image_menu_item->image);  
315 }
316
317 static void
318 gtk_image_menu_item_forall (GtkContainer   *container,
319                             gboolean        include_internals,
320                             GtkCallback     callback,
321                             gpointer        callback_data)
322 {
323   GtkImageMenuItem *image_menu_item;
324
325   g_return_if_fail (GTK_IS_IMAGE_MENU_ITEM (container));
326
327   image_menu_item = GTK_IMAGE_MENU_ITEM (container);
328   
329   (* GTK_CONTAINER_CLASS (parent_class)->forall) (container,
330                                                   include_internals,
331                                                   callback,
332                                                   callback_data);
333
334   if (image_menu_item->image)
335     (* callback) (image_menu_item->image, callback_data);
336 }
337
338 GtkWidget*
339 gtk_image_menu_item_new (GtkWidget   *widget,
340                          const gchar *label)
341 {
342   GtkImageMenuItem *image_menu_item;
343   GtkWidget *accel_label;
344   
345   image_menu_item = GTK_IMAGE_MENU_ITEM (g_object_new (GTK_TYPE_IMAGE_MENU_ITEM,
346                                                        NULL));
347
348   accel_label = gtk_accel_label_new (label);
349   gtk_misc_set_alignment (GTK_MISC (accel_label), 0.0, 0.5);
350
351   gtk_container_add (GTK_CONTAINER (image_menu_item), accel_label);
352   gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (accel_label),
353                                     GTK_WIDGET (image_menu_item));
354   gtk_widget_show (accel_label);
355
356   if (widget)
357     gtk_image_menu_item_add_image (image_menu_item, widget);
358   
359   return GTK_WIDGET(image_menu_item);
360 }
361
362 void
363 gtk_image_menu_item_add_image (GtkImageMenuItem *image_menu_item,
364                                GtkWidget        *child)
365 {
366   g_return_if_fail (GTK_IS_IMAGE_MENU_ITEM (image_menu_item));
367   g_return_if_fail (image_menu_item->image == NULL);
368   
369   gtk_widget_set_parent (child, GTK_WIDGET (image_menu_item));
370   image_menu_item->image = child;
371
372   g_object_notify (G_OBJECT (image_menu_item), "image");
373   
374   if (GTK_WIDGET_REALIZED (child->parent))
375     gtk_widget_realize (child);
376   
377   if (GTK_WIDGET_VISIBLE (child->parent) && GTK_WIDGET_VISIBLE (child))
378     {
379       if (GTK_WIDGET_MAPPED (child->parent))
380         gtk_widget_map (child);
381
382       gtk_widget_queue_resize (child);
383     }
384 }
385
386 GtkWidget*
387 gtk_image_menu_item_get_image (GtkImageMenuItem *image_menu_item)
388 {
389   g_return_val_if_fail (GTK_IS_IMAGE_MENU_ITEM (image_menu_item), NULL);
390
391   return image_menu_item->image;
392 }
393
394 static void
395 gtk_image_menu_item_remove (GtkContainer *container,
396                             GtkWidget    *child)
397 {
398   GtkImageMenuItem *image_menu_item;
399
400   image_menu_item = GTK_IMAGE_MENU_ITEM (container);
401
402   if (child == image_menu_item->image)
403     {
404       gboolean widget_was_visible;
405       
406       widget_was_visible = GTK_WIDGET_VISIBLE (child);
407       
408       gtk_widget_unparent (child);
409       image_menu_item->image = NULL;
410       
411       if (GTK_WIDGET_VISIBLE (container) && widget_was_visible)
412         gtk_widget_queue_resize (GTK_WIDGET (container));
413
414       g_object_notify (G_OBJECT (image_menu_item), "image");
415     }
416   else
417     {
418       (* GTK_CONTAINER_CLASS (parent_class)->remove) (container, child);
419     }
420 }
421
422