~ubuntu-branches/ubuntu/karmic/sanduhr/karmic

« back to all changes in this revision

Viewing changes to gob/sand-window.gob

  • Committer: Bazaar Package Importer
  • Author(s): Jochen Voss
  • Date: 2002-04-12 16:33:03 UTC
  • Revision ID: james.westby@ubuntu.com-20020412163303-xn0v3utm5xcyux60
Tags: upstream-1.0
ImportĀ upstreamĀ versionĀ 1.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* sand-window.gob - Sand window widget implementation
 
2
 *
 
3
 * Copyright (C) 1999, 2000  Jochen Voss.
 
4
 *
 
5
 * $Id: sand-window.gob,v 1.10 2002/01/12 14:12:49 voss Rel $ */
 
6
 
 
7
%headertop{
 
8
#include <gnome.h>
 
9
#include <libgnomeui/gnome-canvas.h>
 
10
%}
 
11
 
 
12
%{
 
13
#include "locate.h"
 
14
#include "../pixmaps/icon24.xbm"
 
15
 
 
16
static double
 
17
mask_get_value (unsigned char *source, int width, int height, int i, int j)
 
18
{
 
19
  int  jj = j+0.5*ABS(width/2-i);
 
20
 
 
21
  if (jj >= height)  return 0;
 
22
  return  source[jj*width+i]/255.0;
 
23
}
 
24
 
 
25
static void
 
26
mask_set_value (unsigned char *target, unsigned char *source, double x,
 
27
                int width, int height, int i, int j)
 
28
{
 
29
  int  jj = j+0.5*ABS(width/2-i);
 
30
 
 
31
  if (jj >= height)  return;
 
32
  target[jj*width+i] = x*source[jj*width+i];
 
33
}
 
34
%}
 
