Code

Extensions. XAML export improvements.
[inkscape.git] / src / libgdl / gdl-dock-tablabel.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  *
3  * gdl-dock-tablabel.c
4  *
5  * This file is part of the GNOME Devtools Libraries.
6  *
7  * Copyright (C) 2002 Gustavo Giráldez <gustavo.giraldez@gmx.net>
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
22  */
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
28 #include "gdl-i18n.h"
29 #include <gtk/gtk.h>
31 #include "gdl-dock-tablabel.h"
32 #include "gdl-tools.h"
33 #include "gdl-dock-item.h"
34 #include "libgdlmarshal.h"
37 /* ----- Private prototypes ----- */
39 static void  gdl_dock_tablabel_class_init    (GdlDockTablabelClass *klass);
40 static void  gdl_dock_tablabel_instance_init (GdlDockTablabel      *tablabel);
42 static void  gdl_dock_tablabel_set_property  (GObject              *object,
43                                               guint                 prop_id,
44                                               const GValue         *value,
45                                               GParamSpec           *pspec);
46 static void  gdl_dock_tablabel_get_property  (GObject              *object,
47                                               guint                 prop_id,
48                                               GValue               *value,
49                                               GParamSpec           *pspec);
51 static void  gdl_dock_tablabel_item_notify   (GObject            *master,
52                                               GParamSpec         *pspec,
53                                               gpointer            data);
55 static void  gdl_dock_tablabel_size_request  (GtkWidget          *widget,
56                                               GtkRequisition     *requisition);
57 static void  gdl_dock_tablabel_size_allocate (GtkWidget          *widget,
58                                               GtkAllocation      *allocation);
59                                               
60 static void  gdl_dock_tablabel_paint         (GtkWidget      *widget,
61                                               GdkEventExpose *event);
62 static gint  gdl_dock_tablabel_expose        (GtkWidget      *widget,
63                                               GdkEventExpose *event);
65 static gboolean gdl_dock_tablabel_button_event  (GtkWidget      *widget,
66                                                  GdkEventButton *event);
67 static gboolean gdl_dock_tablabel_motion_event  (GtkWidget      *widget,
68                                                  GdkEventMotion *event);
70 static void  gdl_dock_tablabel_realize (GtkWidget *widget);
71 static void  gdl_dock_tablabel_unrealize (GtkWidget *widget);
72 static void  gdl_dock_tablabel_map (GtkWidget *widget);
73 static void  gdl_dock_tablabel_unmap (GtkWidget *widget);
75 /* ----- Private data types and variables ----- */
77 #define DEFAULT_DRAG_HANDLE_SIZE 10
78 #define HANDLE_RATIO 1.0
80 enum {
81     BUTTON_PRESSED_HANDLE,
82     LAST_SIGNAL
83 };
85 enum {
86     PROP_0,
87     PROP_ITEM
88 };
91 static guint dock_tablabel_signals [LAST_SIGNAL] = { 0 };
94 /* ----- Private interface ----- */
96 GDL_CLASS_BOILERPLATE (GdlDockTablabel, gdl_dock_tablabel,
97                        GtkBin, GTK_TYPE_BIN);
99 static void
100 gdl_dock_tablabel_class_init (GdlDockTablabelClass *klass)
102     GObjectClass      *g_object_class;
103     GtkObjectClass    *object_class;
104     GtkWidgetClass    *widget_class;
105     GtkContainerClass *container_class;
107     g_object_class = G_OBJECT_CLASS (klass);
108     object_class = GTK_OBJECT_CLASS (klass);
109     widget_class = GTK_WIDGET_CLASS (klass);
110     container_class = GTK_CONTAINER_CLASS (klass);
111     
112     g_object_class->set_property = gdl_dock_tablabel_set_property;
113     g_object_class->get_property = gdl_dock_tablabel_get_property;
115     widget_class->size_request = gdl_dock_tablabel_size_request;
116     widget_class->size_allocate = gdl_dock_tablabel_size_allocate;
117     widget_class->expose_event = gdl_dock_tablabel_expose;
118     widget_class->button_press_event = gdl_dock_tablabel_button_event;
119     widget_class->button_release_event = gdl_dock_tablabel_button_event;
120     widget_class->motion_notify_event = gdl_dock_tablabel_motion_event;
121     widget_class->realize = gdl_dock_tablabel_realize;
122     widget_class->unrealize = gdl_dock_tablabel_unrealize;
123     widget_class->map = gdl_dock_tablabel_map;
124     widget_class->unmap = gdl_dock_tablabel_unmap;
126     g_object_class_install_property (
127         g_object_class, PROP_ITEM,
128         g_param_spec_object ("item", _("Controlling dock item"),
129                              _("Dockitem which 'owns' this tablabel"),
130                              GDL_TYPE_DOCK_ITEM,
131                              G_PARAM_READWRITE));
133     dock_tablabel_signals [BUTTON_PRESSED_HANDLE] =
134         g_signal_new ("button_pressed_handle",
135                       G_TYPE_FROM_CLASS (klass),
136                       G_SIGNAL_RUN_LAST,
137                       G_STRUCT_OFFSET (GdlDockTablabelClass, 
138                                        button_pressed_handle),
139                       NULL, NULL,
140                       gdl_marshal_VOID__BOXED,
141                       G_TYPE_NONE,
142                       1,
143                       GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
145     klass->button_pressed_handle = NULL;
148 static void
149 gdl_dock_tablabel_instance_init (GdlDockTablabel *tablabel)
151     GtkWidget *widget;
152     GtkWidget *label_widget;
154     widget = GTK_WIDGET (tablabel);
156     tablabel->drag_handle_size = DEFAULT_DRAG_HANDLE_SIZE;
157     tablabel->item = NULL;
159     label_widget = gtk_label_new ("Dock item");
160     gtk_container_add (GTK_CONTAINER (tablabel), label_widget);
161     gtk_widget_show (label_widget);
163     tablabel->active = FALSE;
164     gtk_widget_set_state (GTK_WIDGET (tablabel), GTK_STATE_ACTIVE);
167 static void
168 gdl_dock_tablabel_set_property (GObject      *object,
169                                 guint         prop_id,
170                                 const GValue *value,
171                                 GParamSpec   *pspec)
173     GdlDockTablabel *tablabel;
174     GtkBin          *bin;
176     tablabel = GDL_DOCK_TABLABEL (object);
178     switch (prop_id) {
179         case PROP_ITEM:
180             if (tablabel->item) {
181                 g_object_remove_weak_pointer (G_OBJECT (tablabel->item), 
182                                               (gpointer *) &tablabel->item);
183                 g_signal_handlers_disconnect_by_func (
184                     tablabel->item, gdl_dock_tablabel_item_notify, tablabel);
185             };
187             tablabel->item = g_value_get_object (value);
188             if (tablabel->item) {
189                 gboolean locked;
190                 gchar   *long_name;
191                 
192                 g_object_add_weak_pointer (G_OBJECT (tablabel->item), 
193                                            (gpointer *) &tablabel->item);
195                 g_signal_connect (tablabel->item, "notify::locked",
196                                   G_CALLBACK (gdl_dock_tablabel_item_notify),
197                                   tablabel);
198                 g_signal_connect (tablabel->item, "notify::long_name",
199                                   G_CALLBACK (gdl_dock_tablabel_item_notify),
200                                   tablabel);
201                 g_signal_connect (tablabel->item, "notify::grip_size",
202                                   G_CALLBACK (gdl_dock_tablabel_item_notify),
203                                   tablabel);
205                 g_object_get (tablabel->item,
206                               "locked", &locked,
207                               "long-name", &long_name,
208                               "grip-size", &tablabel->drag_handle_size,
209                               NULL);
211                 if (locked)
212                     tablabel->drag_handle_size = 0;
213                 
214                 bin = GTK_BIN (tablabel);
215                 if (bin->child && g_object_class_find_property (
216                     G_OBJECT_GET_CLASS (bin->child), "label"))
217                     g_object_set (bin->child, "label", long_name, NULL);
218                 g_free (long_name);
219             };
220             break;
221             
222         default:
223             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
224             break;
225     }
228 static void
229 gdl_dock_tablabel_get_property (GObject    *object,
230                                 guint       prop_id,
231                                 GValue     *value,
232                                 GParamSpec *pspec)
234     GdlDockTablabel *tablabel;
236     tablabel = GDL_DOCK_TABLABEL (object);
238     switch (prop_id) {
239         case PROP_ITEM:
240             g_value_set_object (value, tablabel->item);
241             break;
242         default:
243             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
244             break;
245     }
248 static void
249 gdl_dock_tablabel_item_notify (GObject    *master,
250                                GParamSpec *pspec,
251                                gpointer    data)
253     GdlDockTablabel *tablabel = GDL_DOCK_TABLABEL (data);
254     gboolean         locked;
255     gchar           *label;
256     GtkBin          *bin;
257     
258     g_object_get (master,
259                   "locked", &locked,
260                   "grip-size", &tablabel->drag_handle_size,
261                   "long-name", &label,
262                   NULL);
264     if (locked)
265         tablabel->drag_handle_size = 0;
267     bin = GTK_BIN (tablabel);
268     if (bin->child && g_object_class_find_property (
269         G_OBJECT_GET_CLASS (bin->child), "label"))
270         g_object_set (bin->child, "label", label, NULL);
271     g_free (label);
273     gtk_widget_queue_resize (GTK_WIDGET (tablabel));
276 static void
277 gdl_dock_tablabel_size_request (GtkWidget      *widget,
278                                 GtkRequisition *requisition)
280     GtkBin          *bin;
281     GtkRequisition   child_req;
282     GdlDockTablabel *tablabel;
284     g_return_if_fail (widget != NULL);
285     g_return_if_fail (GDL_IS_DOCK_TABLABEL (widget));
286     g_return_if_fail (requisition != NULL);
288     tablabel = GDL_DOCK_TABLABEL (widget);
289     bin = GTK_BIN (widget);
291     requisition->width = tablabel->drag_handle_size;
292     requisition->height = 0;
294     if (bin->child)
295         gtk_widget_size_request (bin->child, &child_req);
296     else
297         child_req.width = child_req.height = 0;
298         
299     requisition->width += child_req.width;
300     requisition->height += child_req.height;
302     requisition->width += GTK_CONTAINER (widget)->border_width * 2;
303     requisition->height += GTK_CONTAINER (widget)->border_width * 2;
305     widget->requisition = *requisition;
308 static void
309 gdl_dock_tablabel_size_allocate (GtkWidget     *widget,
310                                  GtkAllocation *allocation)
312     GtkBin          *bin;
313     GdlDockTablabel *tablabel;
314     gint             border_width;
316     g_return_if_fail (widget != NULL);
317     g_return_if_fail (GDL_IS_DOCK_TABLABEL (widget));
318     g_return_if_fail (allocation != NULL);
319   
320     bin = GTK_BIN (widget);
321     tablabel = GDL_DOCK_TABLABEL (widget);
323     border_width = GTK_CONTAINER (widget)->border_width;
324   
325     widget->allocation = *allocation;
327     if (GTK_WIDGET_REALIZED (widget))
328         gdk_window_move_resize (tablabel->event_window, 
329                                 allocation->x, 
330                                 allocation->y,
331                                 allocation->width, 
332                                 allocation->height);
334     if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) {
335         GtkAllocation  child_allocation;
337         child_allocation.x = widget->allocation.x + border_width;
338         child_allocation.y = widget->allocation.y + border_width;
340         allocation->width = MAX (1, (int) allocation->width - 
341                                  (int) tablabel->drag_handle_size);
342         child_allocation.x += tablabel->drag_handle_size;
344         child_allocation.width = 
345             MAX (1, (int) allocation->width - 2 * border_width);
346         child_allocation.height = 
347             MAX (1, (int) allocation->height - 2 * border_width);
349         gtk_widget_size_allocate (bin->child, &child_allocation);
350     }
353 static void
354 gdl_dock_tablabel_paint (GtkWidget      *widget,
355                          GdkEventExpose *event)
357     GdkRectangle     dest, rect;
358     GtkBin          *bin;
359     GdlDockTablabel *tablabel;
360     gint             border_width;
362     bin = GTK_BIN (widget);
363     tablabel = GDL_DOCK_TABLABEL (widget);
364     border_width = GTK_CONTAINER (widget)->border_width;
366     rect.x = widget->allocation.x + border_width;
367     rect.y = widget->allocation.y + border_width;
368     rect.width = tablabel->drag_handle_size * HANDLE_RATIO;
369     rect.height = widget->allocation.height - 2*border_width;
371     if (gdk_rectangle_intersect (&event->area, &rect, &dest)) {
372         gtk_paint_handle (widget->style, widget->window, 
373                           tablabel->active ? GTK_STATE_NORMAL : GTK_STATE_ACTIVE, 
374                           GTK_SHADOW_NONE,
375                           &dest, widget, "dock-tablabel",
376                           rect.x, rect.y, rect.width, rect.height,
377                           GTK_ORIENTATION_VERTICAL);
378     };
381 static gint
382 gdl_dock_tablabel_expose (GtkWidget      *widget,
383                           GdkEventExpose *event)
385     g_return_val_if_fail (widget != NULL, FALSE);
386     g_return_val_if_fail (GDL_IS_DOCK_TABLABEL (widget), FALSE);
387     g_return_val_if_fail (event != NULL, FALSE);
389     if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget)) {
390         GDL_CALL_PARENT_GBOOLEAN(GTK_WIDGET_CLASS, expose_event, (widget,event));
391         gdl_dock_tablabel_paint (widget, event);
392     };
393   
394     return FALSE;
397 static gboolean 
398 gdl_dock_tablabel_button_event (GtkWidget      *widget,
399                                 GdkEventButton *event)
401     GdlDockTablabel *tablabel;
402     gboolean         event_handled;
403   
404     g_return_val_if_fail (widget != NULL, FALSE);
405     g_return_val_if_fail (GDL_IS_DOCK_TABLABEL (widget), FALSE);
406     g_return_val_if_fail (event != NULL, FALSE);
407     
408     tablabel = GDL_DOCK_TABLABEL (widget);
409     
410     event_handled = FALSE;
412     if (event->window != tablabel->event_window)
413         return FALSE;
414     
415     switch (event->type) {
416         case GDK_BUTTON_PRESS:
417             if (tablabel->active) {
418                 gboolean in_handle;
419                 gint     rel_x, rel_y;
420                 guint    border_width;
421                 GtkBin  *bin;
423                 bin = GTK_BIN (widget);
424                 border_width = GTK_CONTAINER (widget)->border_width;
426                 rel_x = event->x - border_width;
427                 rel_y = event->y - border_width;
429                 /* Check if user clicked on the drag handle. */      
430                 in_handle = (rel_x < tablabel->drag_handle_size * HANDLE_RATIO) &&
431                     (rel_x > 0);
433                 if (event->button == 1) {
434                     tablabel->pre_drag = TRUE;
435                     tablabel->drag_start_event = *event;
436                 }
437                 else {
438                     g_signal_emit (widget, 
439                                    dock_tablabel_signals [BUTTON_PRESSED_HANDLE],
440                                    0,
441                                    event);
442                 }
443                 
444                 event_handled = TRUE;
445             }
446             break;
448         case GDK_BUTTON_RELEASE:
449             tablabel->pre_drag = FALSE;
450             break;
452         default:
453             break;
454     }
455     
456     if (!event_handled) {
457         /* propagate the event to the parent's gdkwindow */
458         GdkEventButton e;
460         e = *event;
461         e.window = gtk_widget_get_parent_window (widget);
462         e.x += widget->allocation.x;
463         e.y += widget->allocation.y;
464         
465         gdk_event_put ((GdkEvent *) &e);
466     };
468     return event_handled;
471 static gboolean 
472 gdl_dock_tablabel_motion_event (GtkWidget      *widget,
473                                 GdkEventMotion *event)
475     GdlDockTablabel *tablabel;
476     gboolean         event_handled;
477   
478     g_return_val_if_fail (widget != NULL, FALSE);
479     g_return_val_if_fail (GDL_IS_DOCK_TABLABEL (widget), FALSE);
480     g_return_val_if_fail (event != NULL, FALSE);
481     
482     tablabel = GDL_DOCK_TABLABEL (widget);
483     
484     event_handled = FALSE;
486     if (event->window != tablabel->event_window)
487         return FALSE;
488     
489     if (tablabel->pre_drag) {
490         if (gtk_drag_check_threshold (widget,
491                                       tablabel->drag_start_event.x,
492                                       tablabel->drag_start_event.y,
493                                       event->x,
494                                       event->y)) {
495             tablabel->pre_drag = FALSE;
496             g_signal_emit (widget, 
497                            dock_tablabel_signals [BUTTON_PRESSED_HANDLE],
498                            0,
499                            &tablabel->drag_start_event);
500             event_handled = TRUE;
501         }
502     }
503     
504     if (!event_handled) {
505         /* propagate the event to the parent's gdkwindow */
506         GdkEventMotion e;
508         e = *event;
509         e.window = gtk_widget_get_parent_window (widget);
510         e.x += widget->allocation.x;
511         e.y += widget->allocation.y;
512         
513         gdk_event_put ((GdkEvent *) &e);
514     };
516     return event_handled;
519 static void   
520 gdl_dock_tablabel_realize (GtkWidget *widget)
522     GdlDockTablabel *tablabel;
523     GdkWindowAttr attributes;
524     int attributes_mask;
525     
526     tablabel = GDL_DOCK_TABLABEL (widget);
527     
528     attributes.window_type = GDK_WINDOW_CHILD;
529     attributes.x = widget->allocation.x;
530     attributes.y = widget->allocation.y;
531     attributes.width = widget->allocation.width;
532     attributes.height = widget->allocation.height;
533     attributes.wclass = GDK_INPUT_ONLY;
534     attributes.event_mask = gtk_widget_get_events (widget);
535     attributes.event_mask |= (GDK_EXPOSURE_MASK | 
536                               GDK_BUTTON_PRESS_MASK |
537                               GDK_BUTTON_RELEASE_MASK | 
538                               GDK_ENTER_NOTIFY_MASK | 
539                               GDK_POINTER_MOTION_MASK | 
540                               GDK_LEAVE_NOTIFY_MASK);
541     attributes_mask = GDK_WA_X | GDK_WA_Y;
542     
543     widget->window = gtk_widget_get_parent_window (widget);
544     g_object_ref (widget->window);
545     
546     tablabel->event_window = 
547         gdk_window_new (gtk_widget_get_parent_window (widget),
548                         &attributes, attributes_mask);
549     gdk_window_set_user_data (tablabel->event_window, widget);
550     
551     widget->style = gtk_style_attach (widget->style, widget->window);
552     
553     GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
556 static void   
557 gdl_dock_tablabel_unrealize (GtkWidget *widget)
559     GdlDockTablabel *tablabel = GDL_DOCK_TABLABEL (widget);
560     
561     if (tablabel->event_window) {
562         gdk_window_set_user_data (tablabel->event_window, NULL);
563         gdk_window_destroy (tablabel->event_window);
564         tablabel->event_window = NULL;
565     }
566     
567     GDL_CALL_PARENT (GTK_WIDGET_CLASS, unrealize, (widget));
570 static void  
571 gdl_dock_tablabel_map (GtkWidget *widget)
573     GdlDockTablabel *tablabel = GDL_DOCK_TABLABEL (widget);
574     
575     GDL_CALL_PARENT (GTK_WIDGET_CLASS, map, (widget));
576     
577     gdk_window_show (tablabel->event_window);
580 static void   
581 gdl_dock_tablabel_unmap (GtkWidget *widget)
583     GdlDockTablabel *tablabel = GDL_DOCK_TABLABEL (widget);
585     gdk_window_hide (tablabel->event_window);
587     GDL_CALL_PARENT (GTK_WIDGET_CLASS, unmap, (widget));
590 /* ----- Public interface ----- */
592 GtkWidget *
593 gdl_dock_tablabel_new (GdlDockItem *item)
595     GdlDockTablabel *tablabel;
597     tablabel = GDL_DOCK_TABLABEL (g_object_new (GDL_TYPE_DOCK_TABLABEL,
598                                                 "item", item,
599                                                 NULL));
600     
601     return GTK_WIDGET (tablabel);
604 void
605 gdl_dock_tablabel_activate (GdlDockTablabel *tablabel)
607     g_return_if_fail (tablabel != NULL);
609     tablabel->active = TRUE;
610     gtk_widget_set_state (GTK_WIDGET (tablabel), GTK_STATE_NORMAL);
613 void
614 gdl_dock_tablabel_deactivate (GdlDockTablabel *tablabel)
616     g_return_if_fail (tablabel != NULL);
618     tablabel->active = FALSE;
619     /* yeah, i know it contradictive */
620     gtk_widget_set_state (GTK_WIDGET (tablabel), GTK_STATE_ACTIVE);