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