35
 
 
36
class Sand:Window from Gtk:Window {
 
37
  public int width;
 
38
  public int height;
 
39
 
 
40
  public gboolean decorations;
 
41
  argument BOOL decorations
 
42
    set { self->decorations = ARG; set_decorations (self); } 
 
43
    get { ARG = self->decorations; };
 
44
 
 
45
  public GnomeWinLayer layer = WIN_LAYER_NORMAL;
 
46
 
 
47
  public GtkWidget *canvas;
 
48
  public GnomeCanvasItem *back;
 
49
  public GnomeCanvasItem *front;
 
50
  public GnomeCanvasItem *mid;
 
51
  public GdkImlibImage *sand;
 
52
 
 
53
  public guint8 r;              /* The sand's color */
 
54
  public guint8 g;
 
55
  public guint8 b;
 
56
 
 
57
  public double ratio;          /* The elapsed time: 0.0=start, 1.0=end */
 
58
 
 
59
  protected unsigned char *mask;
 
60
  protected double A;
 
61
  protected double B;
 
62
  protected double fill;
 
63
 
 
64
 
 
65
  /**********************************************************************
 
66
   * widget class implementation
 
67
   */
 
68
 
 
69
  private void
 
70
  create_shape (self, int image_width, int image_height)
 
71
  {
 
72
    GdkImlibImage *im;
 
73
    GdkBitmap *mask;
 
74
    GdkBitmap *im_mask;
 
75
    GdkGC *mgc;
 
76
    GdkColor c;
 
77
 
 
78
    /* Create the initial mask and clear it */
 
79
    mask = gdk_pixmap_new (GTK_WIDGET (self)->window,
 
80
                           image_width, image_height, 1);
 
81
 
 
82
    mgc = gdk_gc_new (mask);
 
83
    c.pixel = 0;
 
84
    gdk_gc_set_foreground (mgc, &c);
 
85
    gdk_draw_rectangle (mask, mgc, TRUE, 0, 0, image_width, image_height);
 
86
 
 
87
    c.pixel = 1;
 
88
    gdk_gc_set_foreground (mgc, &c);
 
89
 
 
90
    /* Paint the mask of the image */
 
91
    im = GNOME_CANVAS_IMAGE (self->back)->im;
 
92
    gdk_imlib_render (im, image_width, image_height);
 
93
    im_mask = gdk_imlib_move_mask (im);
 
94
 
 
95
    if (im_mask) {
 
96
      gdk_draw_pixmap (mask, mgc, im_mask,
 
97
                       0, 0, 0, 0, image_width, image_height);
 
98
      gdk_imlib_free_bitmap (im_mask);
 
99
    } else {
 
100
      gdk_draw_rectangle (mask, mgc, TRUE,
 
101
                          0, 0, image_width, image_height);
 
102
    }
 
103
 
 
104
    if (!GTK_WIDGET_REALIZED (self))
 
105
      gtk_widget_realize (GTK_WIDGET (self));
 
106
 
 
107
    gtk_widget_shape_combine_mask (GTK_WIDGET (self), mask, 0, 0);
 
108
    gdk_bitmap_unref (mask);
 
109
    gdk_gc_unref (mgc);
 
110
  }
 
111
  
 
112
  override (Gtk:Widget) void
 
113
  size_request (GtkWidget *widget (check null), GtkRequisition *requisition)
 
114
  {
 
115
    SandWindow *self;
 
116
    GtkArg args[2];
 
117
 
 
118
    self = SAND_WINDOW (widget);
 
119
    
 
120
    /* Get size of icon image */
 
121
    args[0].name = "width";
 
122
    args[1].name = "height";
 
123
    gtk_object_getv (GTK_OBJECT (self->back), 2, args);
 
124
    requisition->width = GTK_VALUE_DOUBLE (args[0]);
 
125
    requisition->height = GTK_VALUE_DOUBLE (args[1]);
 
126
  }
 
127
 
 
128
  private void
 
129
  drop_handler (GtkWidget        *widget, 
 
130
                GdkDragContext   *context,
 
131
                gint              x,
 
132
                gint              y,
 
133
                GtkSelectionData *selection_data,
 
134
                guint             info,
 
135
                guint             time,
 
136
                gpointer          data)
 
137
  {
 
138
    SandWindow *sand_window = SAND_WINDOW (widget);
 
139
    guint16 *vals;
 
140
    gdouble  r, g, b;
 
141
 
 
142
    if (selection_data->length < 0) return;
 
143
 
 
144
    if ((selection_data->format != 16) || (selection_data->length != 8)) {
 
145
      g_warning ("Received invalid color data");
 
146
      return;
 
147
    }
 
148
  
 
149
    vals = (guint16 *)selection_data->data;
 
150
 
 
151
    r = (gdouble)vals[0] / 0xffff;
 
152
    g = (gdouble)vals[1] / 0xffff;
 
153
    b = (gdouble)vals[2] / 0xffff;
 
154
  
 
155
    set_color (sand_window, r*255, g*255, b*255);
 
156
  }
 
157
 
 
158
  override (Gtk:Widget) void
 
159
  realize (GtkWidget *widget (check null))
 
160
  {
 
161
    GdkPixmap *icon;
 
162
    static const GtkTargetEntry targets[] = {
 
163
      { "application/x-color", 0 }
 
164
    };
 
165
 
 
166
    g_return_if_fail (SAND_IS_WINDOW (widget));
 
167
 
 
168
    PARENT_HANDLER (widget);
 
169
 
 
170
    /* Set the proper GNOME hints */
 
171
    gnome_win_hints_init ();
 
172
    icon = gdk_bitmap_create_from_data (widget->window, icon24_bits,
 
173
                                        icon24_width, icon24_height);
 
174
    gdk_window_set_icon (widget->window, NULL, icon, NULL);
 
175
    gdk_window_set_functions (widget->window, GDK_FUNC_MOVE|GDK_FUNC_CLOSE);
 
176
    set_decorations (SAND_WINDOW (widget));
 
177
    if (gnome_win_hints_wm_exists ()) {
 
178
      gnome_win_hints_set_hints(widget, WIN_HINTS_DO_NOT_COVER);
 
179
      gnome_win_hints_set_layer (widget, SAND_WINDOW (widget)->layer);
 
180
    }
 
181
 
 
182
    gtk_drag_dest_set (widget, GTK_DEST_DEFAULT_ALL,
 
183
                       targets, 1, GDK_ACTION_COPY);
 
184
  
 
185
    gtk_signal_connect (GTK_OBJECT (widget),
 
186
                        "drag_data_received",
 
187
                        GTK_SIGNAL_FUNC (drop_handler),
 
188
                        NULL);
 
189
  }
 
190
 
 
191
  private void
 
192
  size_allocate_handler (GtkWidget *widget, GtkAllocation *allocation,
 
193
                         gpointer data)
 
194
  {
 
195
    SandWindow *self;
 
196
 
 
197
    self = SAND_WINDOW (widget);
 
198
    gnome_canvas_set_scroll_region (GNOME_CANVAS(self->canvas),
 
199
                                    0, 0,
 
200
                                    allocation->width, allocation->height);
 
201
    create_shape (self, allocation->width, allocation->height);
 
202
  }
 
203
 
 
204
  init (swindow) {
 
205
    char *fname;
 
206
    GdkImlibImage *back, *sand, *front;
 
207
  
 
208
    /* Set the window policy */
 
209
    gtk_window_set_policy (GTK_WINDOW (swindow), FALSE, FALSE, TRUE);
 
210
    gtk_window_set_wmclass (GTK_WINDOW (swindow),
 
211
                            "sandUhrTimer", "SandUhrTimer");
 
212
 
 
213
    /* Create the canvas */
 
214
    gtk_widget_push_visual (gdk_rgb_get_visual ());
 
215
    gtk_widget_push_colormap (gdk_rgb_get_cmap ());
 
216
    swindow->canvas = gnome_canvas_new_aa ();
 
217
    gtk_widget_pop_colormap ();
 
218
    gtk_widget_pop_visual ();
 
219
 
 
220
    gtk_container_add (GTK_CONTAINER (swindow), swindow->canvas);
 
221
    gtk_widget_show (swindow->canvas);
 
222
 
 
223
    /* Create the image items */
 
224
    fname = get_pixmap_file ("back.png");
 
225
    back = gdk_imlib_load_image (fname);
 
226
    g_free (fname);
 
227
    swindow->back
 
228
      = gnome_canvas_item_new(gnome_canvas_root(GNOME_CANVAS(swindow->canvas)),
 
229
                              gnome_canvas_image_get_type (),
 
230
                              "image", back,
 
231
                              "width", (double) back->rgb_width,
 
232
                              "height", (double) back->rgb_height,
 
233
                              "anchor", GTK_ANCHOR_NW,
 
234
                              NULL);
 
235
  
 
236
    fname = get_pixmap_file ("mask.png");
 
237
    sand = gnome_canvas_load_alpha (fname);
 
238
    g_free (fname);
 
239
    swindow->sand = sand;
 
240
    swindow->mask = g_malloc (sand->rgb_width*sand->rgb_height);
 
241
    memcpy (swindow->mask, sand->alpha_data, sand->rgb_width*sand->rgb_height);
 
242
    init_sand (swindow);
 
243
    swindow->mid
 
244
      = gnome_canvas_item_new (gnome_canvas_root (GNOME_CANVAS(swindow->canvas)),
 
245
                               gnome_canvas_image_get_type (),
 
246
                               "image", sand,
 
247
                               "width", (double) sand->rgb_width,
 
248
                               "height", (double) sand->rgb_height,
 
249
                               "anchor", GTK_ANCHOR_NW,
 
250
                               NULL);
 
251
 
 
252
    fname = get_pixmap_file ("front.png");
 
253
    front = gnome_canvas_load_alpha (fname);
 
254
    g_free (fname);
 
255
    swindow->front
 
256
      = gnome_canvas_item_new(gnome_canvas_root(GNOME_CANVAS(swindow->canvas)),
 
257
                              gnome_canvas_image_get_type (),
 
258
                              "anchor", GTK_ANCHOR_NW,
 
259
                              "image", front,
 
260
                              "width", (double) front->rgb_width,
 
261
                              "height", (double) front->rgb_height,
 
262
                              NULL);
 
263
 
 
264
    gtk_signal_connect (GTK_OBJECT (swindow), "size_allocate",
 
265
                        (GtkSignalFunc) size_allocate_handler,
 
266
                        NULL);
 
267
 
 
268
    swindow->ratio = 0.0;
 
269
    swindow->r = 0;
 
270
    swindow->g = 0;
 
271
    swindow->b = 0;
 
272
 
 
273
    swindow->decorations = FALSE;
 
274
  }
 
275
 
 
276
  override (Gtk:Object) void
 
277
  destroy (GtkObject *object (check null))
 
278
  {
 
279
    SandWindow *self;
 
280
    
 
281
    self = SAND_WINDOW (object);
 
282
    g_free (self->mask);
 
283
    self->mask = NULL;
 
284
    PARENT_HANDLER (object);
 
285
  }
 
286
  
 
287
  public GtkWidget *
 
288
  new (void)
 
289
  {
 
290
    GtkWidget *ret;
 
291
    
 
292
    ret = GTK_WIDGET (GET_NEW);
 
293
    return  ret;
 
294
  }
 
295
 
 
296
  /**********************************************************************
 
297
   * window manager interaction
 
298
   */
 
299
 
 
300
  private void
 
301
  set_decorations (self)
 
302
  {
 
303
    GtkWidget *widget = GTK_WIDGET (self);
 
304
    gboolean  fix_broken_wm;
 
305
    gint x, y;
 
306
 
 
307
    if (! GTK_WIDGET_REALIZED (self))  return;
 
308
 
 
309
    /* work around broken window managers */
 
310
    fix_broken_wm = GTK_WIDGET_MAPPED (self);
 
311
    if (fix_broken_wm) {
 
312
      gdk_window_get_position (widget->window, &x, &y);
 
313
      gdk_window_hide (widget->window);
 
314
    }
 
315
 
 
316
    if (self->decorations) {
 
317
      gdk_window_set_decorations (widget->window, GDK_DECOR_TITLE);
 
318
    } else {
 
319
      gdk_window_set_decorations (widget->window, 0);
 
320
    }
 
321
 
 
322
    if (fix_broken_wm) {
 
323
      gdk_window_show (widget->window);
 
324
      gdk_window_move (widget->window, x, y);
 
325
    }
 
326
  }
 
327
 
 
328
  public GnomeWinLayer
 
329
  get_layer (self)
 
330
  {
 
331
    if (gnome_win_hints_wm_exists ()) {
 
332
      return  gnome_win_hints_get_layer (GTK_WIDGET(self));
 
333
    }
 
334
    return  -1;
 
335
  }
 
336
 
 
337
  public void
 
338
  set_layer (self, GnomeWinLayer layer)
 
339
  {
 
340
    self->layer = layer;
 
341
    if (GTK_WIDGET_REALIZED (self) && gnome_win_hints_wm_exists ()) {
 
342
      gnome_win_hints_set_layer (GTK_WIDGET(self), layer);
 
343
    }
 
344
  }
 
345
 
 
346
  /**********************************************************************
 
347
   * handle the sand
 
348
   */
 
349
  
 
350
  private void
 
351
  init_color (self, guint8 r, guint8 g, guint8 b)
 
352
  /* Set the sand color to the RGB value (R,G,B).  */
 
353
  {
 
354
    GdkImlibImage *sand = self->sand;
 
355
    int  i;
 
356
 
 
357
    for (i=0; i<sand->rgb_width*sand->rgb_height; ++i) {
 
358
      sand->rgb_data [3*i] = r;
 
359
      sand->rgb_data [3*i+1] = g;
 
360
      sand->rgb_data [3*i+2] = b;
 
361
    }
 
362
  }
 
363
  
 
364
  private void
 
365
  set_mask (self, double q)
 
366
  {
 
367
    GdkImlibImage *sand = self->sand;
 
368
    int  width = sand->rgb_width;
 
369
    int  height = sand->rgb_height;
 
370
    double  a, rest;
 
371
    int  i, j;
 
372
 
 
373
    if (! self->mask)  return;
 
374
 
 
375
    /* upper chamber */
 
376
    a = 0;
 
377
    rest = self->A-(1-q)*self->fill;
 
378
    for (j=0; j<height/2; ++j) {
 
379
      double  current = 0;
 
380
 
 
381
      if (a >= rest) {
 
382
        /* row is completely filled */
 
383
        for (i=0; i<width; ++i) {
 
384
          sand->alpha_data[j*width+i] = self->mask[j*width+i];
 
385
        }
 
386
      } else {
 
387
        for (i=0; i<width; ++i)  current += self->mask[j*width+i]/255.0;
 
388
        a += current;
 
389
        if (a >= rest) {
 
390
          /* row is partially filled */
 
391
          double  x = (a - rest)/current;
 
392
          for (i=0; i<width; ++i) {
 
393
            sand->alpha_data[j*width+i] = x*self->mask[j*width+i];
 
394
          }
 
395
        } else {
 
396
          /* row is completely empty */
 
397
          for (i=0; i<width; ++i) {
 
398
            sand->alpha_data[j*width+i] = 0;
 
399
          }
 
400
        }
 
401
      }
 
402
    }
 
403
 
 
404
    /* lower chamber */
 
405
    a = 0;
 
406
    rest = self->B-q*self->fill;
 
407
    for (j=height/2; j<height; ++j) {
 
408
      double  current = 0;
 
409
 
 
410
      if (a >= rest) {
 
411
        /* row is completely filled */
 
412
        for (i=0; i<width; ++i) {
 
413
          mask_set_value (sand->alpha_data, self->mask, 1,
 
414
                          width, height, i, j);
 
415
        }
 
416
      } else {
 
417
        for (i=0; i<width; ++i) {
 
418
          current += mask_get_value (self->mask, width, height, i, j);
 
419
        }
 
420
        a += current;
 
421
        if (a >= rest) {
 
422
          /* row is partially filled */
 
423
          double  x = (a - rest)/current;
 
424
          for (i=0; i<width; ++i) {
 
425
            mask_set_value (sand->alpha_data, self->mask, x,
 
426
                            width, height, i, j);
 
427
          }
 
428
        } else {
 
429
          /* row is completely empty */
 
430
          for (i=0; i<width; ++i) {
 
431
            mask_set_value (sand->alpha_data, self->mask, 0,
 
432
                            width, height, i, j);
 
433
          }
 
434
          if (q<0.995) sand->alpha_data[j*width+width/2] = 48;
 
435
        }
 
436
      }
 
437
    }
 
438
  }
 
439
 
 
440
  private void 
 
441
  redraw (self)
 
442
  {
 
443
    gtk_object_set (GTK_OBJECT (self->mid),
 
444
                    "image", self->sand,
 
445
                    NULL);
 
446
  }
 
447
 
 
448
  private void
 
449
  refill (self)
 
450
  {
 
451
    init_color (self, self->r, self->g, self->b);
 
452
    set_mask (self, self->ratio);
 
453
    redraw (self);
 
454
  }
 
455
 
 
456
  private void
 
457
  init_sand (self)
 
458
  {
 
459
    GdkImlibImage *sand = self->sand;
 
460
    double  A=0, B=0, fill;
 
461
    int  i, mid;
 
462
 
 
463
    g_assert (self->mask);
 
464
    init_color (self, self->r, self->g, self->b);
 
465
 
 
466
    mid = sand->rgb_height/2;
 
467
    for (i=0; i<sand->rgb_width*mid; ++i) {
 
468
      A += self->mask [i]/255.0;
 
469
    }
 
470
    for (i=sand->rgb_width*mid; i<sand->rgb_width*sand->rgb_height; ++i) {
 
471
      B += self->mask [i]/255.0;
 
472
    }
 
473
 
 
474
    fill = 0.9*MIN(A,B);
 
475
    g_assert (fill >= 50);
 
476
    self->A = A;
 
477
    self->B = B;
 
478
    self->fill = fill;
 
479
  
 
480
    /* TODO: do the remaining stuff */
 
481
    self->ratio = 1;
 
482
    set_mask (self, 0);
 
483
  }
 
484
 
 
485
  /**********************************************************************
 
486
   * user interface
 
487
   */
 
488
  
 
489
  public void
 
490
  get_color (self, guint8 *r, guint8 *g, guint8 *b)
 
491
  {
 
492
    *r = self->r;
 
493
    *g = self->g;
 
494
    *b = self->b;
 
495
  }
 
496
 
 
497
  public void
 
498
  set_color (self, guint8 r, guint8 g, guint8 b)
 
499
  {
 
500
    self->r = r;
 
501
    self->g = g;
 
502
    self->b = b;
 
503
    refill (self);
 
504
  }
 
505
 
 
506
  public void
 
507
  flood (self, double q)
 
508
  {
 
509
    if (q <= 0)  q = 0;
 
510
    if (q >= 1)  q = 1;
 
511
    
 
512
    self->ratio = q;
 
513
    refill (self);
 
514
  }
 
515
}