]> git.karo-electronics.de Git - gbdfed.git/blob - gectrl.c
Fixup several compile faults due to changes in recent distributions,
[gbdfed.git] / gectrl.c
1 /*
2  * Copyright 2008 Department of Mathematical Sciences, New Mexico State University
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * DEPARTMENT OF MATHEMATICAL SCIENCES OR NEW MEXICO STATE UNIVERSITY BE
18  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
19  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  */
22
23 #include <gtk/gtklabel.h>
24 #include "gectrl.h"
25 #include "gectrlbmaps.h"
26
27 #ifdef ENABLE_NLS
28 #include <libintl.h>
29 #define _(s) dgettext(GETTEXT_PACKAGE,s)
30 #else
31 #define _(s) (s)
32 #endif
33
34 /*
35  * All the pixmaps are 16x16.
36  */
37 #define BMAP_DIM 16
38
39 #define GEC_TOGGLE_SIZE 38
40 #define GEC_BUTTON_SIZE 33
41
42 /*
43  * Properties of this widget.
44  */
45 enum {
46     PROP_0 = 0,
47     TIP_LABEL,
48     GLYPH_IMAGE,
49     COLOR_LIST
50 };
51
52 /*
53  * Signals this widget emits.
54  */
55 enum {
56     ACTIVATE = 0
57 };
58
59 static GtkDrawingAreaClass *parent_class = 0;
60 static guint gecontrol_signals[ACTIVATE + 1];
61
62 #define GEC_DRAW_TOGGLE     0
63 #define GEC_MOVE_TOGGLE     1
64 #define GEC_COPY_TOGGLE     2
65 #define GEC_FLIPH_BUTTON    3
66 #define GEC_FLIPV_BUTTON    4
67 #define GEC_SHEAR_BUTTON    5
68 #define GEC_RLEFT_BUTTON    6
69 #define GEC_RRIGHT_BUTTON   7
70 #define GEC_ROTATE_BUTTON   8
71 #define GEC_ULEFT_BUTTON    9
72 #define GEC_UP_BUTTON       10
73 #define GEC_URIGHT_BUTTON   11
74 #define GEC_LEFT_BUTTON     12
75 #define GEC_RIGHT_BUTTON    13
76 #define GEC_DLEFT_BUTTON    14
77 #define GEC_DOWN_BUTTON     15
78 #define GEC_DRIGHT_BUTTON   16
79 #define GEC_GLYPH_IMAGE     17
80
81 /*
82  * These are encoded in UTF-8.
83  */
84 static guchar *help_strings[18] = {
85     (guchar *) "Draw",
86     (guchar *) "Move",
87     (guchar *) "Copy",
88     (guchar *) "Flip Horizontally",
89     (guchar *) "Flip Vertically",
90     (guchar *) "Shear ±45°",
91     (guchar *) "Rotate -90°",
92     (guchar *) "Rotate +90°",
93     (guchar *) "Rotate ±359°",
94     (guchar *) "Shift Up+Left",
95     (guchar *) "Shift Up",
96     (guchar *) "Shift Up+Right",
97     (guchar *) "Shift Left",
98     (guchar *) "Shift Right",
99     (guchar *) "Shift Down+Left",
100     (guchar *) "Shift Down",
101     (guchar *) "Shift Down+Right",
102     (guchar *) "Glyph Image",
103 };
104
105 /*
106  * Position all the buttons in the space provided.
107  */
108 static void
109 gecontrol_position_buttons(GtkWidget *w)
110 {
111     GEControl *ge = GECONTROL(w);
112     gint x, y, sx, sy, ix, dx, i, j, v, wd, ht;
113     GdkPoint points[5];
114
115     dx = 0;
116
117     /*
118      * Determine the starting x and y coordinates, centered in the
119      * window. Modify later to make room for the color strip on the left side
120      * of the window.
121      */
122
123     sx = (w->allocation.width >> 1) - (((GEC_TOGGLE_SIZE * 3) + 6) >> 1);
124     v = (GEC_TOGGLE_SIZE + (GEC_BUTTON_SIZE * 5)) + 15;
125
126     if (ge->gimage != 0) {
127         /*
128          * The addition of 7 includes a space of 3 between the glyph image and
129          * the row of toggles, and 2 pixels on the top and bottom of the glyph
130          * image for a box that will be drawn around it and a single pixel
131          * between the edge of the box and the actual glyph image.
132          */
133         v += ge->gimage->height + 7;
134
135         /*
136          * Calculate a horizontal offset for the toggles and buttons in the
137          * case of 8 bits per pixel. The color selection square is 128x128 so
138          * everything else needs to move over to accomodate it.
139          */
140         if (ge->gimage->bpp == 8 && sx < 128 + 8)
141           dx = (128 + 8) - sx;
142     }
143
144     sx += dx;
145     sy = (w->allocation.height >> 1) - (v >> 1);
146
147     /*
148      * Position the glyph image first if one is present.
149      */
150     if (ge->gimage != 0) {
151         /*
152          * The addition of 2 is for the box and an empty row around the glyph
153          * image.
154          */
155         ix = ((w->allocation.width >> 1)-((ge->gimage->width + 2) >> 1)) + dx;
156
157         if (ge->buttons[GEC_GLYPH_IMAGE].region == NULL) {
158             /* Top left. */
159             points[0].x = points[4].x = ix;
160             points[0].y = points[4].y = sy;
161             /* Top right. */
162             points[1].x = ix + ge->gimage->width + 4;
163             points[1].y = points[0].y;
164             /* Bottom right. */
165             points[2].x = points[1].x;
166             points[2].y = sy + ge->gimage->height + 4;
167             /* Bottom left. */
168             points[3].x = points[0].x;
169             points[3].y = points[2].y;
170             ge->buttons[GEC_GLYPH_IMAGE].region =
171                 gdk_region_polygon(points, 4, GDK_WINDING_RULE);
172         } else
173           gdk_region_offset(ge->buttons[GEC_GLYPH_IMAGE].region,
174                             ix - ge->buttons[GEC_GLYPH_IMAGE].x,
175                             sy - ge->buttons[GEC_GLYPH_IMAGE].y);
176
177         ge->gimage->x = ge->buttons[GEC_GLYPH_IMAGE].x = ix;
178         ge->gimage->y = ge->buttons[GEC_GLYPH_IMAGE].y = sy;
179
180         sy += ge->gimage->height + 7;
181     }
182
183     x = sx;
184     y = sy;
185
186     /*
187      * Prep the points for creating regions for the toggle buttons.
188      */
189     points[0].x = points[4].x = x;
190     points[0].y = points[4].y = y + (GEC_TOGGLE_SIZE >> 1);
191     points[1].x = x + (GEC_TOGGLE_SIZE >> 1);
192     points[1].y = y;
193     points[2].x = x + GEC_TOGGLE_SIZE;
194     points[2].y = points[0].y;
195     points[3].x = points[1].x;
196     points[3].y = y + GEC_TOGGLE_SIZE;
197
198     /*
199      * Position the toggle buttons.
200      */
201     for (i = 0; i < GEC_FLIPH_BUTTON; i++) {
202         if (ge->buttons[i].region == NULL)
203           ge->buttons[i].region =
204               gdk_region_polygon(points, 4, GDK_WINDING_RULE);
205         else
206           gdk_region_offset(ge->buttons[i].region,
207                             x - ge->buttons[i].x, y - ge->buttons[i].y);
208
209         ge->buttons[i].x = x;
210         ge->buttons[i].y = y;
211
212         x += GEC_TOGGLE_SIZE + 3;
213
214         for (j = 0; j < 5; j++)
215           points[j].x += GEC_TOGGLE_SIZE + 3;
216     }
217
218     /*
219      * Recalculate the starting x position based on the button size instead
220      * of the toggle size.
221      */
222     sx = ((w->allocation.width >> 1)-(((GEC_BUTTON_SIZE * 3) + 6) >> 1)) + dx;
223
224     y += GEC_TOGGLE_SIZE + 3;
225
226     /*
227      * Now set up the points for the buttons.
228      */
229     points[0].x = sx;
230     points[0].y = y;
231     points[1].x = sx + GEC_BUTTON_SIZE;
232     points[1].y = points[0].y;
233     points[2].x = points[1].x;
234     points[2].y = y + GEC_BUTTON_SIZE;
235     points[3].x = points[0].x;
236     points[3].y = points[2].y;
237
238     /*
239      * Position the first row of buttons.
240      */
241     for (x = sx; i < GEC_RLEFT_BUTTON; i++) {
242         if (ge->buttons[i].region == NULL)
243           ge->buttons[i].region =
244               gdk_region_polygon(points, 4, GDK_WINDING_RULE);
245         else
246           gdk_region_offset(ge->buttons[i].region,
247                             x - ge->buttons[i].x, y - ge->buttons[i].y);
248         ge->buttons[i].x = x;
249         ge->buttons[i].y = y;
250
251         x += GEC_BUTTON_SIZE + 3;
252
253         for (j = 0; j < 4; j++)
254           points[j].x += GEC_BUTTON_SIZE + 3;
255     }
256
257     /*
258      * Reset the x coordinate for the regions.
259      */
260     points[0].x = points[3].x = sx;
261     points[1].x = points[2].x = sx + GEC_BUTTON_SIZE;
262
263     y += GEC_BUTTON_SIZE + 3;
264
265     for (j = 0; j < 4; j++)
266       points[j].y += GEC_BUTTON_SIZE + 3;
267
268     /*
269      * Position second row of buttons.
270      */
271     for (x = sx; i < GEC_ULEFT_BUTTON; i++) {
272         if (ge->buttons[i].region == NULL)
273           ge->buttons[i].region =
274               gdk_region_polygon(points, 4, GDK_WINDING_RULE);
275         else
276           gdk_region_offset(ge->buttons[i].region,
277                             x - ge->buttons[i].x, y - ge->buttons[i].y);
278         ge->buttons[i].x = x;
279         ge->buttons[i].y = y;
280
281         x += GEC_BUTTON_SIZE + 3;
282
283         for (j = 0; j < 4; j++)
284           points[j].x += GEC_BUTTON_SIZE + 3;
285     }
286
287     /*
288      * Reset the x coordinate for the regions.
289      */
290     points[0].x = points[3].x = sx;
291     points[1].x = points[2].x = sx + GEC_BUTTON_SIZE;
292
293     y += GEC_BUTTON_SIZE + 3;
294
295     for (j = 0; j < 4; j++)
296       points[j].y += GEC_BUTTON_SIZE + 3;
297
298     /*
299      * Position third row of buttons.
300      */
301     for (x = sx; i < GEC_LEFT_BUTTON; i++) {
302         if (ge->buttons[i].region == NULL)
303           ge->buttons[i].region =
304               gdk_region_polygon(points, 4, GDK_WINDING_RULE);
305         else
306           gdk_region_offset(ge->buttons[i].region,
307                             x - ge->buttons[i].x, y - ge->buttons[i].y);
308         ge->buttons[i].x = x;
309         ge->buttons[i].y = y;
310
311         x += GEC_BUTTON_SIZE + 3;
312
313         for (j = 0; j < 4; j++)
314           points[j].x += GEC_BUTTON_SIZE + 3;
315     }
316
317     /*
318      * Reset the x coordinate for the regions.
319      */
320     points[0].x = points[3].x = sx;
321     points[1].x = points[2].x = sx + GEC_BUTTON_SIZE;
322
323     x = sx;
324     y += GEC_BUTTON_SIZE + 3;
325
326     for (j = 0; j < 4; j++)
327       points[j].y += GEC_BUTTON_SIZE + 3;
328
329     /*
330      * Set the coordinates of the LEFT and RIGHT buttons.
331      */
332     if (ge->buttons[i].region == NULL)
333       ge->buttons[i].region =
334           gdk_region_polygon(points, 4, GDK_WINDING_RULE);
335     else
336       gdk_region_offset(ge->buttons[i].region,
337                         x - ge->buttons[i].x, y - ge->buttons[i].y);
338     ge->buttons[i].x = x;
339     ge->buttons[i++].y = y;
340
341     x += (GEC_BUTTON_SIZE + 3) * 2;
342
343     for (j = 0; j < 4; j++)
344       points[j].x += (GEC_BUTTON_SIZE + 3) * 2;
345
346     if (ge->buttons[i].region == NULL)
347       ge->buttons[i].region =
348           gdk_region_polygon(points, 4, GDK_WINDING_RULE);
349     else
350       gdk_region_offset(ge->buttons[i].region,
351                         x - ge->buttons[i].x, y - ge->buttons[i].y);
352     ge->buttons[i].x = x;
353     ge->buttons[i++].y = y;
354
355     /*
356      * Reset the x coordinate for the regions.
357      */
358     points[0].x = points[3].x = sx;
359     points[1].x = points[2].x = sx + GEC_BUTTON_SIZE;
360
361     y += GEC_BUTTON_SIZE + 3;
362
363     for (j = 0; j < 4; j++)
364       points[j].y += GEC_BUTTON_SIZE + 3;
365
366     for (x = sx; i < GEC_GLYPH_IMAGE; i++) {
367         if (ge->buttons[i].region == NULL)
368           ge->buttons[i].region =
369               gdk_region_polygon(points, 4, GDK_WINDING_RULE);
370         else
371           gdk_region_offset(ge->buttons[i].region,
372                             x - ge->buttons[i].x, y - ge->buttons[i].y);
373         ge->buttons[i].x = x;
374         ge->buttons[i].y = y;
375
376         x += GEC_BUTTON_SIZE + 3;
377
378         for (j = 0; j < 4; j++)
379           points[j].x += GEC_BUTTON_SIZE + 3;
380     }
381
382     /*
383      * Now position the color spots if they are needed.
384      */
385
386     if (ge->gimage && ge->gimage->bpp > 1) {
387         if (ge->gimage->bpp == 2 || ge->gimage->bpp == 4) {
388             /*
389              * The starting horizontal position is 1/2 way between the left
390              * edge of the window and the left edge of the buttons. The
391              * starting vertical position is centered on the left edge of the
392              * buttons.
393              */
394             sx = (sx >> 1) - (8 >> 1);
395             y = (8 * (1 << ge->gimage->bpp)) + ((1 << ge->gimage->bpp) - 1);
396             sy = ge->buttons[GEC_FLIPH_BUTTON].y +
397                 ((w->allocation.height-ge->buttons[GEC_FLIPH_BUTTON].y)>>1) -
398                 (y >> 1);
399             wd = 8;
400             ht = 8 * (1 << ge->gimage->bpp);
401         } else {
402             sx = (sx >> 1) - (128 >> 1);
403             sy = ge->buttons[GEC_FLIPH_BUTTON].y +
404                 ((w->allocation.height-ge->buttons[GEC_FLIPH_BUTTON].y)>>1) -
405                 (128 >> 1);
406             wd = ht = 128;
407         }
408
409         /*
410          * Initialize the points for the spot region.
411          */
412
413         /* Top left. */
414         points[0].x = points[4].x = sx;
415         points[0].y = points[4].y = sy;
416         /* Top right. */
417         points[1].x = points[0].x + wd;
418         points[1].y = points[0].y;
419         /* Bottom right. */
420         points[2].x = points[1].x;
421         points[2].y = points[1].y + ht;
422         /* Bottom left. */
423         points[3].x = points[0].x;
424         points[3].y = points[2].y;
425
426         if (ge->spot_region == NULL)
427           ge->spot_region = gdk_region_polygon(points, 4,
428                                                GDK_WINDING_RULE);
429         else
430           gdk_region_offset(ge->spot_region,
431                             sx - ge->spot.x, sy - ge->spot.y);
432
433         ge->spot.x = sx;
434         ge->spot.y = sy;
435         ge->spot.width = wd;
436         ge->spot.height = ht;
437     }
438 }
439
440 /**********************************************************************
441  *
442  * Initialization routines.
443  *
444  **********************************************************************/
445
446 static void
447 gecontrol_finalize(GObject *obj)
448 {
449     gint i;
450     GEControl *ge;
451     GEControlClass *gwc;
452
453     g_return_if_fail(obj != 0);
454     g_return_if_fail(IS_GECONTROL(obj));
455
456     /*
457      * Destroy all the regions for the buttons.
458      */
459     ge = GECONTROL(obj);
460     for (i = 0; i < 18; i++) {
461         if (ge->buttons[i].region != 0)
462           gdk_region_destroy(ge->buttons[i].region);
463         ge->buttons[i].region = 0;
464     }
465
466     /*
467      * Make sure the image is removed if it exists.
468      */
469     if (ge->gimage != 0) {
470         if (ge->gimage->bytes > 0)
471           g_free(ge->gimage->bitmap);
472         g_free(ge->gimage);
473         ge->gimage = 0;
474     }
475
476     gwc = GECONTROL_GET_CLASS(obj);
477
478     if (gwc->selgc != 0)
479       g_object_unref(G_OBJECT(gwc->selgc));
480     gwc->selgc = 0;
481
482     /*
483      * Unreference all the pixbufs that were created.
484      */
485     if (gwc->draw != 0) {
486         g_object_unref(G_OBJECT(gwc->draw));
487         g_object_unref(G_OBJECT(gwc->move));
488         g_object_unref(G_OBJECT(gwc->copy));
489         g_object_unref(G_OBJECT(gwc->fliph));
490         g_object_unref(G_OBJECT(gwc->flipv));
491         g_object_unref(G_OBJECT(gwc->shear));
492         g_object_unref(G_OBJECT(gwc->rleft));
493         g_object_unref(G_OBJECT(gwc->rright));
494         g_object_unref(G_OBJECT(gwc->rotate));
495         g_object_unref(G_OBJECT(gwc->uleft));
496         g_object_unref(G_OBJECT(gwc->up));
497         g_object_unref(G_OBJECT(gwc->uright));
498         g_object_unref(G_OBJECT(gwc->left));
499         g_object_unref(G_OBJECT(gwc->right));
500         g_object_unref(G_OBJECT(gwc->dleft));
501         g_object_unref(G_OBJECT(gwc->down));
502         g_object_unref(G_OBJECT(gwc->dright));
503
504         gwc->draw = gwc->move = gwc->copy =
505             gwc->fliph = gwc->flipv = gwc->shear =
506             gwc->rleft = gwc->rright = gwc->rotate =
507             gwc->uleft = gwc->up = gwc->uright =
508             gwc->left = gwc->right =
509             gwc->dleft = gwc->down = gwc->dright = 0;
510     }
511 }
512
513 static void
514 gecontrol_preferred_size(GtkWidget *widget, GtkRequisition *preferred)
515 {
516     GEControl *gw = GECONTROL(widget);
517     gint ht;
518
519     preferred->width = 50 + (3 * (GEC_TOGGLE_SIZE + 4)) + 4;
520     preferred->height = (GEC_TOGGLE_SIZE + 6) + ((5 * GEC_BUTTON_SIZE) + 8);
521
522     if (gw->gimage != 0) {
523         /*
524          * The addition of 10 includes a box around the glyph, a line of empty
525          * pixels between the box and the glyph image, and a space of 3 pixels
526          * above and below the glyph image.
527          */
528         preferred->height += gw->gimage->height + 10;
529
530         /*
531          * Determine the height of the color list. Each color spot is 8x8 and
532          * there is a buffer of two pixels on each side, and 2 pixels in
533          * between them vertically.
534          */
535         if (gw->gimage->bpp == 2 || gw->gimage->bpp == 4) {
536             preferred->width += 8 + 4;
537             ht = 8 * (1 << gw->gimage->bpp);
538             preferred->height = MAX(preferred->height, ht);
539         } else if (gw->gimage->bpp == 8) {
540             /*
541              * For 8 bits per pixel, the square is 8x8 spots with 16 spots per
542              * row and 16 rows. This gives 64 + 4 pixels which includes the 2
543              * empties on each side.
544              */
545             preferred->width += 128 + 4;
546             ht = 128 + 4;
547             preferred->height = MAX(preferred->height, ht);
548         }
549     }
550 }
551
552 static void
553 gecontrol_actual_size(GtkWidget *widget, GtkAllocation *actual)
554 {
555     widget->allocation = *actual;
556
557     gecontrol_position_buttons(widget);
558
559     if (GTK_WIDGET_REALIZED(widget))
560       gdk_window_move_resize(widget->window, actual->x, actual->y,
561                              actual->width, actual->height);
562 }
563
564 /*
565  * Use our own painting routines to get the look and behavior we want.
566  */
567 static void
568 gecontrol_paint_diamond(GtkStyle *style, GdkWindow *win, GtkStateType state,
569                         GdkRectangle *area, gint x, gint y,
570                         gint width, gint height)
571 {
572     GdkSegment left[6], right[6];
573
574     /*
575      * Start the left segments at the top. Go from outer to inner.
576      */
577
578     /* Outer. */
579     left[0].x1 = x + (width >> 1);
580     left[0].y1 = y;
581     left[0].x2 = x;
582     left[0].y2 = y + (width >> 1);
583     left[1].x1 = left[0].x2;
584     left[1].y1 = left[0].y2;
585     left[1].x2 = x + (width >> 1);
586     left[1].y2 = y + height;
587
588     /* Middle. */
589     left[2].x1 = left[0].x1;
590     left[2].y1 = left[0].y1 + 1;
591     left[2].x2 = left[0].x2 + 1;
592     left[2].y2 = left[0].y2;
593     left[3].x1 = left[2].x2;
594     left[3].y1 = left[2].y2;
595     left[3].x2 = left[1].x2;
596     left[3].y2 = left[1].y2 - 1;
597
598     /* Inner. */
599     left[4].x1 = left[2].x1;
600     left[4].y1 = left[2].y1 + 1;
601     left[4].x2 = left[2].x2 + 1;
602     left[4].y2 = left[2].y2;
603     left[5].x1 = left[4].x2;
604     left[5].y1 = left[4].y2;
605     left[5].x2 = left[3].x2;
606     left[5].y2 = left[3].y2 - 1;
607
608     /* Outer. */
609     right[0].x1 = x + (width >> 1);
610     right[0].y1 = y;
611     right[0].x2 = x + width;
612     right[0].y2 = y + (width >> 1);
613     right[1].x1 = right[0].x2;
614     right[1].y1 = right[0].y2;
615     right[1].x2 = x + (width >> 1);
616     right[1].y2 = y + height;
617
618     /* Middle. */
619     right[2].x1 = right[0].x1;
620     right[2].y1 = right[0].y1 + 1;
621     right[2].x2 = right[0].x2 - 1;
622     right[2].y2 = right[0].y2;
623     right[3].x1 = right[2].x2;
624     right[3].y1 = right[2].y2;
625     right[3].x2 = right[1].x2;
626     right[3].y2 = right[1].y2 - 1;
627
628     /* Inner. */
629     right[4].x1 = right[2].x1;
630     right[4].y1 = right[2].y1 + 1;
631     right[4].x2 = right[2].x2 - 1;
632     right[4].y2 = right[2].y2;
633     right[5].x1 = right[4].x2;
634     right[5].y1 = right[4].y2;
635     right[5].x2 = right[3].x2;
636     right[5].y2 = right[3].y2 - 1;
637
638     if (area) {
639         gdk_gc_set_clip_rectangle(style->bg_gc[state], area);
640         gdk_gc_set_clip_rectangle(style->light_gc[state], area);
641         gdk_gc_set_clip_rectangle(style->dark_gc[state], area);
642         gdk_gc_set_clip_rectangle(style->black_gc, area);
643     }
644
645     if (state != GTK_STATE_ACTIVE) {
646         gdk_draw_segments(win, style->light_gc[state], left, 4);
647         gdk_draw_segments(win, style->bg_gc[state], &left[4], 2);
648         gdk_draw_segments(win, style->black_gc, right, 2);
649         gdk_draw_segments(win, style->dark_gc[state], &right[2], 4);
650     } else {
651         gdk_draw_segments(win, style->dark_gc[state], left, 4);
652         gdk_draw_segments(win, style->black_gc, &left[4], 2);
653         gdk_draw_segments(win, style->light_gc[state], right, 4);
654         gdk_draw_segments(win, style->bg_gc[state], &right[4], 2);
655     }
656
657     if (area) {
658         gdk_gc_set_clip_rectangle(style->bg_gc[state], NULL);
659         gdk_gc_set_clip_rectangle(style->light_gc[state], NULL);
660         gdk_gc_set_clip_rectangle(style->dark_gc[state], NULL);
661         gdk_gc_set_clip_rectangle(style->black_gc, NULL);
662     }
663 }
664
665 static void
666 gecontrol_button_normal(GEControl *ge, gint button)
667 {
668     gint v;
669     GtkWidget *w = GTK_WIDGET(ge);
670     GdkPoint points[4];
671
672     if (button == GEC_GLYPH_IMAGE)
673       return;
674
675     if (button < 3) {
676         gecontrol_paint_diamond(w->style, w->window, GTK_STATE_NORMAL, 0,
677                                 ge->buttons[button].x, ge->buttons[button].y,
678                                 GEC_TOGGLE_SIZE, GEC_TOGGLE_SIZE);
679
680         points[0].x = ge->buttons[button].x + (GEC_TOGGLE_SIZE >> 1);
681         points[0].y = ge->buttons[button].y + 3;
682         points[1].x = ge->buttons[button].x + 3;
683         points[1].y = ge->buttons[button].y + (GEC_TOGGLE_SIZE >> 1);
684         points[2].x = points[0].x;
685         points[2].y = ge->buttons[button].y + GEC_TOGGLE_SIZE - 3;
686         points[3].x = ge->buttons[button].x + GEC_TOGGLE_SIZE - 3;
687         points[3].y = points[1].y;
688
689         gdk_draw_polygon(w->window, w->style->bg_gc[GTK_STATE_NORMAL], TRUE,
690                          points, 4);
691
692         v = (GEC_TOGGLE_SIZE >> 1) - (BMAP_DIM >> 1);
693
694     } else {
695         gtk_paint_box(w->style, w->window, GTK_STATE_NORMAL,
696                       GTK_SHADOW_OUT, 0, GTK_WIDGET(ge), "gectrl",
697                       ge->buttons[button].x, ge->buttons[button].y,
698                       GEC_BUTTON_SIZE, GEC_BUTTON_SIZE);
699
700         v = (GEC_BUTTON_SIZE >> 1) - (BMAP_DIM >> 1);
701     }
702
703     gdk_draw_pixbuf(w->window, w->style->fg_gc[GTK_WIDGET_STATE(w)],
704                     ge->buttons[button].image, 0, 0,
705                     ge->buttons[button].x + v, ge->buttons[button].y + v,
706                     BMAP_DIM, BMAP_DIM, GDK_RGB_DITHER_NONE, 0, 0);
707 }
708
709 static void
710 gecontrol_button_prelight(GEControl *ge, gint button)
711 {
712     gint v;
713     GtkWidget *w = GTK_WIDGET(ge);
714     GdkPoint points[4];
715
716     if (button == GEC_GLYPH_IMAGE)
717       return;
718
719     if (button < 3) {
720         gecontrol_paint_diamond(w->style, w->window, GTK_STATE_PRELIGHT, 0,
721                                 ge->buttons[button].x, ge->buttons[button].y,
722                                 GEC_TOGGLE_SIZE, GEC_TOGGLE_SIZE);
723
724         points[0].x = ge->buttons[button].x + (GEC_TOGGLE_SIZE >> 1);
725         points[0].y = ge->buttons[button].y + 3;
726         points[1].x = ge->buttons[button].x + 3;
727         points[1].y = ge->buttons[button].y + (GEC_TOGGLE_SIZE >> 1);
728         points[2].x = points[0].x;
729         points[2].y = ge->buttons[button].y + GEC_TOGGLE_SIZE - 3;
730         points[3].x = ge->buttons[button].x + GEC_TOGGLE_SIZE - 3;
731         points[3].y = points[1].y;
732
733         gdk_draw_polygon(w->window, w->style->bg_gc[GTK_STATE_PRELIGHT], TRUE,
734                          points, 4);
735         v = (GEC_TOGGLE_SIZE >> 1) - (BMAP_DIM >> 1);
736     } else {
737         gtk_paint_box(w->style, w->window, GTK_STATE_PRELIGHT,
738                       GTK_SHADOW_OUT, 0, GTK_WIDGET(ge), "gectrl",
739                       ge->buttons[button].x, ge->buttons[button].y,
740                       GEC_BUTTON_SIZE, GEC_BUTTON_SIZE);
741         v = (GEC_BUTTON_SIZE >> 1) - (BMAP_DIM >> 1);
742     }
743
744     gdk_draw_pixbuf(w->window, w->style->fg_gc[GTK_WIDGET_STATE(w)],
745                     ge->buttons[button].image, 0, 0,
746                     ge->buttons[button].x + v, ge->buttons[button].y + v,
747                     BMAP_DIM, BMAP_DIM, GDK_RGB_DITHER_NONE, 0, 0);
748 }
749
750 static void
751 gecontrol_button_active(GEControl *ge, gint button)
752 {
753     gint v;
754     GtkWidget *w = GTK_WIDGET(ge);
755     GdkPoint points[4];
756
757     if (button == GEC_GLYPH_IMAGE)
758       return;
759
760     if (button < 3) {
761         gecontrol_paint_diamond(w->style, w->window, GTK_STATE_ACTIVE, 0,
762                                 ge->buttons[button].x, ge->buttons[button].y,
763                                 GEC_TOGGLE_SIZE, GEC_TOGGLE_SIZE);
764
765         points[0].x = ge->buttons[button].x + (GEC_TOGGLE_SIZE >> 1);
766         points[0].y = ge->buttons[button].y + 3;
767         points[1].x = ge->buttons[button].x + 3;
768         points[1].y = ge->buttons[button].y + (GEC_TOGGLE_SIZE >> 1);
769         points[2].x = points[0].x;
770         points[2].y = ge->buttons[button].y + GEC_TOGGLE_SIZE - 3;
771         points[3].x = ge->buttons[button].x + GEC_TOGGLE_SIZE - 3;
772         points[3].y = points[1].y;
773
774         gdk_draw_polygon(w->window, w->style->bg_gc[GTK_STATE_ACTIVE], TRUE,
775                          points, 4);
776         v = (GEC_TOGGLE_SIZE >> 1) - (BMAP_DIM >> 1);
777     } else {
778         gtk_paint_box(w->style, w->window, GTK_STATE_ACTIVE,
779                       GTK_SHADOW_IN, 0, GTK_WIDGET(ge), "gectrl",
780                       ge->buttons[button].x, ge->buttons[button].y,
781                       GEC_BUTTON_SIZE, GEC_BUTTON_SIZE);
782         v = (GEC_BUTTON_SIZE >> 1) - (BMAP_DIM >> 1);
783     }
784
785     gdk_draw_pixbuf(w->window, w->style->fg_gc[GTK_WIDGET_STATE(w)],
786                     ge->buttons[button].image, 0, 0,
787                     ge->buttons[button].x + v, ge->buttons[button].y + v,
788                     BMAP_DIM, BMAP_DIM, GDK_RGB_DITHER_NONE, 0, 0);
789 }
790
791 #if 0
792 static void
793 gecontrol_get_image_pixels(GEControl *ge, gint color)
794 {
795     gint byte;
796     guint16 x, y, bpr, si, di, nx;
797     guchar *masks;
798     bdf_bitmap_t *im;
799
800     im = ge->gimage;
801     ge->points_used = 0;
802
803     di = 0;
804     masks = 0;
805     switch (im->bpp) {
806       case 1: masks = bdf_onebpp; di = 7; break;
807       case 2: masks = bdf_twobpp; di = 3; break;
808       case 4: masks = bdf_fourbpp; di = 1; break;
809       case 8: masks = bdf_eightbpp; di = 0; break;
810     }
811
812     bpr = ((im->width * im->bpp) + 7) >> 3;
813     for (y = 0; y < im->height; y++) {
814         for (nx = x = 0; x < im->width; x++, nx += im->bpp) {
815             si = (nx & 7) / im->bpp;
816
817             byte = im->bitmap[(y * bpr) + (nx >> 3)] & masks[si];
818             if (di > si)
819               byte >>= (di - si) * im->bpp;
820             if (byte == color) {
821                 if (ge->points_used == ge->points_size) {
822                     if (ge->points_size == 0)
823                       ge->points =
824                           (GdkPoint *) g_malloc(sizeof(GdkPoint) * 64);
825                     else
826                       ge->points = (GdkPoint *)
827                           g_realloc(ge->points,
828                                     sizeof(GdkPoint) *
829                                     (ge->points_size + 64));;
830                     ge->points_size += 64;
831                 }
832                 ge->points[ge->points_used].x = x + im->x + 2;
833                 ge->points[ge->points_used].y = y + im->y + 2;
834                 ge->points_used++;
835             }
836         }
837     }
838 }
839 #endif
840
841 static void
842 gecontrol_make_rgb_glyph(GEControl *ge)
843 {
844     GtkWidget *w = GTK_WIDGET(ge);
845     gint byte = 0;
846     guint16 x, y, bpr, rgb_bpr, si, di, nx;
847     guchar bg[4], pix[4], *masks, *img;
848     bdf_bitmap_t *im;
849
850     /*
851      * First, get the background color of the widget for the empty
852      * pixels.
853      */
854     bg[0] = (guchar) w->style->bg[GTK_WIDGET_STATE(w)].red;
855     bg[1] = (guchar) w->style->bg[GTK_WIDGET_STATE(w)].green;
856     bg[2] = (guchar) w->style->bg[GTK_WIDGET_STATE(w)].blue;
857
858     im = ge->gimage;
859
860     di = 0;
861     masks = 0;
862     switch (im->bpp) {
863       case 1: masks = bdf_onebpp; di = 7; break;
864       case 2: masks = bdf_twobpp; di = 3; break;
865       case 4: masks = bdf_fourbpp; di = 1; break;
866       case 8: masks = bdf_eightbpp; di = 0; break;
867     }
868
869     bpr = ((im->width * im->bpp) + 7) >> 3;
870
871     rgb_bpr = im->width * 3;
872     ge->rgb_used = rgb_bpr * im->height;
873
874     /*
875      * Make sure there is enough storage space for the image.
876      */
877     if (ge->rgb_size < ge->rgb_used) {
878         if (ge->rgb_size == 0)
879           ge->rgb = g_malloc(ge->rgb_used);
880         else
881           ge->rgb = g_realloc(ge->rgb, ge->rgb_used);
882         ge->rgb_size = ge->rgb_used;
883     }
884
885     img = ge->rgb;
886
887     for (y = 0; y < im->height; y++) {
888         for (nx = x = 0; x < im->width; x++, nx += im->bpp) {
889             si = (nx & 7) / im->bpp;
890
891             byte = im->bitmap[(y * bpr) + (nx >> 3)] & masks[si];
892             if (di > si)
893               byte >>= (di - si) * im->bpp;
894             if (byte) {
895                 switch (im->bpp) {
896                   case 1: memset(pix, 0, 3); break;
897                   case 2: memset(pix, ge->colors[byte-1], 3); break;
898                   case 4: memset(pix, ge->colors[byte-1+4], 3); break;
899                   case 8: memset(pix, byte-1, 3); break;
900                 }
901             } else
902               memcpy(pix, bg, 3);
903
904             memcpy(&ge->rgb[(y * rgb_bpr) + (x * 3)], pix, 3);
905         }
906     }
907 }
908
909 static void
910 gecontrol_highlight_selected_spot(GEControl *ge)
911 {
912     GtkWidget *w = GTK_WIDGET(ge);
913     gint x, y;
914     GEControlClass *gec = GECONTROL_GET_CLASS(ge);
915
916     if (!GTK_WIDGET_REALIZED(w) || ge->gimage == 0 || ge->gimage->bpp == 1)
917       return;
918
919     if (ge->gimage->bpp != 8) {
920         x = ge->spot.x;
921         y = ge->spot.y + (8 * ge->cidx);
922     } else {
923         x = ge->spot.x + ((ge->cidx % 16) * 8);
924         y = ge->spot.y + ((ge->cidx / 16) * 8);
925     }
926     gdk_draw_rectangle(GTK_WIDGET(ge)->window, gec->selgc, FALSE, x, y, 7, 7);
927 }
928
929 static void
930 gecontrol_make_color_spots(GEControl *ge, gint bpp)
931 {
932     gint i, j, c, wd, ht, bytes;
933
934     if (bpp < 2 || bpp > 8)
935       return;
936
937     bytes = wd = ht = 0;
938
939     switch (bpp) {
940       case 2:
941       case 4:
942         wd = 8;
943         ht = 8 * (1 << bpp);
944         break;
945       case 8:
946         wd = ht = 128;
947         break;
948     }
949     bytes = wd * ht;
950
951     if (ge->rgb_size < bytes) {
952         if (ge->rgb_size == 0)
953           ge->rgb = g_malloc(bytes);
954         else
955           ge->rgb = g_realloc(ge->rgb, bytes);
956         ge->rgb_size = bytes;
957     }
958     ge->rgb_used = bytes;
959
960     /*
961      * Now create the color spots image.
962      */
963     if (bpp != 8) {
964         for (i = 0; i < (1 << bpp); i++) {
965             if (bpp == 2)
966               memset(ge->rgb+(i*64), ge->colors[i], 64);
967             else
968               memset(ge->rgb+(i*64), ge->colors[i+4], 64);
969         }
970     } else {
971         for (c = i = 0; i < 128; i += 8) {
972             for (j = 0; j < 128; j += 8, c++)
973               memset(ge->rgb+((i*128)+j), c, 8);
974             memcpy(ge->rgb+((i+1)*128), ge->rgb+(i*128), 128);
975             memcpy(ge->rgb+((i+2)*128), ge->rgb+(i*128), 256);
976             memcpy(ge->rgb+((i+4)*128), ge->rgb+(i*128), 512);
977         }
978     }
979 }
980
981 static void
982 gecontrol_draw_glyph_image(GEControl *ge)
983 {
984     GtkWidget *w = GTK_WIDGET(ge);
985
986     if (ge->gimage == 0 || !GTK_WIDGET_REALIZED(w))
987       return;
988
989     /*
990      * 1. Draw the box around the image.
991      */
992     gdk_draw_rectangle(w->window, w->style->fg_gc[GTK_WIDGET_STATE(w)],
993                        FALSE, ge->gimage->x, ge->gimage->y,
994                        ge->gimage->width + 4, ge->gimage->height + 4);
995
996     /*
997      * 2. Clear the space inside the rectangle.
998      */
999     gdk_window_clear_area(w->window, ge->gimage->x + 1, ge->gimage->y + 1,
1000                           ge->gimage->width - 2, ge->gimage->height - 2);
1001
1002     /*
1003      * 3. Draw the points.
1004      */
1005     gecontrol_make_rgb_glyph(ge);
1006     gdk_draw_rgb_image(w->window,
1007                        w->style->bg_gc[GTK_WIDGET_STATE(w)],
1008                        ge->gimage->x + 2, ge->gimage->y + 2,
1009                        ge->gimage->width, ge->gimage->height,
1010                        GDK_RGB_DITHER_NONE, ge->rgb,
1011                        ge->gimage->width * 3);
1012 }
1013
1014 static gboolean
1015 gecontrol_expose(GtkWidget *w, GdkEventExpose *ev)
1016 {
1017     gint i;
1018     GEControl *ge = GECONTROL(w);
1019     GEControlClass *gec = GECONTROL_GET_CLASS(w);
1020     GdkGCValues gcv;
1021
1022     /*
1023      * Draw the glyph image if one was provided.
1024      */
1025     gecontrol_draw_glyph_image(ge);
1026
1027     for (i = 0; i < GEC_GLYPH_IMAGE; i++) {
1028         if (ge->buttons[i].set)
1029           gecontrol_button_active(ge, i);
1030         else
1031           gecontrol_button_normal(ge, i);
1032     }
1033
1034     /*
1035      * Draw the color spots if called for.
1036      */
1037     if (ge->gimage && ge->gimage->bpp > 1) {
1038         /*
1039          * Make sure the selection GC has been created.
1040          */
1041         if (gec->selgc == 0) {
1042             gcv.foreground.pixel = w->style->fg[GTK_WIDGET_STATE(w)].pixel;
1043             gcv.background.pixel = w->style->bg[GTK_WIDGET_STATE(w)].pixel;
1044             gcv.foreground.pixel ^= gcv.background.pixel;
1045             gcv.function = GDK_XOR;
1046             gec->selgc = gdk_gc_new_with_values(w->window, &gcv,
1047                                                 GDK_GC_FOREGROUND|GDK_GC_BACKGROUND|GDK_GC_FUNCTION);
1048         }
1049
1050         gecontrol_make_color_spots(ge, ge->gimage->bpp);
1051
1052         gdk_draw_gray_image(w->window,
1053                             w->style->fg_gc[GTK_WIDGET_STATE(w)],
1054                             ge->spot.x, ge->spot.y,
1055                             ge->spot.width, ge->spot.height,
1056                             GDK_RGB_DITHER_NONE, ge->rgb, ge->spot.width);
1057
1058         /*
1059          * Draw the box around the active color.
1060          */
1061         gecontrol_highlight_selected_spot(ge);
1062     }
1063     return FALSE;
1064 }
1065
1066 static gboolean
1067 gecontrol_motion_notify(GtkWidget *w, GdkEventMotion *ev)
1068 {
1069     gint i, x, y;
1070     GEControl *ge;
1071     gchar buf[24];
1072
1073     ge = GECONTROL(w);
1074     for (i = 0; i < 18; i++) {
1075         if (ge->buttons[i].region != NULL &&
1076             gdk_region_point_in(ge->buttons[i].region, ev->x, ev->y)) {
1077             if (i != ge->last_button) {
1078
1079                 /*
1080                  * Turn of the prelight on the previous button.
1081                  */
1082                 if (ge->last_button >= 0) {
1083                     if (ge->buttons[ge->last_button].set == FALSE)
1084                       gecontrol_button_normal(ge, ge->last_button);
1085                 }
1086
1087                 if (ge->buttons[i].set == FALSE)
1088                   gecontrol_button_prelight(ge, i);
1089
1090                 if (ge->tip_label != 0)
1091                   gtk_label_set_text(GTK_LABEL(ge->tip_label),
1092                                      (gchar *) ge->buttons[i].help);
1093                 ge->last_button = i;
1094             }
1095             break;
1096         }
1097     }
1098     if (i == 18) {
1099         /*
1100          * Now check to see if the pointer is in the color spot. Only
1101          * if the tip label exists. No reason to know this info other than
1102          * to inform the user.
1103          */
1104         if (ge->tip_label) {
1105             if (ge->spot_region != NULL &&
1106                 gdk_region_point_in(ge->spot_region, ev->x, ev->y)) {
1107                 /*
1108                  * Determine which color this is and it's value. Mask
1109                  * the coordinates so they can't overflow the text buffer
1110                  * if they somehow get too large.
1111                  */
1112                 x = (((guint) ev->x) - ge->spot.x) & 0xff;
1113                 y = (((guint) ev->y) - ge->spot.y) & 0xff;
1114                 
1115                 if (ge->gimage->bpp == 2)
1116                   sprintf(buf, "Color: %03d Gray: %03d", (y>>3)+1,
1117                           ge->colors[y>>3]);
1118                 else if (ge->gimage->bpp == 4)
1119                   sprintf(buf, "Color: %03d Gray: %03d", (y>>3)+1,
1120                           ge->colors[(y>>3) + 4]);
1121                 else {
1122                     /*
1123                      * Divide x and y by 4 (spots are 4x4 in the 8bpp image)
1124                      * to get row and column.
1125                      */
1126                     x >>= 3;
1127                     y >>= 3;
1128                     sprintf(buf, "Color: %03d Gray: %03d",
1129                             ((y<<4)+x)+1, (y<<4)+x);
1130                 }
1131                 gtk_label_set_text(GTK_LABEL(ge->tip_label), buf);
1132                 return FALSE;
1133             }
1134         }
1135
1136         if (ge->tip_label != 0)
1137           gtk_label_set_text(GTK_LABEL(ge->tip_label), "");
1138         if (ge->last_button >= 0) {
1139             if (ge->buttons[ge->last_button].set == FALSE)
1140               gecontrol_button_normal(ge, ge->last_button);
1141         }
1142         ge->last_button = -1;
1143     }
1144     return FALSE;
1145 }
1146
1147 static gboolean
1148 handle_timeout(gpointer data)
1149 {
1150     GEControl *ge = GECONTROL(data);
1151     GEControlActivateInfo ai;
1152
1153     if (ge->timer_button < 0 || ge->buttons[ge->timer_button].set == FALSE) {
1154         ge->timer_button = -1;
1155         return FALSE;
1156     }
1157
1158     /*
1159      * Emit the operation signal here.
1160      */
1161     ai.operation = (GEControlOperation) ge->timer_button;
1162     g_signal_emit(G_OBJECT(ge), gecontrol_signals[ACTIVATE], 0, &ai);
1163     ge->timer_count++;
1164     return TRUE;
1165 }
1166
1167 static gboolean
1168 gecontrol_button_press(GtkWidget *w, GdkEventButton *ev)
1169 {
1170     gint i, o;
1171     GEControl *ge = GECONTROL(w);
1172
1173     for (i = 0; i < 17; i++) {
1174         if (ge->buttons[i].region != 0 &&
1175             gdk_region_point_in(ge->buttons[i].region, ev->x, ev->y)) {
1176             if (i < 3) {
1177                 if (ge->buttons[i].set == TRUE)
1178                   /*
1179                    * The toggle button is already set. Simply return.
1180                    */
1181                   return FALSE;
1182
1183                 /*
1184                  * Clear the button that is set.
1185                  */
1186                 o = (ge->buttons[ge->buttons[i].other_toggles[0]].set) ?
1187                     ge->buttons[i].other_toggles[0] :
1188                     ge->buttons[i].other_toggles[1];
1189                 gecontrol_button_normal(ge, o);
1190                 ge->buttons[o].set = FALSE;
1191             }
1192             gecontrol_button_active(ge, i);
1193             ge->buttons[i].set = TRUE;
1194
1195             /*
1196              * If this is any of the shift buttons, add a timer so it
1197              * will be handled multiple times.
1198              */
1199             if (i >= GEC_ULEFT_BUTTON && i <= GEC_DRIGHT_BUTTON) {
1200                 ge->timer_count = 0;
1201                 ge->timer_button = i;
1202                 ge->timer = g_timeout_add(100, handle_timeout,
1203                                           (gpointer) ge);
1204             }
1205             break;
1206         }
1207     }
1208
1209     return FALSE;
1210 }
1211
1212 static gboolean
1213 gecontrol_button_release(GtkWidget *w, GdkEventButton *ev)
1214 {
1215     gint i, x, y;
1216     GEControl *ge = GECONTROL(w);
1217     GEControlActivateInfo ai;
1218
1219     for (i = 0; i < 17; i++) {
1220         if (ge->buttons[i].region != 0 &&
1221             gdk_region_point_in(ge->buttons[i].region, ev->x, ev->y)) {
1222             if (i >= 3) {
1223                 gecontrol_button_prelight(ge, i);
1224                 ge->buttons[i].set = FALSE;
1225             }
1226             if (ge->timer_count == 0) {
1227                 ai.operation = (GEControlOperation) i;
1228                 g_signal_emit(G_OBJECT(ge), gecontrol_signals[ACTIVATE], 0,
1229                               &ai);
1230             } else
1231               /*
1232                * Simply reset the timer count because the signal was emitted
1233                * in the timeout handler, probably more than once.
1234                */
1235               ge->timer_count = 0;
1236             break;
1237         }
1238     }
1239     if (i == 17) {
1240         /*
1241          * Check to see if one of the colors was selected.
1242          */
1243         if (ge->gimage || ge->gimage->bpp > 1) {
1244             if (ge->spot_region != NULL &&
1245                 gdk_region_point_in(ge->spot_region, ev->x, ev->y)) {
1246                 x = (((guint) ev->x) - ge->spot.x) & 0xff;
1247                 y = (((guint) ev->y) - ge->spot.y) & 0xff;
1248                 if (ge->gimage->bpp != 8)
1249                   i = y >> 3;
1250                 else {
1251                     x >>= 3;
1252                     y >>= 3;
1253                     i = (y << 4) + x;
1254                 }
1255                 gecontrol_highlight_selected_spot(ge);
1256                 ge->cidx = i;
1257                 gecontrol_highlight_selected_spot(ge);
1258
1259                 ai.operation = GECONTROL_COLOR_CHANGE;
1260                 ai.color = ge->cidx + 1;
1261                 g_signal_emit(G_OBJECT(ge), gecontrol_signals[ACTIVATE],
1262                               0, &ai);
1263             }
1264         }
1265     }
1266     return FALSE;
1267 }
1268
1269 static void
1270 gecontrol_set_property(GObject *obj, guint prop_id, const GValue *value,
1271                        GParamSpec *pspec)
1272 {
1273     GEControl *ge;
1274
1275     ge = GECONTROL(obj);
1276
1277     switch (prop_id) {
1278       case TIP_LABEL:
1279         ge->tip_label = (GtkWidget *) g_value_get_object(value);
1280         break;
1281       case GLYPH_IMAGE:
1282         gecontrol_set_glyph_image(ge,
1283                                   (bdf_bitmap_t *) g_value_get_pointer(value));
1284         break;
1285       case COLOR_LIST:
1286         gecontrol_set_color_list(ge, (guint16 *) g_value_get_pointer(value));
1287         break;
1288     }
1289 }
1290
1291 static void
1292 gecontrol_get_property(GObject *obj, guint prop_id, GValue *value,
1293                        GParamSpec *pspec)
1294 {
1295     GEControl *ge;
1296
1297     ge = GECONTROL(obj);
1298
1299     switch (prop_id) {
1300       case TIP_LABEL:
1301         g_value_set_object(value, ge->tip_label);
1302         break;
1303       case GLYPH_IMAGE:
1304         g_value_set_pointer(value, ge->gimage);
1305         break;
1306       case COLOR_LIST:
1307         g_value_set_pointer(value, ge->colors);
1308         break;
1309     }
1310 }
1311
1312 static void
1313 gecontrol_class_init(gpointer g_class, gpointer class_data)
1314 {
1315     GObjectClass *goc = G_OBJECT_CLASS(g_class);
1316     GtkWidgetClass *wc = GTK_WIDGET_CLASS(g_class);
1317     GEControlClass *gc = GECONTROL_CLASS(g_class);
1318
1319     goc->set_property = gecontrol_set_property;
1320     goc->get_property = gecontrol_get_property;
1321     goc->finalize = gecontrol_finalize;
1322
1323     wc->size_request = gecontrol_preferred_size;
1324     wc->size_allocate = gecontrol_actual_size;
1325     wc->expose_event = gecontrol_expose;
1326     wc->motion_notify_event = gecontrol_motion_notify;
1327     wc->button_press_event = gecontrol_button_press;
1328     wc->button_release_event = gecontrol_button_release;
1329
1330     g_object_class_install_property(goc, TIP_LABEL,
1331                                     g_param_spec_object("tipLabel",
1332                                                         _("Tip Label"),
1333                                                         _("A GtkLabel widget where tips are shown when the mouse moves."),
1334                                                         GTK_TYPE_WIDGET,
1335                                                         G_PARAM_READWRITE));
1336
1337     g_object_class_install_property(goc, GLYPH_IMAGE,
1338                                     g_param_spec_pointer("glyphImage",
1339                                                        _("Glyph Image"),
1340                                                        _("The bitmap image of a glyph."),
1341                                                        G_PARAM_READWRITE));
1342
1343     g_object_class_install_property(goc, COLOR_LIST,
1344                                     g_param_spec_pointer("colorList",
1345                                                          _("Color list"),
1346                                                          _("Colors to be used for glyphs having bits-per-pixel > 1."),
1347                                                        G_PARAM_READWRITE));
1348
1349     gecontrol_signals[ACTIVATE] =
1350         g_signal_new("activate",
1351                      G_TYPE_FROM_CLASS(goc),
1352                      G_SIGNAL_RUN_FIRST,
1353                      G_STRUCT_OFFSET(GEControlClass, activate),
1354                      NULL, NULL,
1355                      g_cclosure_marshal_VOID__POINTER,
1356                      G_TYPE_NONE, 1, G_TYPE_POINTER);
1357
1358     /*
1359      * Initialize all the pixbufs.
1360      */
1361     gc->draw = gdk_pixbuf_new_from_xpm_data(draw_xpm);
1362     gc->move = gdk_pixbuf_new_from_xpm_data(move_xpm);
1363     gc->copy = gdk_pixbuf_new_from_xpm_data(copy_xpm);
1364
1365     gc->fliph = gdk_pixbuf_new_from_xpm_data(fliph_xpm);
1366     gc->flipv = gdk_pixbuf_new_from_xpm_data(flipv_xpm);
1367     gc->shear = gdk_pixbuf_new_from_xpm_data(shear_xpm);
1368
1369     gc->rleft = gdk_pixbuf_new_from_xpm_data(rleft_xpm);
1370     gc->rright = gdk_pixbuf_new_from_xpm_data(rright_xpm);
1371     gc->rotate = gdk_pixbuf_new_from_xpm_data(rotate_xpm);
1372
1373     gc->uleft = gdk_pixbuf_new_from_xpm_data(uleft_xpm);
1374     gc->up = gdk_pixbuf_new_from_xpm_data(up_xpm);
1375     gc->uright = gdk_pixbuf_new_from_xpm_data(uright_xpm);
1376
1377     gc->left = gdk_pixbuf_new_from_xpm_data(left_xpm);
1378     gc->right = gdk_pixbuf_new_from_xpm_data(right_xpm);
1379
1380     gc->dleft = gdk_pixbuf_new_from_xpm_data(dleft_xpm);
1381     gc->down = gdk_pixbuf_new_from_xpm_data(down_xpm);
1382     gc->dright = gdk_pixbuf_new_from_xpm_data(dright_xpm);
1383
1384     parent_class = g_type_class_peek_parent(gc);
1385 }
1386
1387 #define GEC_EVMASK (GDK_POINTER_MOTION_MASK|GDK_BUTTON_PRESS_MASK|\
1388                     GDK_BUTTON_RELEASE_MASK)
1389
1390 static void
1391 gecontrol_init(GTypeInstance *instance, gpointer g_class)
1392 {
1393     gint i;
1394     GEControl *gw = GECONTROL(instance);
1395     GEControlClass *gc = GECONTROL_CLASS(g_class);
1396
1397     gw->gimage = 0;
1398
1399     gw->last_button = gw->timer_button = -1;
1400     gw->timer_count = 0;
1401
1402     /*
1403      * Enable the button press, release, and motion events.
1404      */
1405     gtk_widget_add_events(GTK_WIDGET(gw), GEC_EVMASK);
1406
1407     gw->points_used = gw->points_size = 0;
1408
1409     gw->buttons[GEC_DRAW_TOGGLE].image = gc->draw;
1410     gw->buttons[GEC_MOVE_TOGGLE].image = gc->move;
1411     gw->buttons[GEC_COPY_TOGGLE].image = gc->copy;
1412
1413     gw->buttons[GEC_FLIPH_BUTTON].image = gc->fliph;
1414     gw->buttons[GEC_FLIPV_BUTTON].image = gc->flipv;
1415     gw->buttons[GEC_SHEAR_BUTTON].image = gc->shear;
1416
1417     gw->buttons[GEC_RLEFT_BUTTON].image = gc->rleft;
1418     gw->buttons[GEC_RRIGHT_BUTTON].image = gc->rright;
1419     gw->buttons[GEC_ROTATE_BUTTON].image = gc->rotate;
1420
1421     gw->buttons[GEC_ULEFT_BUTTON].image = gc->uleft;
1422     gw->buttons[GEC_UP_BUTTON].image = gc->up;
1423     gw->buttons[GEC_URIGHT_BUTTON].image = gc->uright;
1424
1425     gw->buttons[GEC_LEFT_BUTTON].image = gc->left;
1426     gw->buttons[GEC_RIGHT_BUTTON].image = gc->right;
1427
1428     gw->buttons[GEC_DLEFT_BUTTON].image = gc->dleft;
1429     gw->buttons[GEC_DOWN_BUTTON].image = gc->down;
1430     gw->buttons[GEC_DRIGHT_BUTTON].image = gc->dright;
1431
1432     for (i = 0; i < 18; i++) {
1433         gw->buttons[i].help = help_strings[i];
1434         gw->buttons[i].region = NULL;
1435         gw->buttons[i].x = gw->buttons[i].y = 0;
1436         gw->buttons[i].set = gw->buttons[i].toggle = FALSE;
1437
1438         /*
1439          * At initialization time, the Draw toggle is always set by
1440          * default.
1441          */
1442         switch (i) {
1443           case GEC_DRAW_TOGGLE:
1444             gw->buttons[i].set = TRUE;
1445             gw->buttons[i].toggle = TRUE;
1446             gw->buttons[i].other_toggles[0] = GEC_MOVE_TOGGLE;
1447             gw->buttons[i].other_toggles[1] = GEC_COPY_TOGGLE;
1448             break;
1449           case GEC_MOVE_TOGGLE:
1450             gw->buttons[i].toggle = TRUE;
1451             gw->buttons[i].other_toggles[0] = GEC_DRAW_TOGGLE;
1452             gw->buttons[i].other_toggles[1] = GEC_COPY_TOGGLE;
1453             break;
1454           case GEC_COPY_TOGGLE:
1455             gw->buttons[i].toggle = TRUE;
1456             gw->buttons[i].other_toggles[0] = GEC_DRAW_TOGGLE;
1457             gw->buttons[i].other_toggles[1] = GEC_MOVE_TOGGLE;
1458             break;
1459         }
1460     }
1461
1462     gw->cidx = 0;
1463     gw->spot_region = 0;
1464     gw->spot.x = gw->spot.y = gw->spot.width = gw->spot.height = 0;
1465 }
1466
1467 /**********************************************************************
1468  *
1469  * API functions.
1470  *
1471  **********************************************************************/
1472
1473 GType
1474 gecontrol_get_type(void)
1475 {
1476     static GType gecontrol_type = 0;
1477   
1478     if (!gecontrol_type) {
1479         static const GTypeInfo gecontrol_info = {
1480             sizeof (GEControlClass),            /* class_size           */
1481             0,                                  /* base_init            */
1482             0,                                  /* base_finalize        */
1483             gecontrol_class_init,               /* class_init           */
1484             0,                                  /* class_finalize       */
1485             0,                                  /* class_data           */
1486             sizeof(GEControl),                  /* instance_size        */
1487             0,                                  /* n_preallocs          */
1488             gecontrol_init,                     /* instance_init        */
1489             0,                                  /* value_table          */
1490         };
1491
1492         gecontrol_type = g_type_register_static(GTK_TYPE_DRAWING_AREA,
1493                                                 "GEControl",
1494                                                 &gecontrol_info, 0);
1495     }
1496   
1497     return gecontrol_type;
1498 }
1499
1500 GtkWidget *
1501 gecontrol_new(const gchar *prop1, ...)
1502 {
1503     GtkWidget *w;
1504     va_list var_args;
1505
1506     va_start(var_args, prop1);
1507     w = GTK_WIDGET(g_object_new_valist(gecontrol_get_type(), prop1, var_args));
1508     va_end(var_args);
1509
1510     return w;
1511 }
1512
1513 GtkWidget *
1514 gecontrol_newv(GtkWidget *tip_label, bdf_bitmap_t *image, guint16 *colors)
1515 {
1516     GEControl *ge = g_object_new(gecontrol_get_type(),
1517                                  "tipLabel", tip_label,
1518                                  "glyphImage", image,
1519                                  "colorList", colors,
1520                                  NULL);
1521
1522     return GTK_WIDGET(ge);
1523 }
1524
1525 void
1526 gecontrol_update_glyph_image(GEControl *ge, bdf_bitmap_t *image)
1527 {
1528     if (ge->gimage) {
1529         if (ge->gimage->bytes > 0)
1530           g_free(ge->gimage->bitmap);
1531         g_free(ge->gimage);
1532         ge->gimage = 0;
1533     }
1534     if (image != 0) {
1535         ge->gimage = (bdf_bitmap_t *) g_malloc(sizeof(bdf_bitmap_t));
1536         memcpy(ge->gimage, image, sizeof(bdf_bitmap_t));
1537         if (ge->gimage->bytes > 0) {
1538             ge->gimage->bitmap = g_malloc(ge->gimage->bytes);
1539             memcpy(ge->gimage->bitmap, image->bitmap, image->bytes);
1540         }
1541         ge->gimage->x = ge->buttons[GEC_GLYPH_IMAGE].x;
1542         ge->gimage->y = ge->buttons[GEC_GLYPH_IMAGE].y;
1543         gecontrol_draw_glyph_image(ge);
1544     } else
1545       gtk_widget_queue_draw(GTK_WIDGET(ge));
1546 }
1547
1548 void
1549 gecontrol_set_glyph_image(GEControl *ge, bdf_bitmap_t *image)
1550 {
1551     g_return_if_fail(ge != NULL);
1552     g_return_if_fail(IS_GECONTROL(ge));
1553
1554     if (ge->gimage) {
1555         if (ge->gimage->bytes > 0)
1556           g_free(ge->gimage->bitmap);
1557         g_free(ge->gimage);
1558         ge->gimage = 0;
1559     }
1560     if (image != 0) {
1561         ge->gimage = (bdf_bitmap_t *) g_malloc(sizeof(bdf_bitmap_t));
1562         memcpy(ge->gimage, image, sizeof(bdf_bitmap_t));
1563         if (ge->gimage->bytes > 0) {
1564             ge->gimage->bitmap = g_malloc(ge->gimage->bytes);
1565             memcpy(ge->gimage->bitmap, image->bitmap, image->bytes);
1566         }
1567     }
1568
1569     /*
1570      * Delete any spot region to force a new one to be created. This is
1571      * because the sizes change depending on the bits per pixel.
1572      */
1573     if (ge->spot_region != 0) {
1574         gdk_region_destroy(ge->spot_region);
1575         ge->spot_region = 0;
1576     }
1577
1578     /*
1579      * Always make sure the color index is reset in this case.
1580      */
1581     ge->cidx = 0;
1582
1583     /*
1584      * Always queue a resize to at least force a redraw of the widget.
1585      */
1586     gtk_widget_queue_resize(GTK_WIDGET(ge));
1587 }
1588
1589 void
1590 gecontrol_set_color_list(GEControl *ge, guint16 *colors)
1591 {
1592     g_return_if_fail(ge != NULL);
1593     g_return_if_fail(IS_GECONTROL(ge));
1594
1595     ge->colors = colors;
1596     gtk_widget_queue_draw(GTK_WIDGET(ge));
1597 }
1598
1599 void
1600 gecontrol_change_operation(GEControl *ge, GEControlOperation op)
1601 {
1602     gint b, i;
1603
1604     g_return_if_fail(ge != NULL);
1605     g_return_if_fail(IS_GECONTROL(ge));
1606
1607     b = -1;
1608     if (op == GECONTROL_DRAW)
1609       b = GEC_DRAW_TOGGLE;
1610     else if (op == GECONTROL_MOVE)
1611       b = GEC_MOVE_TOGGLE;
1612     else if (op == GECONTROL_COPY)
1613       b = GEC_COPY_TOGGLE;
1614
1615     if (b < 0 || ge->buttons[b].set == TRUE)
1616       return;
1617
1618     for (i = 0; i < 3; i++) {
1619         if (i != b && ge->buttons[i].set == TRUE) {
1620             ge->buttons[i].set = FALSE;
1621             gecontrol_button_normal(ge, i);
1622             break;
1623         }
1624     }
1625
1626     gecontrol_button_active(ge, b);
1627     ge->buttons[b].set = TRUE;
1628 }
1629
1630 void
1631 gecontrol_change_color(GEControl *ge, gint cidx)
1632 {
1633     g_return_if_fail(ge != NULL);
1634     g_return_if_fail(IS_GECONTROL(ge));
1635
1636     /*
1637      * No point in setting a color if this is a one bit per pixel image or
1638      * there is no image.
1639      */
1640     if (!ge->gimage || ge->gimage->bpp == 1)
1641       return;
1642
1643     /*
1644      * If the index is out of bounds, then wrap it around the other side.
1645      */
1646     cidx--;
1647     if (cidx >= (1 << ge->gimage->bpp))
1648       cidx = 0;
1649     else if (cidx < 0)
1650       cidx = (1 << ge->gimage->bpp) - 1;
1651
1652     gecontrol_highlight_selected_spot(ge);
1653     ge->cidx = cidx;
1654     gecontrol_highlight_selected_spot(ge);
1655 }