2 * Copyright 2008 Department of Mathematical Sciences, New Mexico State University
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:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
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.
23 #include <gtk/gtklabel.h>
25 #include "gectrlbmaps.h"
29 #define _(s) dgettext(GETTEXT_PACKAGE,s)
35 * All the pixmaps are 16x16.
39 #define GEC_TOGGLE_SIZE 38
40 #define GEC_BUTTON_SIZE 33
43 * Properties of this widget.
53 * Signals this widget emits.
59 static GtkDrawingAreaClass *parent_class = 0;
60 static guint gecontrol_signals[ACTIVATE + 1];
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
82 * These are encoded in UTF-8.
84 static guchar *help_strings[18] = {
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",
106 * Position all the buttons in the space provided.
109 gecontrol_position_buttons(GtkWidget *w)
111 GEControl *ge = GECONTROL(w);
112 gint x, y, sx, sy, ix, dx, i, j, v, wd, ht;
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
123 sx = (w->allocation.width >> 1) - (((GEC_TOGGLE_SIZE * 3) + 6) >> 1);
124 v = (GEC_TOGGLE_SIZE + (GEC_BUTTON_SIZE * 5)) + 15;
126 if (ge->gimage != 0) {
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.
133 v += ge->gimage->height + 7;
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.
140 if (ge->gimage->bpp == 8 && sx < 128 + 8)
145 sy = (w->allocation.height >> 1) - (v >> 1);
148 * Position the glyph image first if one is present.
150 if (ge->gimage != 0) {
152 * The addition of 2 is for the box and an empty row around the glyph
155 ix = ((w->allocation.width >> 1)-((ge->gimage->width + 2) >> 1)) + dx;
157 if (ge->buttons[GEC_GLYPH_IMAGE].region == NULL) {
159 points[0].x = points[4].x = ix;
160 points[0].y = points[4].y = sy;
162 points[1].x = ix + ge->gimage->width + 4;
163 points[1].y = points[0].y;
165 points[2].x = points[1].x;
166 points[2].y = sy + ge->gimage->height + 4;
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);
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);
177 ge->gimage->x = ge->buttons[GEC_GLYPH_IMAGE].x = ix;
178 ge->gimage->y = ge->buttons[GEC_GLYPH_IMAGE].y = sy;
180 sy += ge->gimage->height + 7;
187 * Prep the points for creating regions for the toggle buttons.
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);
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;
199 * Position the toggle buttons.
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);
206 gdk_region_offset(ge->buttons[i].region,
207 x - ge->buttons[i].x, y - ge->buttons[i].y);
209 ge->buttons[i].x = x;
210 ge->buttons[i].y = y;
212 x += GEC_TOGGLE_SIZE + 3;
214 for (j = 0; j < 5; j++)
215 points[j].x += GEC_TOGGLE_SIZE + 3;
219 * Recalculate the starting x position based on the button size instead
220 * of the toggle size.
222 sx = ((w->allocation.width >> 1)-(((GEC_BUTTON_SIZE * 3) + 6) >> 1)) + dx;
224 y += GEC_TOGGLE_SIZE + 3;
227 * Now set up the points for the buttons.
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;
239 * Position the first row of buttons.
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);
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;
251 x += GEC_BUTTON_SIZE + 3;
253 for (j = 0; j < 4; j++)
254 points[j].x += GEC_BUTTON_SIZE + 3;
258 * Reset the x coordinate for the regions.
260 points[0].x = points[3].x = sx;
261 points[1].x = points[2].x = sx + GEC_BUTTON_SIZE;
263 y += GEC_BUTTON_SIZE + 3;
265 for (j = 0; j < 4; j++)
266 points[j].y += GEC_BUTTON_SIZE + 3;
269 * Position second row of buttons.
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);
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;
281 x += GEC_BUTTON_SIZE + 3;
283 for (j = 0; j < 4; j++)
284 points[j].x += GEC_BUTTON_SIZE + 3;
288 * Reset the x coordinate for the regions.
290 points[0].x = points[3].x = sx;
291 points[1].x = points[2].x = sx + GEC_BUTTON_SIZE;
293 y += GEC_BUTTON_SIZE + 3;
295 for (j = 0; j < 4; j++)
296 points[j].y += GEC_BUTTON_SIZE + 3;
299 * Position third row of buttons.
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);
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;
311 x += GEC_BUTTON_SIZE + 3;
313 for (j = 0; j < 4; j++)
314 points[j].x += GEC_BUTTON_SIZE + 3;
318 * Reset the x coordinate for the regions.
320 points[0].x = points[3].x = sx;
321 points[1].x = points[2].x = sx + GEC_BUTTON_SIZE;
324 y += GEC_BUTTON_SIZE + 3;
326 for (j = 0; j < 4; j++)
327 points[j].y += GEC_BUTTON_SIZE + 3;
330 * Set the coordinates of the LEFT and RIGHT buttons.
332 if (ge->buttons[i].region == NULL)
333 ge->buttons[i].region =
334 gdk_region_polygon(points, 4, GDK_WINDING_RULE);
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;
341 x += (GEC_BUTTON_SIZE + 3) * 2;
343 for (j = 0; j < 4; j++)
344 points[j].x += (GEC_BUTTON_SIZE + 3) * 2;
346 if (ge->buttons[i].region == NULL)
347 ge->buttons[i].region =
348 gdk_region_polygon(points, 4, GDK_WINDING_RULE);
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;
356 * Reset the x coordinate for the regions.
358 points[0].x = points[3].x = sx;
359 points[1].x = points[2].x = sx + GEC_BUTTON_SIZE;
361 y += GEC_BUTTON_SIZE + 3;
363 for (j = 0; j < 4; j++)
364 points[j].y += GEC_BUTTON_SIZE + 3;
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);
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;
376 x += GEC_BUTTON_SIZE + 3;
378 for (j = 0; j < 4; j++)
379 points[j].x += GEC_BUTTON_SIZE + 3;
383 * Now position the color spots if they are needed.
386 if (ge->gimage && ge->gimage->bpp > 1) {
387 if (ge->gimage->bpp == 2 || ge->gimage->bpp == 4) {
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
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) -
400 ht = 8 * (1 << ge->gimage->bpp);
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) -
410 * Initialize the points for the spot region.
414 points[0].x = points[4].x = sx;
415 points[0].y = points[4].y = sy;
417 points[1].x = points[0].x + wd;
418 points[1].y = points[0].y;
420 points[2].x = points[1].x;
421 points[2].y = points[1].y + ht;
423 points[3].x = points[0].x;
424 points[3].y = points[2].y;
426 if (ge->spot_region == NULL)
427 ge->spot_region = gdk_region_polygon(points, 4,
430 gdk_region_offset(ge->spot_region,
431 sx - ge->spot.x, sy - ge->spot.y);
436 ge->spot.height = ht;
440 /**********************************************************************
442 * Initialization routines.
444 **********************************************************************/
447 gecontrol_finalize(GObject *obj)
453 g_return_if_fail(obj != 0);
454 g_return_if_fail(IS_GECONTROL(obj));
457 * Destroy all the regions for the buttons.
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;
467 * Make sure the image is removed if it exists.
469 if (ge->gimage != 0) {
470 if (ge->gimage->bytes > 0)
471 g_free(ge->gimage->bitmap);
476 gwc = GECONTROL_GET_CLASS(obj);
479 g_object_unref(G_OBJECT(gwc->selgc));
483 * Unreference all the pixbufs that were created.
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));
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;
514 gecontrol_preferred_size(GtkWidget *widget, GtkRequisition *preferred)
516 GEControl *gw = GECONTROL(widget);
519 preferred->width = 50 + (3 * (GEC_TOGGLE_SIZE + 4)) + 4;
520 preferred->height = (GEC_TOGGLE_SIZE + 6) + ((5 * GEC_BUTTON_SIZE) + 8);
522 if (gw->gimage != 0) {
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.
528 preferred->height += gw->gimage->height + 10;
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.
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) {
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.
545 preferred->width += 128 + 4;
547 preferred->height = MAX(preferred->height, ht);
553 gecontrol_actual_size(GtkWidget *widget, GtkAllocation *actual)
555 widget->allocation = *actual;
557 gecontrol_position_buttons(widget);
559 if (GTK_WIDGET_REALIZED(widget))
560 gdk_window_move_resize(widget->window, actual->x, actual->y,
561 actual->width, actual->height);
565 * Use our own painting routines to get the look and behavior we want.
568 gecontrol_paint_diamond(GtkStyle *style, GdkWindow *win, GtkStateType state,
569 GdkRectangle *area, gint x, gint y,
570 gint width, gint height)
572 GdkSegment left[6], right[6];
575 * Start the left segments at the top. Go from outer to inner.
579 left[0].x1 = x + (width >> 1);
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;
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;
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;
609 right[0].x1 = x + (width >> 1);
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;
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;
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;
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);
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);
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);
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);
666 gecontrol_button_normal(GEControl *ge, gint button)
669 GtkWidget *w = GTK_WIDGET(ge);
672 if (button == GEC_GLYPH_IMAGE)
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);
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;
689 gdk_draw_polygon(w->window, w->style->bg_gc[GTK_STATE_NORMAL], TRUE,
692 v = (GEC_TOGGLE_SIZE >> 1) - (BMAP_DIM >> 1);
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);
700 v = (GEC_BUTTON_SIZE >> 1) - (BMAP_DIM >> 1);
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);
710 gecontrol_button_prelight(GEControl *ge, gint button)
713 GtkWidget *w = GTK_WIDGET(ge);
716 if (button == GEC_GLYPH_IMAGE)
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);
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;
733 gdk_draw_polygon(w->window, w->style->bg_gc[GTK_STATE_PRELIGHT], TRUE,
735 v = (GEC_TOGGLE_SIZE >> 1) - (BMAP_DIM >> 1);
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);
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);
751 gecontrol_button_active(GEControl *ge, gint button)
754 GtkWidget *w = GTK_WIDGET(ge);
757 if (button == GEC_GLYPH_IMAGE)
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);
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;
774 gdk_draw_polygon(w->window, w->style->bg_gc[GTK_STATE_ACTIVE], TRUE,
776 v = (GEC_TOGGLE_SIZE >> 1) - (BMAP_DIM >> 1);
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);
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);
793 gecontrol_get_image_pixels(GEControl *ge, gint color)
796 guint16 x, y, bpr, si, di, nx;
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;
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;
817 byte = im->bitmap[(y * bpr) + (nx >> 3)] & masks[si];
819 byte >>= (di - si) * im->bpp;
821 if (ge->points_used == ge->points_size) {
822 if (ge->points_size == 0)
824 (GdkPoint *) g_malloc(sizeof(GdkPoint) * 64);
826 ge->points = (GdkPoint *)
827 g_realloc(ge->points,
829 (ge->points_size + 64));;
830 ge->points_size += 64;
832 ge->points[ge->points_used].x = x + im->x + 2;
833 ge->points[ge->points_used].y = y + im->y + 2;
842 gecontrol_make_rgb_glyph(GEControl *ge)
844 GtkWidget *w = GTK_WIDGET(ge);
846 guint16 x, y, bpr, rgb_bpr, si, di, nx;
847 guchar bg[4], pix[4], *masks, *img;
851 * First, get the background color of the widget for the empty
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;
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;
869 bpr = ((im->width * im->bpp) + 7) >> 3;
871 rgb_bpr = im->width * 3;
872 ge->rgb_used = rgb_bpr * im->height;
875 * Make sure there is enough storage space for the image.
877 if (ge->rgb_size < ge->rgb_used) {
878 if (ge->rgb_size == 0)
879 ge->rgb = g_malloc(ge->rgb_used);
881 ge->rgb = g_realloc(ge->rgb, ge->rgb_used);
882 ge->rgb_size = ge->rgb_used;
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;
891 byte = im->bitmap[(y * bpr) + (nx >> 3)] & masks[si];
893 byte >>= (di - si) * 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;
904 memcpy(&ge->rgb[(y * rgb_bpr) + (x * 3)], pix, 3);
910 gecontrol_highlight_selected_spot(GEControl *ge)
912 GtkWidget *w = GTK_WIDGET(ge);
914 GEControlClass *gec = GECONTROL_GET_CLASS(ge);
916 if (!GTK_WIDGET_REALIZED(w) || ge->gimage == 0 || ge->gimage->bpp == 1)
919 if (ge->gimage->bpp != 8) {
921 y = ge->spot.y + (8 * ge->cidx);
923 x = ge->spot.x + ((ge->cidx % 16) * 8);
924 y = ge->spot.y + ((ge->cidx / 16) * 8);
926 gdk_draw_rectangle(GTK_WIDGET(ge)->window, gec->selgc, FALSE, x, y, 7, 7);
930 gecontrol_make_color_spots(GEControl *ge, gint bpp)
932 gint i, j, c, wd, ht, bytes;
934 if (bpp < 2 || bpp > 8)
951 if (ge->rgb_size < bytes) {
952 if (ge->rgb_size == 0)
953 ge->rgb = g_malloc(bytes);
955 ge->rgb = g_realloc(ge->rgb, bytes);
956 ge->rgb_size = bytes;
958 ge->rgb_used = bytes;
961 * Now create the color spots image.
964 for (i = 0; i < (1 << bpp); i++) {
966 memset(ge->rgb+(i*64), ge->colors[i], 64);
968 memset(ge->rgb+(i*64), ge->colors[i+4], 64);
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);
982 gecontrol_draw_glyph_image(GEControl *ge)
984 GtkWidget *w = GTK_WIDGET(ge);
986 if (ge->gimage == 0 || !GTK_WIDGET_REALIZED(w))
990 * 1. Draw the box around the image.
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);
997 * 2. Clear the space inside the rectangle.
999 gdk_window_clear_area(w->window, ge->gimage->x + 1, ge->gimage->y + 1,
1000 ge->gimage->width - 2, ge->gimage->height - 2);
1003 * 3. Draw the points.
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);
1015 gecontrol_expose(GtkWidget *w, GdkEventExpose *ev)
1018 GEControl *ge = GECONTROL(w);
1019 GEControlClass *gec = GECONTROL_GET_CLASS(w);
1023 * Draw the glyph image if one was provided.
1025 gecontrol_draw_glyph_image(ge);
1027 for (i = 0; i < GEC_GLYPH_IMAGE; i++) {
1028 if (ge->buttons[i].set)
1029 gecontrol_button_active(ge, i);
1031 gecontrol_button_normal(ge, i);
1035 * Draw the color spots if called for.
1037 if (ge->gimage && ge->gimage->bpp > 1) {
1039 * Make sure the selection GC has been created.
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);
1050 gecontrol_make_color_spots(ge, ge->gimage->bpp);
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);
1059 * Draw the box around the active color.
1061 gecontrol_highlight_selected_spot(ge);
1067 gecontrol_motion_notify(GtkWidget *w, GdkEventMotion *ev)
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) {
1080 * Turn of the prelight on the previous button.
1082 if (ge->last_button >= 0) {
1083 if (ge->buttons[ge->last_button].set == FALSE)
1084 gecontrol_button_normal(ge, ge->last_button);
1087 if (ge->buttons[i].set == FALSE)
1088 gecontrol_button_prelight(ge, i);
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;
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.
1104 if (ge->tip_label) {
1105 if (ge->spot_region != NULL &&
1106 gdk_region_point_in(ge->spot_region, ev->x, ev->y)) {
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.
1112 x = (((guint) ev->x) - ge->spot.x) & 0xff;
1113 y = (((guint) ev->y) - ge->spot.y) & 0xff;
1115 if (ge->gimage->bpp == 2)
1116 sprintf(buf, "Color: %03d Gray: %03d", (y>>3)+1,
1118 else if (ge->gimage->bpp == 4)
1119 sprintf(buf, "Color: %03d Gray: %03d", (y>>3)+1,
1120 ge->colors[(y>>3) + 4]);
1123 * Divide x and y by 4 (spots are 4x4 in the 8bpp image)
1124 * to get row and column.
1128 sprintf(buf, "Color: %03d Gray: %03d",
1129 ((y<<4)+x)+1, (y<<4)+x);
1131 gtk_label_set_text(GTK_LABEL(ge->tip_label), buf);
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);
1142 ge->last_button = -1;
1148 handle_timeout(gpointer data)
1150 GEControl *ge = GECONTROL(data);
1151 GEControlActivateInfo ai;
1153 if (ge->timer_button < 0 || ge->buttons[ge->timer_button].set == FALSE) {
1154 ge->timer_button = -1;
1159 * Emit the operation signal here.
1161 ai.operation = (GEControlOperation) ge->timer_button;
1162 g_signal_emit(G_OBJECT(ge), gecontrol_signals[ACTIVATE], 0, &ai);
1168 gecontrol_button_press(GtkWidget *w, GdkEventButton *ev)
1171 GEControl *ge = GECONTROL(w);
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)) {
1177 if (ge->buttons[i].set == TRUE)
1179 * The toggle button is already set. Simply return.
1184 * Clear the button that is set.
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;
1192 gecontrol_button_active(ge, i);
1193 ge->buttons[i].set = TRUE;
1196 * If this is any of the shift buttons, add a timer so it
1197 * will be handled multiple times.
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,
1213 gecontrol_button_release(GtkWidget *w, GdkEventButton *ev)
1216 GEControl *ge = GECONTROL(w);
1217 GEControlActivateInfo ai;
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)) {
1223 gecontrol_button_prelight(ge, i);
1224 ge->buttons[i].set = FALSE;
1226 if (ge->timer_count == 0) {
1227 ai.operation = (GEControlOperation) i;
1228 g_signal_emit(G_OBJECT(ge), gecontrol_signals[ACTIVATE], 0,
1232 * Simply reset the timer count because the signal was emitted
1233 * in the timeout handler, probably more than once.
1235 ge->timer_count = 0;
1241 * Check to see if one of the colors was selected.
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)
1255 gecontrol_highlight_selected_spot(ge);
1257 gecontrol_highlight_selected_spot(ge);
1259 ai.operation = GECONTROL_COLOR_CHANGE;
1260 ai.color = ge->cidx + 1;
1261 g_signal_emit(G_OBJECT(ge), gecontrol_signals[ACTIVATE],
1270 gecontrol_set_property(GObject *obj, guint prop_id, const GValue *value,
1275 ge = GECONTROL(obj);
1279 ge->tip_label = (GtkWidget *) g_value_get_object(value);
1282 gecontrol_set_glyph_image(ge,
1283 (bdf_bitmap_t *) g_value_get_pointer(value));
1286 gecontrol_set_color_list(ge, (guint16 *) g_value_get_pointer(value));
1292 gecontrol_get_property(GObject *obj, guint prop_id, GValue *value,
1297 ge = GECONTROL(obj);
1301 g_value_set_object(value, ge->tip_label);
1304 g_value_set_pointer(value, ge->gimage);
1307 g_value_set_pointer(value, ge->colors);
1313 gecontrol_class_init(gpointer g_class, gpointer class_data)
1315 GObjectClass *goc = G_OBJECT_CLASS(g_class);
1316 GtkWidgetClass *wc = GTK_WIDGET_CLASS(g_class);
1317 GEControlClass *gc = GECONTROL_CLASS(g_class);
1319 goc->set_property = gecontrol_set_property;
1320 goc->get_property = gecontrol_get_property;
1321 goc->finalize = gecontrol_finalize;
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;
1330 g_object_class_install_property(goc, TIP_LABEL,
1331 g_param_spec_object("tipLabel",
1333 _("A GtkLabel widget where tips are shown when the mouse moves."),
1335 G_PARAM_READWRITE));
1337 g_object_class_install_property(goc, GLYPH_IMAGE,
1338 g_param_spec_pointer("glyphImage",
1340 _("The bitmap image of a glyph."),
1341 G_PARAM_READWRITE));
1343 g_object_class_install_property(goc, COLOR_LIST,
1344 g_param_spec_pointer("colorList",
1346 _("Colors to be used for glyphs having bits-per-pixel > 1."),
1347 G_PARAM_READWRITE));
1349 gecontrol_signals[ACTIVATE] =
1350 g_signal_new("activate",
1351 G_TYPE_FROM_CLASS(goc),
1353 G_STRUCT_OFFSET(GEControlClass, activate),
1355 g_cclosure_marshal_VOID__POINTER,
1356 G_TYPE_NONE, 1, G_TYPE_POINTER);
1359 * Initialize all the pixbufs.
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);
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);
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);
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);
1377 gc->left = gdk_pixbuf_new_from_xpm_data(left_xpm);
1378 gc->right = gdk_pixbuf_new_from_xpm_data(right_xpm);
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);
1384 parent_class = g_type_class_peek_parent(gc);
1387 #define GEC_EVMASK (GDK_POINTER_MOTION_MASK|GDK_BUTTON_PRESS_MASK|\
1388 GDK_BUTTON_RELEASE_MASK)
1391 gecontrol_init(GTypeInstance *instance, gpointer g_class)
1394 GEControl *gw = GECONTROL(instance);
1395 GEControlClass *gc = GECONTROL_CLASS(g_class);
1399 gw->last_button = gw->timer_button = -1;
1400 gw->timer_count = 0;
1403 * Enable the button press, release, and motion events.
1405 gtk_widget_add_events(GTK_WIDGET(gw), GEC_EVMASK);
1407 gw->points_used = gw->points_size = 0;
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;
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;
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;
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;
1425 gw->buttons[GEC_LEFT_BUTTON].image = gc->left;
1426 gw->buttons[GEC_RIGHT_BUTTON].image = gc->right;
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;
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;
1439 * At initialization time, the Draw toggle is always set by
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;
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;
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;
1463 gw->spot_region = 0;
1464 gw->spot.x = gw->spot.y = gw->spot.width = gw->spot.height = 0;
1467 /**********************************************************************
1471 **********************************************************************/
1474 gecontrol_get_type(void)
1476 static GType gecontrol_type = 0;
1478 if (!gecontrol_type) {
1479 static const GTypeInfo gecontrol_info = {
1480 sizeof (GEControlClass), /* class_size */
1482 0, /* base_finalize */
1483 gecontrol_class_init, /* class_init */
1484 0, /* class_finalize */
1486 sizeof(GEControl), /* instance_size */
1487 0, /* n_preallocs */
1488 gecontrol_init, /* instance_init */
1489 0, /* value_table */
1492 gecontrol_type = g_type_register_static(GTK_TYPE_DRAWING_AREA,
1494 &gecontrol_info, 0);
1497 return gecontrol_type;
1501 gecontrol_new(const gchar *prop1, ...)
1506 va_start(var_args, prop1);
1507 w = GTK_WIDGET(g_object_new_valist(gecontrol_get_type(), prop1, var_args));
1514 gecontrol_newv(GtkWidget *tip_label, bdf_bitmap_t *image, guint16 *colors)
1516 GEControl *ge = g_object_new(gecontrol_get_type(),
1517 "tipLabel", tip_label,
1518 "glyphImage", image,
1519 "colorList", colors,
1522 return GTK_WIDGET(ge);
1526 gecontrol_update_glyph_image(GEControl *ge, bdf_bitmap_t *image)
1529 if (ge->gimage->bytes > 0)
1530 g_free(ge->gimage->bitmap);
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);
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);
1545 gtk_widget_queue_draw(GTK_WIDGET(ge));
1549 gecontrol_set_glyph_image(GEControl *ge, bdf_bitmap_t *image)
1551 g_return_if_fail(ge != NULL);
1552 g_return_if_fail(IS_GECONTROL(ge));
1555 if (ge->gimage->bytes > 0)
1556 g_free(ge->gimage->bitmap);
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);
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.
1573 if (ge->spot_region != 0) {
1574 gdk_region_destroy(ge->spot_region);
1575 ge->spot_region = 0;
1579 * Always make sure the color index is reset in this case.
1584 * Always queue a resize to at least force a redraw of the widget.
1586 gtk_widget_queue_resize(GTK_WIDGET(ge));
1590 gecontrol_set_color_list(GEControl *ge, guint16 *colors)
1592 g_return_if_fail(ge != NULL);
1593 g_return_if_fail(IS_GECONTROL(ge));
1595 ge->colors = colors;
1596 gtk_widget_queue_draw(GTK_WIDGET(ge));
1600 gecontrol_change_operation(GEControl *ge, GEControlOperation op)
1604 g_return_if_fail(ge != NULL);
1605 g_return_if_fail(IS_GECONTROL(ge));
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;
1615 if (b < 0 || ge->buttons[b].set == TRUE)
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);
1626 gecontrol_button_active(ge, b);
1627 ge->buttons[b].set = TRUE;
1631 gecontrol_change_color(GEControl *ge, gint cidx)
1633 g_return_if_fail(ge != NULL);
1634 g_return_if_fail(IS_GECONTROL(ge));
1637 * No point in setting a color if this is a one bit per pixel image or
1638 * there is no image.
1640 if (!ge->gimage || ge->gimage->bpp == 1)
1644 * If the index is out of bounds, then wrap it around the other side.
1647 if (cidx >= (1 << ge->gimage->bpp))
1650 cidx = (1 << ge->gimage->bpp) - 1;
1652 gecontrol_highlight_selected_spot(ge);
1654 gecontrol_highlight_selected_spot(ge);