]> Pileus Git - ~andy/gtk/blob - gtk/gtkpreview.c
66a83c0dee2470dcc6fb097d2e6ca8e73be4b59b
[~andy/gtk] / gtk / gtkpreview.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
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 #undef GDK_DISABLE_DEPRECATED
28 #undef GTK_DISABLE_DEPRECATED
29
30 #include <config.h>
31
32 #include <math.h>
33 #include <string.h>
34 #include <sys/types.h>
35 #ifdef HAVE_SYS_PARAM_H
36 #include <sys/param.h>
37 #endif
38 #include "gdk/gdkrgb.h"
39 #include "gtkpreview.h"
40 #include "gtksignal.h"
41 #include "gtkprivate.h"
42 #include "gtkintl.h"
43 #include "gtkalias.h"
44
45
46 #define PREVIEW_CLASS(w)      GTK_PREVIEW_CLASS (GTK_OBJECT (w)->klass)
47
48 enum {
49   PROP_0,
50   PROP_EXPAND
51 };
52
53
54 static void   gtk_preview_class_init    (GtkPreviewClass  *klass);
55 static void   gtk_preview_init          (GtkPreview       *preview);
56 static void   gtk_preview_set_property  (GObject          *object,
57                                          guint             prop_id,
58                                          const GValue     *value,
59                                          GParamSpec       *pspec);
60 static void   gtk_preview_get_property  (GObject          *object,
61                                          guint             prop_id,
62                                          GValue           *value,
63                                          GParamSpec       *pspec);
64 static void   gtk_preview_finalize      (GObject          *object);
65 static void   gtk_preview_realize       (GtkWidget        *widget);
66 static void   gtk_preview_size_allocate (GtkWidget        *widget,
67                                          GtkAllocation    *allocation);
68 static gint   gtk_preview_expose        (GtkWidget        *widget,
69                                          GdkEventExpose   *event);
70 static void   gtk_preview_make_buffer   (GtkPreview       *preview);
71 static void   gtk_fill_lookup_array     (guchar           *array);
72
73 static GtkWidgetClass *parent_class = NULL;
74 static GtkPreviewClass *preview_class = NULL;
75 static gint install_cmap = FALSE;
76
77
78 GtkType
79 gtk_preview_get_type (void)
80 {
81   static GtkType preview_type = 0;
82
83   if (!preview_type)
84     {
85       static const GtkTypeInfo preview_info =
86       {
87         "GtkPreview",
88         sizeof (GtkPreview),
89         sizeof (GtkPreviewClass),
90         (GtkClassInitFunc) gtk_preview_class_init,
91         (GtkObjectInitFunc) gtk_preview_init,
92         /* reserved_1 */ NULL,
93         /* reserved_2 */ NULL,
94         (GtkClassInitFunc) NULL,
95       };
96
97       I_("GtkPreview");
98       preview_type = gtk_type_unique (GTK_TYPE_WIDGET, &preview_info);
99     }
100
101   return preview_type;
102 }
103
104 static void
105 gtk_preview_class_init (GtkPreviewClass *klass)
106 {
107   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
108   GtkObjectClass *object_class;
109   GtkWidgetClass *widget_class;
110
111   object_class = (GtkObjectClass*) klass;
112   widget_class = (GtkWidgetClass*) klass;
113
114   parent_class = gtk_type_class (GTK_TYPE_WIDGET);
115   preview_class = klass;
116
117   gobject_class->finalize = gtk_preview_finalize;
118
119   gobject_class->set_property = gtk_preview_set_property;
120   gobject_class->get_property = gtk_preview_get_property;
121
122   widget_class->realize = gtk_preview_realize;
123   widget_class->size_allocate = gtk_preview_size_allocate;
124   widget_class->expose_event = gtk_preview_expose;
125
126   klass->info.lookup = NULL;
127
128   klass->info.gamma = 1.0;
129
130   gdk_rgb_init ();
131
132   g_object_class_install_property (gobject_class,
133                                    PROP_EXPAND,
134                                    g_param_spec_boolean ("expand",
135                                                          P_("Expand"),
136                                                          P_("Whether the preview widget should take up the entire space it is allocated"),
137                                                          FALSE,
138                                                          GTK_PARAM_READWRITE));
139 }
140
141 static void
142 gtk_preview_set_property (GObject      *object,
143                           guint         prop_id,
144                           const GValue *value,
145                           GParamSpec   *pspec)
146 {
147   GtkPreview *preview = GTK_PREVIEW (object);
148   
149   switch (prop_id)
150     {
151     case PROP_EXPAND:
152       gtk_preview_set_expand (preview, g_value_get_boolean (value));
153       break;
154     default:
155       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
156       break;
157     }
158 }
159
160 static void
161 gtk_preview_get_property (GObject      *object,
162                           guint         prop_id,
163                           GValue       *value,
164                           GParamSpec   *pspec)
165 {
166   GtkPreview *preview;
167   
168   preview = GTK_PREVIEW (object);
169   
170   switch (prop_id)
171     {
172     case PROP_EXPAND:
173       g_value_set_boolean (value, preview->expand);
174       break;
175     default:
176       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
177       break;
178     }
179 }
180
181 void
182 gtk_preview_reset (void)
183 {
184   /* unimplemented */
185 }
186
187 static void
188 gtk_preview_init (GtkPreview *preview)
189 {
190   preview->buffer = NULL;
191   preview->buffer_width = 0;
192   preview->buffer_height = 0;
193   preview->expand = FALSE;
194 }
195
196 void
197 gtk_preview_uninit (void)
198 {
199   /* unimplemented */
200 }
201
202 GtkWidget*
203 gtk_preview_new (GtkPreviewType type)
204 {
205   GtkPreview *preview;
206
207   preview = gtk_type_new (gtk_preview_get_type ());
208   preview->type = type;
209
210   if (type == GTK_PREVIEW_COLOR)
211     preview->bpp = 3;
212   else
213     preview->bpp = 1;
214
215   preview->dither = GDK_RGB_DITHER_NORMAL;
216
217   return GTK_WIDGET (preview);
218 }
219
220 void
221 gtk_preview_size (GtkPreview *preview,
222                   gint        width,
223                   gint        height)
224 {
225   g_return_if_fail (GTK_IS_PREVIEW (preview));
226
227   if ((width != GTK_WIDGET (preview)->requisition.width) ||
228       (height != GTK_WIDGET (preview)->requisition.height))
229     {
230       GTK_WIDGET (preview)->requisition.width = width;
231       GTK_WIDGET (preview)->requisition.height = height;
232
233       if (preview->buffer)
234         g_free (preview->buffer);
235       preview->buffer = NULL;
236     }
237 }
238
239 void
240 gtk_preview_put (GtkPreview   *preview,
241                  GdkWindow    *window,
242                  GdkGC        *gc,
243                  gint          srcx,
244                  gint          srcy,
245                  gint          destx,
246                  gint          desty,
247                  gint          width,
248                  gint          height)
249 {
250   GtkWidget *widget;
251   GdkRectangle r1, r2, r3;
252   guchar *src;
253   guint bpp;
254   guint rowstride;
255
256   g_return_if_fail (GTK_IS_PREVIEW (preview));
257   g_return_if_fail (window != NULL);
258
259   if (!preview->buffer)
260     return;
261
262   widget = GTK_WIDGET (preview);
263
264   r1.x = 0;
265   r1.y = 0;
266   r1.width = preview->buffer_width;
267   r1.height = preview->buffer_height;
268
269   r2.x = srcx;
270   r2.y = srcy;
271   r2.width = width;
272   r2.height = height;
273
274   if (!gdk_rectangle_intersect (&r1, &r2, &r3))
275     return;
276
277   bpp = preview->bpp;
278   rowstride = preview->rowstride;
279
280   src = preview->buffer + r3.y * rowstride + r3.x * bpp;
281
282   if (preview->type == GTK_PREVIEW_COLOR)
283     gdk_draw_rgb_image (window,
284                         gc,
285                         destx + (r3.x - srcx),
286                         desty + (r3.y - srcy),
287                         r3.width,
288                         r3.height,
289                         preview->dither,
290                         src,
291                         rowstride);
292   else
293     gdk_draw_gray_image (window,
294                          gc,
295                          destx + (r3.x - srcx),
296                          desty + (r3.y - srcy),
297                          r3.width,
298                          r3.height,
299                          preview->dither,
300                          src,
301                          rowstride);
302                         
303 }
304
305 void
306 gtk_preview_draw_row (GtkPreview *preview,
307                       guchar     *data,
308                       gint        x,
309                       gint        y,
310                       gint        w)
311 {
312   guint bpp;
313   guint rowstride;
314
315   g_return_if_fail (GTK_IS_PREVIEW (preview));
316   g_return_if_fail (data != NULL);
317   
318   bpp = (preview->type == GTK_PREVIEW_COLOR ? 3 : 1);
319   rowstride = (preview->buffer_width * bpp + 3) & -4;
320
321   if ((w <= 0) || (y < 0))
322     return;
323
324   g_return_if_fail (data != NULL);
325
326   gtk_preview_make_buffer (preview);
327
328   if (x + w > preview->buffer_width)
329     return;
330
331   if (y + 1 > preview->buffer_height)
332     return;
333
334   if (preview_class->info.gamma == 1.0)
335     memcpy (preview->buffer + y * rowstride + x * bpp, data, w * bpp);
336   else
337     {
338       guint i, size;
339       guchar *src, *dst;
340       guchar *lookup;
341
342       if (preview_class->info.lookup != NULL)
343         lookup = preview_class->info.lookup;
344       else
345         {
346           preview_class->info.lookup = g_new (guchar, 256);
347           gtk_fill_lookup_array (preview_class->info.lookup);
348           lookup = preview_class->info.lookup;
349         }
350       size = w * bpp;
351       src = data;
352       dst = preview->buffer + y * rowstride + x * bpp;
353       for (i = 0; i < size; i++)
354         *dst++ = lookup[*src++];
355     }
356 }
357
358 void
359 gtk_preview_set_expand (GtkPreview *preview,
360                         gboolean    expand)
361 {
362   g_return_if_fail (GTK_IS_PREVIEW (preview));
363
364   expand = expand != FALSE;
365
366   if (preview->expand != expand)
367     {
368       preview->expand = expand;
369       gtk_widget_queue_resize (GTK_WIDGET (preview));
370  
371       g_object_notify (G_OBJECT (preview), "expand"); 
372     }
373 }
374
375 void
376 gtk_preview_set_gamma (double _gamma)
377 {
378   if (!preview_class)
379     preview_class = gtk_type_class (gtk_preview_get_type ());
380
381   if (preview_class->info.gamma != _gamma)
382     {
383       preview_class->info.gamma = _gamma;
384       if (preview_class->info.lookup != NULL)
385         {
386           g_free (preview_class->info.lookup);
387           preview_class->info.lookup = NULL;
388         }
389     }
390 }
391
392 void
393 gtk_preview_set_color_cube (guint nred_shades,
394                             guint ngreen_shades,
395                             guint nblue_shades,
396                             guint ngray_shades)
397 {
398   /* unimplemented */
399 }
400
401 void
402 gtk_preview_set_install_cmap (gint _install_cmap)
403 {
404   /* effectively unimplemented */
405   install_cmap = _install_cmap;
406 }
407
408 void
409 gtk_preview_set_reserved (gint nreserved)
410 {
411
412   /* unimplemented */
413 }
414
415 void
416 gtk_preview_set_dither (GtkPreview      *preview,
417                         GdkRgbDither     dither)
418 {
419   preview->dither = dither;
420 }
421
422 GdkVisual*
423 gtk_preview_get_visual (void)
424 {
425   return gdk_screen_get_rgb_visual (gdk_screen_get_default ());
426 }
427
428 GdkColormap*
429 gtk_preview_get_cmap (void)
430 {
431   return gdk_screen_get_rgb_colormap (gdk_screen_get_default ());
432 }
433
434 GtkPreviewInfo*
435 gtk_preview_get_info (void)
436 {
437   if (!preview_class)
438     preview_class = gtk_type_class (gtk_preview_get_type ());
439
440   return &preview_class->info;
441 }
442
443
444 static void
445 gtk_preview_finalize (GObject *object)
446 {
447   GtkPreview *preview;
448
449   g_return_if_fail (GTK_IS_PREVIEW (object));
450
451   preview = GTK_PREVIEW (object);
452   if (preview->buffer)
453     g_free (preview->buffer);
454   preview->type = (GtkPreviewType) -1;
455
456   G_OBJECT_CLASS (parent_class)->finalize (object);
457 }
458
459 static void
460 gtk_preview_realize (GtkWidget *widget)
461 {
462   GtkPreview *preview;
463   GdkWindowAttr attributes;
464   gint attributes_mask;
465
466   g_return_if_fail (GTK_IS_PREVIEW (widget));
467
468   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
469   preview = GTK_PREVIEW (widget);
470
471   attributes.window_type = GDK_WINDOW_CHILD;
472
473   if (preview->expand)
474     {
475       attributes.width = widget->allocation.width;
476       attributes.height = widget->allocation.height;
477     }
478   else
479     {
480       attributes.width = MIN (widget->requisition.width, widget->allocation.width);
481       attributes.height = MIN (widget->requisition.height, widget->allocation.height);
482     }
483
484   attributes.x = widget->allocation.x + (widget->allocation.width - attributes.width) / 2;
485   attributes.y = widget->allocation.y + (widget->allocation.height - attributes.height) / 2;;
486
487   attributes.wclass = GDK_INPUT_OUTPUT;
488   attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
489   attributes_mask = GDK_WA_X | GDK_WA_Y;
490
491   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
492   gdk_window_set_user_data (widget->window, widget);
493
494   widget->style = gtk_style_attach (widget->style, widget->window);
495   gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
496 }
497
498 static void   
499 gtk_preview_size_allocate (GtkWidget        *widget,
500                            GtkAllocation    *allocation)
501 {
502   GtkPreview *preview;
503   gint width, height;
504
505   g_return_if_fail (GTK_IS_PREVIEW (widget));
506
507   preview = GTK_PREVIEW (widget);
508   widget->allocation = *allocation;
509
510   if (GTK_WIDGET_REALIZED (widget))
511     {
512       if (preview->expand)
513         {
514           width = widget->allocation.width;
515           height = widget->allocation.height;
516         }
517       else
518         {
519           width = MIN (widget->allocation.width, widget->requisition.width);
520           height = MIN (widget->allocation.height, widget->requisition.height);
521         }
522
523       gdk_window_move_resize (widget->window,
524                               widget->allocation.x + (widget->allocation.width - width) / 2,
525                               widget->allocation.y + (widget->allocation.height - height) / 2,
526                               width, height);
527     }
528 }
529
530 static gint
531 gtk_preview_expose (GtkWidget      *widget,
532                     GdkEventExpose *event)
533 {
534   GtkPreview *preview;
535   gint width, height;
536
537   g_return_val_if_fail (GTK_IS_PREVIEW (widget), FALSE);
538   g_return_val_if_fail (event != NULL, FALSE);
539
540   if (GTK_WIDGET_DRAWABLE (widget))
541     {
542       preview = GTK_PREVIEW (widget);
543       
544       gdk_window_get_size (widget->window, &width, &height);
545
546       gtk_preview_put (GTK_PREVIEW (widget),
547                        widget->window, widget->style->black_gc,
548                        event->area.x - (width - preview->buffer_width)/2,
549                        event->area.y - (height - preview->buffer_height)/2,
550                        event->area.x, event->area.y,
551                        event->area.width, event->area.height);
552     }
553   
554   return FALSE;
555 }
556
557 static void
558 gtk_preview_make_buffer (GtkPreview *preview)
559 {
560   GtkWidget *widget;
561   gint width;
562   gint height;
563
564   g_return_if_fail (GTK_IS_PREVIEW (preview));
565
566   widget = GTK_WIDGET (preview);
567
568   if (preview->expand &&
569       (widget->allocation.width != 0) &&
570       (widget->allocation.height != 0))
571     {
572       width = widget->allocation.width;
573       height = widget->allocation.height;
574     }
575   else
576     {
577       width = widget->requisition.width;
578       height = widget->requisition.height;
579     }
580
581   if (!preview->buffer ||
582       (preview->buffer_width != width) ||
583       (preview->buffer_height != height))
584     {
585       if (preview->buffer)
586         g_free (preview->buffer);
587
588       preview->buffer_width = width;
589       preview->buffer_height = height;
590
591       preview->rowstride = (preview->buffer_width * preview->bpp + 3) & -4;
592       preview->buffer = g_new0 (guchar,
593                                 preview->buffer_height *
594                                 preview->rowstride);
595     }
596 }
597
598 /* This is used for implementing gamma. */
599 static void
600 gtk_fill_lookup_array (guchar *array)
601 {
602   double one_over_gamma;
603   double ind;
604   int val;
605   int i;
606
607   one_over_gamma = 1.0 / preview_class->info.gamma;
608
609   for (i = 0; i < 256; i++)
610     {
611       ind = (double) i / 255.0;
612       val = (int) (255 * pow (ind, one_over_gamma));
613       array[i] = val;
614     }
615 }
616
617 #define __GTK_PREVIEW_C__
618 #include "gtkaliasdef.c"