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