Code

Fixing preview/swatch sizes.
[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 static guint trackCount = 0;
94 static guint* trackSizes = 0;
95 static GtkIconSize* trackKeys = 0;
97 void eek_preview_set_size_mappings( guint count, GtkIconSize const* sizes )
98 {
99     gint width = 0;
100     gint height = 0;
101     gint smallest = 512;
102     gint largest = 0;
103     guint i = 0;
104     guint delta = 0;
106     for ( i = 0; i < count; ++i ) {
107         gboolean worked = gtk_icon_size_lookup( sizes[i], &width, &height );
108         if ( worked ) {
109             if ( width < smallest ) {
110                 smallest = width;
111             }
112             if ( width > largest ) {
113                 largest = width;
114             }
115         }
116     }
118     smallest = (smallest * 3) / 4;
120     delta = largest - smallest;
122     if ( trackSizes ) {
123         g_free(trackSizes);
124         trackSizes = 0;
125     }
126     if ( trackKeys ) {
127         g_free(trackKeys);
128         trackKeys = 0;
129     }
131     trackCount = count;
132     trackSizes = g_new(guint, count);
133     trackKeys = g_new(GtkIconSize, count);
134     for ( i = 0; i < count; ++i ) {
135         guint val = smallest + ( (i * delta) / (count-1) );
136         trackKeys[i] = sizes[i];
137         trackSizes[i] = val;
138     }
141 GtkWidget* eek_preview_area_new(void)
143     return NULL;
146 static void eek_preview_size_request( GtkWidget* widget, GtkRequisition* req )
148     gint width = 0;
149     gint height = 0;
150     EekPreview* preview = EEK_PREVIEW(widget);
151     gboolean tracked = TRUE;
152     guint i = 0;
154     for ( i = 0; i < trackCount; ++i ) {
155         tracked = (trackKeys[i] == preview->_size);
156         if ( tracked ) {
157             width = trackSizes[i];
158             height = width;
159             break;
160         }
161     }
163     if ( !tracked ) {
164         gboolean worked = gtk_icon_size_lookup( preview->_size, &width, &height );
165         if ( !worked ) {
166             width = 16;
167             height = 16;
168             g_warning("Size not found [%d]", preview->_size);
169         }
170     }
171     if ( preview->_view == VIEW_TYPE_LIST ) {
172         width *= 3;
173     }
174     req->width = width;
175     req->height = height;
178 enum {
179   CLICKED_SIGNAL,
180   ALTCLICKED_SIGNAL,
181   LAST_SIGNAL
182 };
185 static guint eek_preview_signals[LAST_SIGNAL] = { 0 };
188 gboolean eek_preview_expose_event( GtkWidget* widget, GdkEventExpose* event )
190 /*     g_message("Exposed!!!   %s", GTK_WIDGET_HAS_FOCUS(widget) ? "XXX" : "---" ); */
191     gint insetX = 0;
192     gint insetY = 0;
194     (void)event;
195 /*
196     gint lower = widget->allocation.width;
197     lower = (widget->allocation.height < lower) ? widget->allocation.height : lower;
198     if ( lower > 16 ) {
199         insetX++;
200         if ( lower > 18 ) {
201             insetX++;
202             if ( lower > 22 ) {
203                 insetX++;
204                 if ( lower > 24 ) {
205                     insetX++;
206                     if ( lower > 32 ) {
207                         insetX++;
208                     }
209                 }
210             }
211         }
212         insetY = insetX;
213     }
214 */
216     if ( GTK_WIDGET_DRAWABLE( widget ) ) {
217         GtkStyle* style = gtk_widget_get_style( widget );
219         if ( insetX > 0 || insetY > 0 ) {
220             gtk_paint_flat_box( style,
221                                 widget->window,
222                                 (GtkStateType)GTK_WIDGET_STATE(widget),
223                                 GTK_SHADOW_NONE,
224                                 NULL,
225                                 widget,
226                                 NULL,
227                                 0, 0,
228                                 widget->allocation.width, widget->allocation.height);
229         }
231         GdkGC *gc = gdk_gc_new( widget->window );
232         EekPreview* preview = EEK_PREVIEW(widget);
233         GdkColor fg = {0, preview->_r, preview->_g, preview->_b};
234         gdk_colormap_alloc_color( gdk_colormap_get_system(), &fg, FALSE, TRUE );
236         gdk_gc_set_foreground( gc, &fg );
238         gdk_draw_rectangle( widget->window,
239                             gc,
240                             TRUE,
241                             insetX, insetY,
242                             widget->allocation.width - (insetX * 2), widget->allocation.height - (insetY * 2) );
244         if ( preview->_linked ) {
245             /* Draw arrow */
246             GdkRectangle possible = {insetX, insetY, (widget->allocation.width - (insetX * 2)), (widget->allocation.height - (insetY * 2)) };
247             GdkRectangle area = {possible.x, possible.y, possible.width / 2, possible.height / 2 };
249             /* Make it square */
250             if ( area.width > area.height )
251                 area.width = area.height;
252             if ( area.height > area.width )
253                 area.height = area.width;
255             /* Center it horizontally */
256             if ( area.width < possible.width ) {
257                 int diff = (possible.width - area.width) / 2;
258                 area.x += diff;
259             }
262             if ( preview->_linked & PREVIEW_LINK_IN ) {
263                 gtk_paint_arrow( style,
264                                  widget->window,
265                                  (GtkStateType)widget->state,
266                                  GTK_SHADOW_ETCHED_IN,
267                                  NULL, /* clip area.  &area, */
268                                  widget, /* may be NULL */
269                                  NULL, /* detail */
270                                  GTK_ARROW_DOWN,
271                                  FALSE,
272                                  area.x, area.y,
273                                  area.width, area.height
274                                  );
275             }
277             if ( preview->_linked & PREVIEW_LINK_OUT ) {
278                 GdkRectangle otherArea = {area.x, area.y, area.width, area.height};
279                 if ( otherArea.height < possible.height ) {
280                     otherArea.y = possible.y + (possible.height - otherArea.height);
281                 }
283                 gtk_paint_arrow( style,
284                                  widget->window,
285                                  (GtkStateType)widget->state,
286                                  GTK_SHADOW_ETCHED_OUT,
287                                  NULL, /* clip area.  &area, */
288                                  widget, /* may be NULL */
289                                  NULL, /* detail */
290                                  GTK_ARROW_UP,
291                                  FALSE,
292                                  otherArea.x, otherArea.y,
293                                  otherArea.width, otherArea.height
294                                  );
295             }
297             if ( preview->_linked & PREVIEW_LINK_OTHER ) {
298                 GdkRectangle otherArea = {insetX, area.y, area.width, area.height};
299                 if ( otherArea.height < possible.height ) {
300                     otherArea.y = possible.y + (possible.height - otherArea.height) / 2;
301                 }
303                 gtk_paint_arrow( style,
304                                  widget->window,
305                                  (GtkStateType)widget->state,
306                                  GTK_SHADOW_ETCHED_OUT,
307                                  NULL, /* clip area.  &area, */
308                                  widget, /* may be NULL */
309                                  NULL, /* detail */
310                                  GTK_ARROW_LEFT,
311                                  FALSE,
312                                  otherArea.x, otherArea.y,
313                                  otherArea.width, otherArea.height
314                                  );
315             }
316         }
318         if ( GTK_WIDGET_HAS_FOCUS(widget) ) {
319             gtk_paint_focus( style,
320                              widget->window,
321                              GTK_STATE_NORMAL,
322                              NULL, /* GdkRectangle *area, */
323                              widget,
324                              NULL,
325                              0 + 1, 0 + 1,
326                              widget->allocation.width - 2, widget->allocation.height - 2 );
327         }
328     }
331     return FALSE;
335 static gboolean eek_preview_enter_cb( GtkWidget* widget, GdkEventCrossing* event )
337     if ( gtk_get_event_widget( (GdkEvent*)event ) == widget ) {
338         EekPreview* preview = EEK_PREVIEW(widget);
339         preview->_within = TRUE;
340         gtk_widget_set_state( widget, preview->_hot ? GTK_STATE_ACTIVE : GTK_STATE_PRELIGHT );
341     }
342     return FALSE;
345 static gboolean eek_preview_leave_cb( GtkWidget* widget, GdkEventCrossing* event )
347     if ( gtk_get_event_widget( (GdkEvent*)event ) == widget ) {
348         EekPreview* preview = EEK_PREVIEW(widget);
349         preview->_within = FALSE;
350         gtk_widget_set_state( widget, GTK_STATE_NORMAL );
351     }
352     return FALSE;
355 /*
356 static gboolean eek_preview_focus_in_event( GtkWidget* widget, GdkEventFocus* event )
358     g_message("focus IN");
359     gboolean blip = parent_class->focus_in_event ? parent_class->focus_in_event(widget, event) : FALSE;
360     return blip;
363 static gboolean eek_preview_focus_out_event( GtkWidget* widget, GdkEventFocus* event )
365     g_message("focus OUT");
366     gboolean blip = parent_class->focus_out_event ? parent_class->focus_out_event(widget, event) : FALSE;
367     return blip;
369 */
371 static gboolean eek_preview_button_press_cb( GtkWidget* widget, GdkEventButton* event )
373     if ( gtk_get_event_widget( (GdkEvent*)event ) == widget ) {
374         EekPreview* preview = EEK_PREVIEW(widget);
376         if ( preview->_takesFocus && !GTK_WIDGET_HAS_FOCUS(widget) ) {
377             gtk_widget_grab_focus(widget);
378         }
380         if ( event->button == PRIME_BUTTON_MAGIC_NUMBER ) {
381             preview->_hot = TRUE;
382             if ( preview->_within ) {
383                 gtk_widget_set_state( widget, GTK_STATE_ACTIVE );
384             }
385         }
386     }
388     return FALSE;
391 static gboolean eek_preview_button_release_cb( GtkWidget* widget, GdkEventButton* event )
393     if ( gtk_get_event_widget( (GdkEvent*)event ) == widget ) {
394         EekPreview* preview = EEK_PREVIEW(widget);
395         preview->_hot = FALSE;
396         gtk_widget_set_state( widget, GTK_STATE_NORMAL );
397         if ( preview->_within && event->button == PRIME_BUTTON_MAGIC_NUMBER ) {
398             gboolean isAlt = (event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK;
400             if ( isAlt ) {
401                 g_signal_emit( widget, eek_preview_signals[ALTCLICKED_SIGNAL], 0, 2 );
402             } else {
403                 g_signal_emit( widget, eek_preview_signals[CLICKED_SIGNAL], 0 );
404             }
405         }
406     }
407     return FALSE;
410 gboolean eek_preview_key_press_event( GtkWidget* widget, GdkEventKey* event)
412     (void)widget;
413     (void)event;
414     g_message("TICK");
415     return FALSE;
418 gboolean eek_preview_key_release_event( GtkWidget* widget, GdkEventKey* event)
420     (void)widget;
421     (void)event;
422     g_message("tock");
423     return FALSE;
426 static void eek_preview_get_property( GObject *object,
427                                       guint property_id,
428                                       GValue *value,
429                                       GParamSpec *pspec)
431     GObjectClass* gobjClass = G_OBJECT_CLASS(parent_class);
432     switch ( property_id ) {
433         case FOCUS_PROP_ID:
434         {
435             EekPreview* preview = EEK_PREVIEW( object );
436             g_value_set_boolean( value, preview->_takesFocus );
437         }
438         break;
439         default:
440         {
441             if ( gobjClass->get_property ) {
442                 gobjClass->get_property( object, property_id, value, pspec );
443             }
444         }
445     }
448 static void eek_preview_set_property( GObject *object,
449                                       guint property_id,
450                                       const GValue *value,
451                                       GParamSpec *pspec)
453     GObjectClass* gobjClass = G_OBJECT_CLASS(parent_class);
454     switch ( property_id ) {
455         case FOCUS_PROP_ID:
456         {
457             EekPreview* preview = EEK_PREVIEW( object );
458             gboolean val = g_value_get_boolean( value );
459             if ( val != preview->_takesFocus ) {
460                 preview->_takesFocus = val;
461             }
462         }
463         break;
464         default:
465         {
466             if ( gobjClass->set_property ) {
467                 gobjClass->set_property( object, property_id, value, pspec );
468             }
469         }
470     }
474 static gboolean eek_preview_popup_menu( GtkWidget* widget )
476 /*     g_message("Do the popup!"); */
477     gboolean blip = parent_class->popup_menu ? parent_class->popup_menu(widget) : FALSE;
478     return blip;
482 static void eek_preview_class_init( EekPreviewClass *klass )
484     GObjectClass* gobjClass = G_OBJECT_CLASS(klass);
485     /*GtkObjectClass* objectClass = (GtkObjectClass*)klass;*/
486     GtkWidgetClass* widgetClass = (GtkWidgetClass*)klass;
488     gobjClass->set_property = eek_preview_set_property;
489     gobjClass->get_property = eek_preview_get_property;
491     /*objectClass->destroy = eek_preview_destroy;*/
493     parent_class = (GtkWidgetClass*)g_type_class_peek_parent( klass );
495     /*widgetClass->map = ;*/
496     /*widgetClass->unmap = ;*/
497     /*widgetClass->realize = ;*/
498     /*widgetClass->unrealize = ;*/
499     widgetClass->size_request = eek_preview_size_request;
500     /*widgetClass->size_allocate = ;*/
501     /*widgetClass->state_changed = ;*/
502     /*widgetClass->style_set = ;*/
503     /*widgetClass->grab_notify = ;*/
505     widgetClass->button_press_event = eek_preview_button_press_cb;
506     widgetClass->button_release_event = eek_preview_button_release_cb;
507     /*widgetClass->delete_event = ;*/
508     /*widgetClass->destroy_event = ;*/
509     widgetClass->expose_event = eek_preview_expose_event;
510 /*     widgetClass->key_press_event = eek_preview_key_press_event; */
511 /*     widgetClass->key_release_event = eek_preview_key_release_event; */
512     widgetClass->enter_notify_event = eek_preview_enter_cb;
513     widgetClass->leave_notify_event = eek_preview_leave_cb;
514     /*widgetClass->configure_event = ;*/
515     /*widgetClass->focus_in_event = eek_preview_focus_in_event;*/
516     /*widgetClass->focus_out_event = eek_preview_focus_out_event;*/
518     /* selection */
519     /*widgetClass->selection_get = ;*/
520     /*widgetClass->selection_received = ;*/
523     /* drag source: */
524     /*widgetClass->drag_begin = ;*/
525     /*widgetClass->drag_end = ;*/
526     /*widgetClass->drag_data_get = ;*/
527     /*widgetClass->drag_data_delete = ;*/
529     /* drag target: */
530     /*widgetClass->drag_leave = ;*/
531     /*widgetClass->drag_motion = ;*/
532     /*widgetClass->drag_drop = ;*/
533     /*widgetClass->drag_data_received = ;*/
535     /* For keybindings: */
536     widgetClass->popup_menu = eek_preview_popup_menu;
537     /*widgetClass->show_help = ;*/
539     /* Accessibility support: */
540     /*widgetClass->get_accessible = ;*/
541     /*widgetClass->screen_changed = ;*/
542     /*widgetClass->can_activate_accel = ;*/
545     eek_preview_signals[CLICKED_SIGNAL] =
546         g_signal_new( "clicked",
547                       G_TYPE_FROM_CLASS( klass ),
548                       (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION),
549                       G_STRUCT_OFFSET( EekPreviewClass, clicked ),
550                       NULL, NULL,
551                       g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0 );
553     eek_preview_signals[ALTCLICKED_SIGNAL] =
554         g_signal_new( "alt-clicked",
555                       G_TYPE_FROM_CLASS( klass ),
556                       (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION),
557                       G_STRUCT_OFFSET( EekPreviewClass, clicked ),
558                       NULL, NULL,
559                       g_cclosure_marshal_VOID__INT, G_TYPE_NONE,
560                       1, G_TYPE_INT );
563     g_object_class_install_property( gobjClass,
564                                      FOCUS_PROP_ID,
565                                      g_param_spec_boolean(
566                                          "focus-on-click",
567                                          NULL,
568                                          "flag to grab focus when clicked",
569                                          TRUE,
570                                          (GParamFlags)(G_PARAM_READWRITE | G_PARAM_CONSTRUCT)
571                                          )
572         );
575 void eek_preview_set_linked( EekPreview* splat, LinkType link )
577     link = (LinkType)(link & PREVIEW_LINK_ALL);
578     if ( link != (LinkType)splat->_linked ) {
579         splat->_linked = link;
581         gtk_widget_queue_draw( GTK_WIDGET(splat) );
582     }
585 LinkType eek_preview_get_linked( EekPreview* splat )
587     return (LinkType)splat->_linked;
590 gboolean eek_preview_get_focus_on_click( EekPreview* preview )
592     return preview->_takesFocus;
595 void eek_preview_set_focus_on_click( EekPreview* preview, gboolean focus_on_click )
597     if ( focus_on_click != preview->_takesFocus ) {
598         preview->_takesFocus = focus_on_click;
599     }
602 void eek_preview_set_details( EekPreview* preview, PreviewStyle prevstyle, ViewType view, GtkIconSize size )
604     preview->_prevstyle = prevstyle;
605     preview->_view = view;
606     preview->_size = size;
608     gtk_widget_queue_draw(GTK_WIDGET(preview));
611 static void eek_preview_init( EekPreview *preview )
613     GtkWidget* widg = GTK_WIDGET(preview);
614     GTK_WIDGET_SET_FLAGS( widg, GTK_CAN_FOCUS );
615     GTK_WIDGET_SET_FLAGS( widg, GTK_RECEIVES_DEFAULT );
617     gtk_widget_set_sensitive( widg, TRUE );
619     gtk_widget_add_events(widg, GDK_BUTTON_PRESS_MASK
620                           | GDK_BUTTON_RELEASE_MASK
621                           | GDK_KEY_PRESS_MASK
622                           | GDK_KEY_RELEASE_MASK
623                           | GDK_FOCUS_CHANGE_MASK
624                           | GDK_ENTER_NOTIFY_MASK
625                           | GDK_LEAVE_NOTIFY_MASK );
627 /*    gtk_widget_add_events( widg, GDK_ALL_EVENTS_MASK );*/
629     preview->_r = 0x80;
630     preview->_g = 0x80;
631     preview->_b = 0xcc;
633     preview->_hot = FALSE;
634     preview->_within = FALSE;
635     preview->_takesFocus = FALSE;
637     preview->_prevstyle = PREVIEW_STYLE_ICON;
638     preview->_view = VIEW_TYPE_LIST;
639     preview->_size = GTK_ICON_SIZE_BUTTON;
641 /*
642     GdkColor color = {0};
643     color.red = (255 << 8) | 255;
645     GdkColor whack = {0};
646     whack.green = (255 << 8) | 255;
648     gtk_widget_modify_bg( widg, GTK_STATE_NORMAL, &color );
649     gtk_widget_modify_bg( widg, GTK_STATE_PRELIGHT, &whack );
650 */
652 /*   GTK_STATE_ACTIVE, */
653 /*   GTK_STATE_PRELIGHT, */
654 /*   GTK_STATE_SELECTED, */
655 /*   GTK_STATE_INSENSITIVE */
657   if ( 0 ) {
658     GdkColor color = {0,0,0,0};
660     color.red = 0xffff;
661     color.green = 0;
662     color.blue = 0xffff;
663     gdk_colormap_alloc_color( gdk_colormap_get_system(), &color, FALSE, TRUE );
664     gtk_widget_modify_bg(widg, GTK_STATE_ACTIVE, &color);
666     color.red = 0;
667     color.green = 0xffff;
668     color.blue = 0;
669     gdk_colormap_alloc_color( gdk_colormap_get_system(), &color, FALSE, TRUE );
670     gtk_widget_modify_bg(widg, GTK_STATE_SELECTED, &color);
672     color.red = 0xffff;
673     color.green = 0;
674     color.blue = 0;
675     gdk_colormap_alloc_color( gdk_colormap_get_system(), &color, FALSE, TRUE );
676     gtk_widget_modify_bg( widg, GTK_STATE_PRELIGHT, &color );
677   }
681 GtkWidget* eek_preview_new(void)
683     return GTK_WIDGET( g_object_new( EEK_PREVIEW_TYPE, NULL ) );