Code

0108d47775bacf0908ce496a021e6c43101a03c7
[inkscape.git] / src / dialogs / eek-preview.cpp
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  *
3  */
4 /* ***** BEGIN LICENSE BLOCK *****
5  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6  *
7  * The contents of this file are subject to the Mozilla Public License Version
8  * 1.1 (the "License"); you may not use this file except in compliance with
9  * the License. You may obtain a copy of the License at
10  * http://www.mozilla.org/MPL/
11  *
12  * Software distributed under the License is distributed on an "AS IS" basis,
13  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14  * for the specific language governing rights and limitations under the
15  * License.
16  *
17  * The Original Code is Eek Preview Stuffs.
18  *
19  * The Initial Developer of the Original Code is
20  * Jon A. Cruz.
21  * Portions created by the Initial Developer are Copyright (C) 2005
22  * the Initial Developer. All Rights Reserved.
23  *
24  * Contributor(s):
25  *
26  * Alternatively, the contents of this file may be used under the terms of
27  * either the GNU General Public License Version 2 or later (the "GPL"), or
28  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29  * in which case the provisions of the GPL or the LGPL are applicable instead
30  * of those above. If you wish to allow use of your version of this file only
31  * under the terms of either the GPL or the LGPL, and not to allow others to
32  * use your version of this file under the terms of the MPL, indicate your
33  * decision by deleting the provisions above and replace them with the notice
34  * and other provisions required by the GPL or the LGPL. If you do not delete
35  * the provisions above, a recipient may use your version of this file under
36  * the terms of any one of the MPL, the GPL or the LGPL.
37  *
38  * ***** END LICENSE BLOCK ***** */
40 #include <gtk/gtk.h>
41 #include "eek-preview.h"
43 #define PRIME_BUTTON_MAGIC_NUMBER 1
45 #define FOCUS_PROP_ID 1
49 static void eek_preview_class_init( EekPreviewClass *klass );
50 static void eek_preview_init( EekPreview *preview );
52 static GtkWidgetClass* parent_class = 0;
54 void eek_preview_set_color( EekPreview* preview, int r, int g, int b )
55 {
56     if ( (preview->_r = r)
57          || (preview->_g = g)
58          || (preview->_b = b) ) {
59         preview->_r = r;
60         preview->_g = g;
61         preview->_b = b;
63         gtk_widget_queue_draw(GTK_WIDGET(preview));
64     }
65 }
68 GType eek_preview_get_type(void)
69 {
70     static GType preview_type = 0;
72     if (!preview_type) {
73       static const GTypeInfo preview_info = {
74           sizeof( EekPreviewClass ),
75           NULL, /* base_init */
76           NULL, /* base_finalize */
77           (GClassInitFunc)eek_preview_class_init,
78           NULL, /* class_finalize */
79           NULL, /* class_data */
80           sizeof( EekPreview ),
81           0,    /* n_preallocs */
82           (GInstanceInitFunc)eek_preview_init,
83           NULL /* value_table */
84       };
87       preview_type = g_type_register_static( GTK_TYPE_DRAWING_AREA, "EekPreview", &preview_info, (GTypeFlags)0 );
88     }
90     return preview_type;
91 }
93 GtkWidget* eek_preview_area_new(void)
94 {
95     return NULL;
96 }
98 static void eek_preview_size_request( GtkWidget* widget, GtkRequisition* req )
99 {
100     gint width = 0;
101     gint height = 0;
102     EekPreview* preview = EEK_PREVIEW(widget);
103     gboolean worked = gtk_icon_size_lookup( preview->_size, &width, &height );
104     if ( !worked ) {
105         width = 16;
106         height = 16;
107     }
108     if ( preview->_view == VIEW_TYPE_LIST ) {
109         width *= 3;
110     }
111     req->width = width;
112     req->height = height;
115 enum {
116   CLICKED_SIGNAL,
117   ALTCLICKED_SIGNAL,
118   LAST_SIGNAL
119 };
122 static guint eek_preview_signals[LAST_SIGNAL] = { 0 };
125 gboolean eek_preview_expose_event( GtkWidget* widget, GdkEventExpose* event )
127 /*     g_message("Exposed!!!   %s", GTK_WIDGET_HAS_FOCUS(widget) ? "XXX" : "---" ); */
128     gint insetX = 0;
129     gint insetY = 0;
131 /*
132     gint lower = widget->allocation.width;
133     lower = (widget->allocation.height < lower) ? widget->allocation.height : lower;
134     if ( lower > 16 ) {
135         insetX++;
136         if ( lower > 18 ) {
137             insetX++;
138             if ( lower > 22 ) {
139                 insetX++;
140                 if ( lower > 24 ) {
141                     insetX++;
142                     if ( lower > 32 ) {
143                         insetX++;
144                     }
145                 }
146             }
147         }
148         insetY = insetX;
149     }
150 */
152     if ( GTK_WIDGET_DRAWABLE( widget ) ) {
153         GtkStyle* style = gtk_widget_get_style( widget );
155         if ( insetX > 0 || insetY > 0 ) {
156             gtk_paint_flat_box( style,
157                                 widget->window,
158                                 (GtkStateType)GTK_WIDGET_STATE(widget),
159                                 GTK_SHADOW_NONE,
160                                 NULL,
161                                 widget,
162                                 NULL,
163                                 0, 0,
164                                 widget->allocation.width, widget->allocation.height);
165         }
167         GdkGC *gc = gdk_gc_new( widget->window );
168         EekPreview* preview = EEK_PREVIEW(widget);
169         GdkColor fg = {0, preview->_r, preview->_g, preview->_b};
170         gdk_colormap_alloc_color( gdk_colormap_get_system(), &fg, FALSE, TRUE );
172         gdk_gc_set_foreground( gc, &fg );
174         gdk_draw_rectangle( widget->window,
175                             gc,
176                             TRUE,
177                             insetX, insetY,
178                             widget->allocation.width - (insetX * 2), widget->allocation.height - (insetY * 2) );
180         if ( preview->_linked ) {
181             /* Draw arrow */
182             GdkRectangle possible = {insetX, insetY, (widget->allocation.width - (insetX * 2)), (widget->allocation.height - (insetY * 2)) };
183             GdkRectangle area = {possible.x, possible.y, possible.width / 2, possible.height / 2 };
185             /* Make it square */
186             if ( area.width > area.height )
187                 area.width = area.height;
188             if ( area.height > area.width )
189                 area.height = area.width;
191             /* Center it horizontally */
192             if ( area.width < possible.width ) {
193                 int diff = (possible.width - area.width) / 2;
194                 area.x += diff;
195             }
198             if ( preview->_linked & PREVIEW_LINK_IN ) {
199                 gtk_paint_arrow( style,
200                                  widget->window,
201                                  (GtkStateType)widget->state,
202                                  GTK_SHADOW_ETCHED_IN,
203                                  NULL, /* clip area.  &area, */
204                                  widget, /* may be NULL */
205                                  NULL, /* detail */
206                                  GTK_ARROW_DOWN,
207                                  FALSE,
208                                  area.x, area.y,
209                                  area.width, area.height
210                                  );
211             }
213             if ( preview->_linked & PREVIEW_LINK_OUT ) {
214                 GdkRectangle otherArea = {area.x, area.y, area.width, area.height};
215                 if ( otherArea.height < possible.height ) {
216                     otherArea.y = possible.y + (possible.height - otherArea.height);
217                 }
219                 gtk_paint_arrow( style,
220                                  widget->window,
221                                  (GtkStateType)widget->state,
222                                  GTK_SHADOW_ETCHED_OUT,
223                                  NULL, /* clip area.  &area, */
224                                  widget, /* may be NULL */
225                                  NULL, /* detail */
226                                  GTK_ARROW_UP,
227                                  FALSE,
228                                  otherArea.x, otherArea.y,
229                                  otherArea.width, otherArea.height
230                                  );
231             }
233             if ( preview->_linked & PREVIEW_LINK_OTHER ) {
234                 GdkRectangle otherArea = {insetX, area.y, area.width, area.height};
235                 if ( otherArea.height < possible.height ) {
236                     otherArea.y = possible.y + (possible.height - otherArea.height) / 2;
237                 }
239                 gtk_paint_arrow( style,
240                                  widget->window,
241                                  (GtkStateType)widget->state,
242                                  GTK_SHADOW_ETCHED_OUT,
243                                  NULL, /* clip area.  &area, */
244                                  widget, /* may be NULL */
245                                  NULL, /* detail */
246                                  GTK_ARROW_LEFT,
247                                  FALSE,
248                                  otherArea.x, otherArea.y,
249                                  otherArea.width, otherArea.height
250                                  );
251             }
252         }
254         if ( GTK_WIDGET_HAS_FOCUS(widget) ) {
255             gtk_paint_focus( style,
256                              widget->window,
257                              GTK_STATE_NORMAL,
258                              NULL, /* GdkRectangle *area, */
259                              widget,
260                              NULL,
261                              0 + 1, 0 + 1,
262                              widget->allocation.width - 2, widget->allocation.height - 2 );
263         }
264     }
267     return FALSE;
271 static gboolean eek_preview_enter_cb( GtkWidget* widget, GdkEventCrossing* event )
273     if ( gtk_get_event_widget( (GdkEvent*)event ) == widget ) {
274         EekPreview* preview = EEK_PREVIEW(widget);
275         preview->_within = TRUE;
276         gtk_widget_set_state( widget, preview->_hot ? GTK_STATE_ACTIVE : GTK_STATE_PRELIGHT );
277     }
278     return FALSE;
281 static gboolean eek_preview_leave_cb( GtkWidget* widget, GdkEventCrossing* event )
283     if ( gtk_get_event_widget( (GdkEvent*)event ) == widget ) {
284         EekPreview* preview = EEK_PREVIEW(widget);
285         preview->_within = FALSE;
286         gtk_widget_set_state( widget, GTK_STATE_NORMAL );
287     }
288     return FALSE;
291 /*
292 static gboolean eek_preview_focus_in_event( GtkWidget* widget, GdkEventFocus* event )
294     g_message("focus IN");
295     gboolean blip = parent_class->focus_in_event ? parent_class->focus_in_event(widget, event) : FALSE;
296     return blip;
299 static gboolean eek_preview_focus_out_event( GtkWidget* widget, GdkEventFocus* event )
301     g_message("focus OUT");
302     gboolean blip = parent_class->focus_out_event ? parent_class->focus_out_event(widget, event) : FALSE;
303     return blip;
305 */
307 static gboolean eek_preview_button_press_cb( GtkWidget* widget, GdkEventButton* event )
309     if ( gtk_get_event_widget( (GdkEvent*)event ) == widget ) {
310         EekPreview* preview = EEK_PREVIEW(widget);
312         if ( preview->_takesFocus && !GTK_WIDGET_HAS_FOCUS(widget) ) {
313             gtk_widget_grab_focus(widget);
314         }
316         if ( event->button == PRIME_BUTTON_MAGIC_NUMBER ) {
317             preview->_hot = TRUE;
318             if ( preview->_within ) {
319                 gtk_widget_set_state( widget, GTK_STATE_ACTIVE );
320             }
321         }
322     }
324     return FALSE;
327 static gboolean eek_preview_button_release_cb( GtkWidget* widget, GdkEventButton* event )
329     if ( gtk_get_event_widget( (GdkEvent*)event ) == widget ) {
330         EekPreview* preview = EEK_PREVIEW(widget);
331         preview->_hot = FALSE;
332         gtk_widget_set_state( widget, GTK_STATE_NORMAL );
333         if ( preview->_within && event->button == PRIME_BUTTON_MAGIC_NUMBER ) {
334             gboolean isAlt = (event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK;
336             if ( isAlt ) {
337                 g_signal_emit( widget, eek_preview_signals[ALTCLICKED_SIGNAL], 0, 2 );
338             } else {
339                 g_signal_emit( widget, eek_preview_signals[CLICKED_SIGNAL], 0 );
340             }
341         }
342     }
343     return FALSE;
346 gboolean eek_preview_key_press_event( GtkWidget* widget, GdkEventKey* event)
348     g_message("TICK");
349     return FALSE;
352 gboolean eek_preview_key_release_event( GtkWidget* widget, GdkEventKey* event)
354     g_message("tock");
355     return FALSE;
358 static void eek_preview_get_property( GObject *object,
359                                       guint property_id,
360                                       GValue *value,
361                                       GParamSpec *pspec)
363     GObjectClass* gobjClass = G_OBJECT_CLASS(parent_class);
364     switch ( property_id ) {
365         case FOCUS_PROP_ID:
366         {
367             EekPreview* preview = EEK_PREVIEW( object );
368             g_value_set_boolean( value, preview->_takesFocus );
369         }
370         break;
371         default:
372         {
373             if ( gobjClass->get_property ) {
374                 gobjClass->get_property( object, property_id, value, pspec );
375             }
376         }
377     }
380 static void eek_preview_set_property( GObject *object,
381                                       guint property_id,
382                                       const GValue *value,
383                                       GParamSpec *pspec)
385     GObjectClass* gobjClass = G_OBJECT_CLASS(parent_class);
386     switch ( property_id ) {
387         case FOCUS_PROP_ID:
388         {
389             EekPreview* preview = EEK_PREVIEW( object );
390             gboolean val = g_value_get_boolean( value );
391             if ( val != preview->_takesFocus ) {
392                 preview->_takesFocus = val;
393             }
394         }
395         break;
396         default:
397         {
398             if ( gobjClass->set_property ) {
399                 gobjClass->set_property( object, property_id, value, pspec );
400             }
401         }
402     }
406 static gboolean eek_preview_popup_menu( GtkWidget* widget )
408 /*     g_message("Do the popup!"); */
409     gboolean blip = parent_class->popup_menu ? parent_class->popup_menu(widget) : FALSE;
410     return blip;
414 static void eek_preview_class_init( EekPreviewClass *klass )
416     GObjectClass* gobjClass = G_OBJECT_CLASS(klass);
417     /*GtkObjectClass* objectClass = (GtkObjectClass*)klass;*/
418     GtkWidgetClass* widgetClass = (GtkWidgetClass*)klass;
420     gobjClass->set_property = eek_preview_set_property;
421     gobjClass->get_property = eek_preview_get_property;
423     /*objectClass->destroy = eek_preview_destroy;*/
425     parent_class = (GtkWidgetClass*)g_type_class_peek_parent( klass );
427     /*widgetClass->map = ;*/
428     /*widgetClass->unmap = ;*/
429     /*widgetClass->realize = ;*/
430     /*widgetClass->unrealize = ;*/
431     widgetClass->size_request = eek_preview_size_request;
432     /*widgetClass->size_allocate = ;*/
433     /*widgetClass->state_changed = ;*/
434     /*widgetClass->style_set = ;*/
435     /*widgetClass->grab_notify = ;*/
437     widgetClass->button_press_event = eek_preview_button_press_cb;
438     widgetClass->button_release_event = eek_preview_button_release_cb;
439     /*widgetClass->delete_event = ;*/
440     /*widgetClass->destroy_event = ;*/
441     widgetClass->expose_event = eek_preview_expose_event;
442 /*     widgetClass->key_press_event = eek_preview_key_press_event; */
443 /*     widgetClass->key_release_event = eek_preview_key_release_event; */
444     widgetClass->enter_notify_event = eek_preview_enter_cb;
445     widgetClass->leave_notify_event = eek_preview_leave_cb;
446     /*widgetClass->configure_event = ;*/
447     /*widgetClass->focus_in_event = eek_preview_focus_in_event;*/
448     /*widgetClass->focus_out_event = eek_preview_focus_out_event;*/
450     /* selection */
451     /*widgetClass->selection_get = ;*/
452     /*widgetClass->selection_received = ;*/
455     /* drag source: */
456     /*widgetClass->drag_begin = ;*/
457     /*widgetClass->drag_end = ;*/
458     /*widgetClass->drag_data_get = ;*/
459     /*widgetClass->drag_data_delete = ;*/
461     /* drag target: */
462     /*widgetClass->drag_leave = ;*/
463     /*widgetClass->drag_motion = ;*/
464     /*widgetClass->drag_drop = ;*/
465     /*widgetClass->drag_data_received = ;*/
467     /* For keybindings: */
468     widgetClass->popup_menu = eek_preview_popup_menu;
469     /*widgetClass->show_help = ;*/
471     /* Accessibility support: */
472     /*widgetClass->get_accessible = ;*/
473     /*widgetClass->screen_changed = ;*/
474     /*widgetClass->can_activate_accel = ;*/
477     eek_preview_signals[CLICKED_SIGNAL] =
478         g_signal_new( "clicked",
479                       G_TYPE_FROM_CLASS( klass ),
480                       (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION),
481                       G_STRUCT_OFFSET( EekPreviewClass, clicked ),
482                       NULL, NULL,
483                       g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0 );
485     eek_preview_signals[ALTCLICKED_SIGNAL] =
486         g_signal_new( "alt-clicked",
487                       G_TYPE_FROM_CLASS( klass ),
488                       (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION),
489                       G_STRUCT_OFFSET( EekPreviewClass, clicked ),
490                       NULL, NULL,
491                       g_cclosure_marshal_VOID__INT, G_TYPE_NONE,
492                       1, G_TYPE_INT );
495     g_object_class_install_property( gobjClass,
496                                      FOCUS_PROP_ID,
497                                      g_param_spec_boolean(
498                                          "focus-on-click",
499                                          NULL,
500                                          "flag to grab focus when clicked",
501                                          TRUE,
502                                          (GParamFlags)(G_PARAM_READWRITE | G_PARAM_CONSTRUCT)
503                                          )
504         );
507 void eek_preview_set_linked( EekPreview* splat, LinkType link )
509     link = (LinkType)(link & PREVIEW_LINK_ALL);
510     if ( link != (LinkType)splat->_linked ) {
511         splat->_linked = link;
513         gtk_widget_queue_draw( GTK_WIDGET(splat) );
514     }
517 LinkType eek_preview_get_linked( EekPreview* splat )
519     return (LinkType)splat->_linked;
522 gboolean eek_preview_get_focus_on_click( EekPreview* preview )
524     return preview->_takesFocus;
527 void eek_preview_set_focus_on_click( EekPreview* preview, gboolean focus_on_click )
529     if ( focus_on_click != preview->_takesFocus ) {
530         preview->_takesFocus = focus_on_click;
531     }
534 void eek_preview_set_details( EekPreview* preview, PreviewStyle prevstyle, ViewType view, GtkIconSize size )
536     preview->_prevstyle = prevstyle;
537     preview->_view = view;
538     preview->_size = size;
540     gtk_widget_queue_draw(GTK_WIDGET(preview));
543 static void eek_preview_init( EekPreview *preview )
545     GtkWidget* widg = GTK_WIDGET(preview);
546     GTK_WIDGET_SET_FLAGS( widg, GTK_CAN_FOCUS );
547     GTK_WIDGET_SET_FLAGS( widg, GTK_RECEIVES_DEFAULT );
549     gtk_widget_set_sensitive( widg, TRUE );
551     gtk_widget_add_events(widg, GDK_BUTTON_PRESS_MASK
552                           | GDK_BUTTON_RELEASE_MASK
553                           | GDK_KEY_PRESS_MASK
554                           | GDK_KEY_RELEASE_MASK
555                           | GDK_FOCUS_CHANGE_MASK
556                           | GDK_ENTER_NOTIFY_MASK
557                           | GDK_LEAVE_NOTIFY_MASK );
559 /*    gtk_widget_add_events( widg, GDK_ALL_EVENTS_MASK );*/
561     preview->_r = 0x80;
562     preview->_g = 0x80;
563     preview->_b = 0xcc;
565     preview->_hot = FALSE;
566     preview->_within = FALSE;
567     preview->_takesFocus = FALSE;
569     preview->_prevstyle = PREVIEW_STYLE_ICON;
570     preview->_view = VIEW_TYPE_LIST;
571     preview->_size = GTK_ICON_SIZE_BUTTON;
573 /*
574     GdkColor color = {0};
575     color.red = (255 << 8) | 255;
577     GdkColor whack = {0};
578     whack.green = (255 << 8) | 255;
580     gtk_widget_modify_bg( widg, GTK_STATE_NORMAL, &color );
581     gtk_widget_modify_bg( widg, GTK_STATE_PRELIGHT, &whack );
582 */
584 /*   GTK_STATE_ACTIVE, */
585 /*   GTK_STATE_PRELIGHT, */
586 /*   GTK_STATE_SELECTED, */
587 /*   GTK_STATE_INSENSITIVE */
589   if ( 0 ) {
590     GdkColor color = {0,0,0,0};
592     color.red = 0xffff;
593     color.green = 0;
594     color.blue = 0xffff;
595     gdk_colormap_alloc_color( gdk_colormap_get_system(), &color, FALSE, TRUE );
596     gtk_widget_modify_bg(widg, GTK_STATE_ACTIVE, &color);
598     color.red = 0;
599     color.green = 0xffff;
600     color.blue = 0;
601     gdk_colormap_alloc_color( gdk_colormap_get_system(), &color, FALSE, TRUE );
602     gtk_widget_modify_bg(widg, GTK_STATE_SELECTED, &color);
604     color.red = 0xffff;
605     color.green = 0;
606     color.blue = 0;
607     gdk_colormap_alloc_color( gdk_colormap_get_system(), &color, FALSE, TRUE );
608     gtk_widget_modify_bg( widg, GTK_STATE_PRELIGHT, &color );
609   }
613 GtkWidget* eek_preview_new(void)
615     return GTK_WIDGET( g_object_new( EEK_PREVIEW_TYPE, NULL ) );