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