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 "glyphedit.h"
25 #include <gdk/gdkkeysyms.h>
26 #include <gtk/gtkselection.h>
34 #define _(s) dgettext(GETTEXT_PACKAGE,s)
40 * Each pixel will be displayed by a square with this number of pixels
43 #define MIN_PIXEL_SIZE 2
44 #define MAX_PIXEL_SIZE 20
45 #define DEFAULT_PIXEL_SIZE 10
47 #define HMARGINS(gw) ((gw)->hmargin << 1)
48 #define VMARGINS(gw) ((gw)->vmargin << 1)
53 static const gchar *cross_xpm[] = {
73 * Macros that represent the properties used by this type of object.
75 #define GLYPHEDIT_CLIPBOARD gdk_atom_intern("GLYPHEDIT_CLIPBOARD", FALSE)
76 #define GLYPHEDIT_BDF_CHAR gdk_atom_intern("GLYPHEDIT_BDF_CHAR", FALSE)
77 #define GLYPHEDIT_BITMAP gdk_atom_intern("GLYPHEDIT_BITMAP", FALSE)
78 #define GLYPHEDIT_GLYPH gdk_atom_intern("GLYPHEDIT_GLYPH", FALSE)
85 * Enums used for identifying properties.
101 * The list of signals emitted by these objects.
110 /**************************************************************************
114 **************************************************************************/
116 static GtkWidgetClass *parent_class = 0;
117 static guint glyphedit_signals[OPERATION_CHANGE + 2];
119 /**************************************************************************
121 * Class member functions.
123 **************************************************************************/
126 glyphedit_set_property(GObject *obj, guint prop_id, const GValue *value,
132 widget = GTK_WIDGET(obj);
137 glyphedit_set_grid(gw,
138 (bdf_glyph_grid_t *) g_value_get_pointer(value));
142 case SELECTION_COLOR:
147 glyphedit_set_pixel_size(gw, g_value_get_uint(value));
150 glyphedit_set_show_x_height(gw, g_value_get_boolean(value));
152 case SHOW_CAP_HEIGHT:
153 glyphedit_set_show_cap_height(gw, g_value_get_boolean(value));
156 gw->colors = (guint16 *) g_value_get_pointer(value);
157 gtk_widget_queue_draw(widget);
160 glyphedit_set_operation(gw,
161 (GlypheditOperation) g_value_get_uint(value));
167 glyphedit_get_property(GObject *obj, guint prop_id, GValue *value,
173 widget = GTK_WIDGET(obj);
178 g_value_set_pointer(value, gw->grid);
182 case SELECTION_COLOR:
187 g_value_set_uint(value, gw->pixel_size);
190 g_value_set_boolean(value, gw->show_x_height);
192 case SHOW_CAP_HEIGHT:
193 g_value_set_boolean(value, gw->show_cap_height);
196 g_value_set_pointer(value, gw->colors);
199 g_value_set_uint(value, (guint) gw->op);
205 glyphedit_destroy(GtkObject *obj)
211 * Do some checks to make sure the incoming object exists and is the right
214 g_return_if_fail(obj != 0);
215 g_return_if_fail(IS_GLYPHEDIT(obj));
218 gwc = GLYPHEDIT_GET_CLASS(obj);
221 * Unreference objects used class-wide so they get deallocated properly
222 * when no longer used. The unreference only needs to happen the first
223 * time since the objects are created at class initialization time.
225 if (gwc->cursor != 0)
226 gdk_cursor_unref(gwc->cursor);
228 if (gwc->gridgc != 0)
229 g_object_unref(G_OBJECT(gwc->gridgc));
231 g_object_unref(G_OBJECT(gwc->bbxgc));
233 g_object_unref(G_OBJECT(gwc->pixgc));
235 g_object_unref(G_OBJECT(gwc->selgc));
238 * Free up any colors allocated.
240 if (gw->baselineColor.pixel != 0)
241 gdk_colormap_free_colors(gw->widget.style->colormap,
242 &gw->baselineColor, 1);
245 gwc->gridgc = gwc->bbxgc = gwc->pixgc = gwc->selgc = 0;
248 * Free up the grid info.
251 bdf_free_glyph_grid(gw->grid);
255 if (gw->spot_size > 0) {
257 gw->spot_size = gw->spot_used = 0;
260 GTK_OBJECT_CLASS(parent_class)->destroy(obj);
264 glyphedit_finalize(GObject *obj)
267 * Do some checks to make sure the incoming object exists and is the right
270 g_return_if_fail(obj != 0);
271 g_return_if_fail(IS_GLYPHEDIT(obj));
274 * Follow the class chain back up to free up resources allocated in the
277 G_OBJECT_CLASS(parent_class)->finalize(obj);
281 glyphedit_preferred_size(GtkWidget *widget, GtkRequisition *preferred)
287 gw = GLYPHEDIT(widget);
289 screen = gdk_display_get_default_screen(gdk_display_get_default());
290 dht = gdk_screen_get_height(screen);
293 * This little bit of code quietly forces the glyph grid to be
294 * at most 1/2 the height of the screen being used to help avoid taking
295 * up too much space on the desktop.
297 margin = VMARGINS(gw);
298 preferred->height = margin +
299 ((gw->pixel_size + 4) * gw->grid->grid_height);
300 if (preferred->height > (dht >> 1)) {
301 while (gw->pixel_size > 2) {
302 preferred->height = margin +
303 ((gw->pixel_size + 4) * gw->grid->grid_height);
304 if (preferred->height < (dht >> 1))
310 preferred->width = HMARGINS(gw) +
311 ((gw->pixel_size + 4) * gw->grid->grid_width);
315 glyphedit_actual_size(GtkWidget *widget, GtkAllocation *actual)
317 widget->allocation = *actual;
319 if (GTK_WIDGET_REALIZED(widget))
320 gdk_window_move_resize(widget->window, actual->x, actual->y,
321 actual->width, actual->height);
325 glyphedit_draw_focus(GtkWidget *widget, GdkRectangle *area)
328 gint x, y, wd, ht, fwidth, fpad;
331 * Do something with this later to make sure the focus line width
332 * is set in the GC's.
334 gtk_widget_style_get(widget,
335 "focus-line-width", &fwidth,
336 "focus-padding", &fpad, NULL);
338 gc = widget->style->bg_gc[GTK_WIDGET_STATE(widget)];
340 x = (widget->style->xthickness + fwidth + fpad) - 1;
341 y = (widget->style->ythickness + fwidth + fpad) - 1;
342 wd = (widget->allocation.width - (x * 2));
343 ht = (widget->allocation.height - (y * 2));
345 if (GTK_WIDGET_HAS_FOCUS(widget))
346 gtk_paint_focus(widget->style, widget->window, GTK_WIDGET_STATE(widget),
347 area, widget, "glyphedit", x, y, wd, ht);
349 gdk_gc_set_clip_rectangle(gc, area);
350 gdk_draw_rectangle(widget->window, gc, FALSE, x, y, wd - 1, ht - 1);
351 gdk_gc_set_clip_rectangle(gc, 0);
356 glyphedit_draw_pixel(Glyphedit *gw, gint16 x, gint16 y, gboolean sel)
358 GtkWidget *w = GTK_WIDGET(gw);
360 gint16 bpr, set, dx, dy, di, si;
361 guchar *masks, *bmap;
364 if (!GTK_WIDGET_REALIZED(w) || gw->grid == 0)
367 gwc = GLYPHEDIT_GET_CLASS(gw);
371 switch (gw->grid->bpp) {
372 case 1: masks = bdf_onebpp; di = 7; break;
373 case 2: masks = bdf_twobpp; di = 3; break;
374 case 4: masks = bdf_fourbpp; di = 1; break;
375 case 8: masks = bdf_eightbpp; di = 0; break;
378 dx = (gw->pixel_size + 4) * gw->grid->grid_width;
379 dy = (gw->pixel_size + 4) * gw->grid->grid_height;
381 pix.x = (gw->widget.allocation.width >> 1) - (dx >> 1) +
382 ((gw->pixel_size + 4) * x) + 2;
383 pix.y = (gw->widget.allocation.height >> 1) - (dy >> 1) +
384 ((gw->pixel_size + 4) * y) + 2;
385 pix.width = pix.height = gw->pixel_size + 1;
387 if (sel == TRUE && gw->grid->sel.width != 0) {
388 bpr = ((gw->grid->sel.width * gw->grid->bpp) + 7) >> 3;
389 dy = y - gw->grid->sel.y;
390 dx = (x - gw->grid->sel.x) * gw->grid->bpp;
391 bmap = gw->grid->sel.bitmap;
393 bpr = ((gw->grid->grid_width * gw->grid->bpp) + 7) >> 3;
395 dx = x * gw->grid->bpp;
396 bmap = gw->grid->bitmap;
398 si = (dx & 7) / gw->grid->bpp;
399 set = bmap[(dy * bpr) + (dx >> 3)] & masks[si];
401 set >>= (di - si) * gw->grid->bpp;
404 if (gw->grid->bpp > 1) {
405 switch (gw->grid->bpp) {
407 memset(gw->spot, gw->colors[set-1], gw->spot_used);
410 memset(gw->spot, gw->colors[set-1+4], gw->spot_used);
413 memset(gw->spot, set, gw->spot_used);
416 gdk_draw_gray_image(GTK_WIDGET(gw)->window, gwc->pixgc,
417 pix.x, pix.y, pix.width, pix.height,
418 GDK_RGB_DITHER_NONE, gw->spot, pix.width);
420 gdk_draw_rectangle(GTK_WIDGET(gw)->window, gwc->pixgc, TRUE,
421 pix.x, pix.y, pix.width, pix.height);
423 gdk_window_clear_area(GTK_WIDGET(gw)->window, pix.x, pix.y,
424 pix.width, pix.height);
426 gdk_draw_rectangle(GTK_WIDGET(gw)->window, gwc->selgc, TRUE,
427 pix.x + 1, pix.y + 1,
428 pix.width - 2, pix.height - 2);
432 glyphedit_draw_glyph(Glyphedit *gw)
434 GtkWidget *w = GTK_WIDGET(gw);
438 if (!GTK_WIDGET_REALIZED(w) || gw->grid == 0)
441 for (y = 0; y < gw->grid->grid_height; y++) {
442 for (x = 0; x < gw->grid->grid_width; x++) {
443 sel = (bdf_in_selection(gw->grid, x, y, 0) ? TRUE : FALSE);
444 glyphedit_draw_pixel(gw, x, y, sel);
450 glyphedit_draw_font_bbx(Glyphedit *gw)
452 GtkWidget *w = GTK_WIDGET(gw);
454 gint16 xoff, yoff, fxoff, fyoff, psize;
457 if (!GTK_WIDGET_REALIZED(w))
460 gwc = GLYPHEDIT_GET_CLASS(gw);
462 psize = gw->pixel_size + 4;
463 frame.width = psize * gw->grid->font_bbx.width;
464 frame.height = psize *
465 (gw->grid->font_bbx.ascent + gw->grid->font_bbx.descent);
467 fxoff = psize * gw->grid->grid_width;
468 fyoff = psize * gw->grid->grid_height;
469 frame.x = (gw->widget.allocation.width >> 1) - (fxoff >> 1);
470 frame.y = (gw->widget.allocation.height >> 1) - (fyoff >> 1);
472 if (gw->grid->font_bbx.x_offset < 0)
473 fxoff = psize * (gw->grid->base_x + gw->grid->font_bbx.x_offset);
475 fxoff = psize * gw->grid->base_x;
477 fyoff = psize * (gw->grid->base_y - gw->grid->font_bbx.ascent);
480 * Due to some odd behavior, the box has to be drawn with the y point off
481 * by one because the top of the rectangle does not get drawn otherwise.
482 * Even calling gdk_draw_line() specifically doesn't work.
484 * This may have been fixed in later versions of GDK.
486 gdk_draw_rectangle(GTK_WIDGET(gw)->window, gwc->bbxgc, FALSE,
487 frame.x + fxoff, frame.y + fyoff + 1,
488 frame.width, frame.height);
491 * Draw vertical baseline.
493 xoff = (gw->pixel_size + 4) * gw->grid->base_x;
494 yoff = (gw->pixel_size + 4) * gw->grid->base_y;
496 gdk_draw_line(GTK_WIDGET(gw)->window, gwc->bbxgc,
497 frame.x + xoff, frame.y + fyoff,
498 frame.x + xoff, frame.y + fyoff + frame.height);
501 * Draw horizontal baseline.
503 gdk_draw_line(GTK_WIDGET(gw)->window, gwc->bbxgc,
504 frame.x + fxoff, frame.y + yoff,
505 frame.x + fxoff + frame.width, frame.y + yoff);
508 * Draw the CAP_HEIGHT if indicated and exists.
510 if (gw->grid && gw->grid->cap_height != 0) {
511 yoff = (gw->pixel_size + 4) *
512 (gw->grid->base_y - gw->grid->cap_height);
513 if (gw->show_cap_height == TRUE)
514 gdk_draw_line(GTK_WIDGET(gw)->window, gwc->bbxgc,
515 frame.x + fxoff, frame.y + yoff,
516 frame.x + fxoff + frame.width, frame.y + yoff);
518 gdk_window_clear_area(GTK_WIDGET(gw)->window, frame.x + fxoff,
519 frame.y + yoff, frame.width, 1);
520 gdk_draw_line(GTK_WIDGET(gw)->window, gwc->gridgc,
521 frame.x + fxoff, frame.y + yoff,
522 frame.x + fxoff + frame.width, frame.y + yoff);
527 * Draw the X_HEIGHT if indicated and exists.
529 if (gw->grid && gw->grid->x_height != 0) {
530 yoff = (gw->pixel_size + 4) * (gw->grid->base_y - gw->grid->x_height);
531 if (gw->show_x_height == TRUE)
532 gdk_draw_line(GTK_WIDGET(gw)->window, gwc->bbxgc,
533 frame.x + fxoff, frame.y + yoff,
534 frame.x + fxoff + frame.width, frame.y + yoff);
536 gdk_window_clear_area(GTK_WIDGET(gw)->window, frame.x + fxoff,
537 frame.y + yoff, frame.width, 1);
538 gdk_draw_line(GTK_WIDGET(gw)->window, gwc->gridgc,
539 frame.x + fxoff, frame.y + yoff,
540 frame.x + fxoff + frame.width, frame.y + yoff);
546 glyphedit_draw(GtkWidget *widget, GdkRegion *region)
549 gint x, y, limit, unit, wd, ht;
553 g_return_if_fail(widget != NULL);
554 g_return_if_fail(IS_GLYPHEDIT(widget));
556 gw = GLYPHEDIT(widget);
557 gwc = GLYPHEDIT_GET_CLASS(widget);
559 wd = gw->grid->grid_width;
560 ht = gw->grid->grid_height;
562 frame.width = (gw->pixel_size + 4) * wd;
563 frame.height = (gw->pixel_size + 4) * ht;
566 * Adjust the frame horizontal and vertical positions so it
567 * always appears centered on the window.
569 frame.x = (widget->allocation.width >> 1) - (frame.width >> 1);
570 frame.y = (widget->allocation.height >> 1) - (frame.height >> 1);
573 * Limit the drawing area to the clip region.
576 gdk_gc_set_clip_region(gwc->gridgc, region);
579 * Draw the outside frame.
581 gdk_draw_rectangle(widget->window, gwc->gridgc, FALSE,
582 frame.x, frame.y, frame.width, frame.height);
585 * Draw the vertical grid lines.
587 limit = frame.x + frame.width;
588 unit = gw->pixel_size + 4;
589 for (x = frame.x + unit, y = frame.y; x < limit; x += unit)
590 gdk_draw_line(widget->window, gwc->gridgc, x, y, x, y + frame.height);
593 * Draw the horizontal grid lines.
595 limit = frame.y + frame.height;
596 for (x = frame.x, y = frame.y + unit; y < limit; y += unit)
597 gdk_draw_line(widget->window, gwc->gridgc, x, y, x + frame.width, y);
600 gdk_gc_set_clip_region(gwc->gridgc, 0);
602 glyphedit_draw_font_bbx(gw);
603 glyphedit_draw_glyph(gw);
607 glyphedit_create_gcs(GtkWidget *widget, gboolean force)
613 gint8 dashes[2] = {1, 1};
615 gw = GLYPHEDIT(widget);
616 gwc = GLYPHEDIT_GET_CLASS(G_OBJECT(widget));
618 gcm = GDK_GC_FOREGROUND|GDK_GC_BACKGROUND|GDK_GC_FUNCTION;
620 if (gwc->gridgc == 0 || force == TRUE) {
621 if (gwc->gridgc != 0)
622 g_object_unref(G_OBJECT(gwc->gridgc));
623 gcv.foreground.pixel =
624 widget->style->fg[GTK_WIDGET_STATE(widget)].pixel;
625 gcv.background.pixel =
626 widget->style->bg[GTK_WIDGET_STATE(widget)].pixel;
627 gcv.function = GDK_COPY;
628 gcv.line_style = GDK_LINE_ON_OFF_DASH;
629 gwc->gridgc = gdk_gc_new_with_values(widget->window, &gcv,
630 gcm|GDK_GC_LINE_STYLE);
633 * Now set the dash lengths since they can't be set in the GC values.
635 gdk_gc_set_dashes(gwc->gridgc, 0, dashes, 2);
638 if (gwc->bbxgc == 0 || force == TRUE) {
640 g_object_unref(G_OBJECT(gwc->bbxgc));
642 if (gw->baselineColor.pixel == 0)
646 gdk_colormap_alloc_color(gw->widget.style->colormap,
647 &gw->baselineColor, FALSE, TRUE);
649 gcv.foreground.pixel = gw->baselineColor.pixel;
650 gcv.function = GDK_COPY;
651 gwc->bbxgc = gdk_gc_new_with_values(widget->window, &gcv,
652 GDK_GC_FOREGROUND|GDK_GC_FUNCTION);
655 if (gwc->selgc == 0 || force == TRUE) {
657 g_object_unref(G_OBJECT(gwc->selgc));
659 gcv.foreground.pixel =
660 widget->style->fg[GTK_WIDGET_STATE(widget)].pixel;
661 gcv.background.pixel =
662 widget->style->bg[GTK_WIDGET_STATE(widget)].pixel;
663 gcv.foreground.pixel ^= gcv.background.pixel;
664 gcv.function = GDK_XOR;
665 gwc->selgc = gdk_gc_new_with_values(widget->window, &gcv, gcm);
668 if (gwc->pixgc == 0 || force == TRUE) {
670 g_object_unref(G_OBJECT(gwc->pixgc));
672 gcv.foreground.pixel =
673 widget->style->fg[GTK_WIDGET_STATE(widget)].pixel;
674 gcv.background.pixel =
675 widget->style->bg[GTK_WIDGET_STATE(widget)].pixel;
676 gcv.function = GDK_COPY;
677 gwc->pixgc = gdk_gc_new_with_values(widget->window, &gcv, gcm);
682 glyphedit_realize(GtkWidget *widget)
686 GdkWindowAttr attributes;
687 gint attributes_mask;
690 g_return_if_fail(widget != NULL);
691 g_return_if_fail(IS_GLYPHEDIT(widget));
693 gwc = GLYPHEDIT_GET_CLASS(widget);
694 gw = GLYPHEDIT(widget);
695 GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED);
697 attributes.window_type = GDK_WINDOW_CHILD;
698 attributes.x = widget->allocation.x;
699 attributes.y = widget->allocation.y;
700 attributes.width = widget->allocation.width;
701 attributes.height = widget->allocation.height;
702 attributes.wclass = GDK_INPUT_OUTPUT;
703 attributes.visual = gtk_widget_get_visual(widget);
704 attributes.colormap = gtk_widget_get_colormap(widget);
705 attributes.event_mask = gtk_widget_get_events(widget);
706 attributes.event_mask |= (GDK_EXPOSURE_MASK|GDK_BUTTON_PRESS_MASK|
707 GDK_BUTTON_RELEASE_MASK|GDK_ENTER_NOTIFY_MASK|
708 GDK_POINTER_MOTION_MASK|
709 GDK_KEY_PRESS_MASK|GDK_KEY_RELEASE_MASK|
710 GDK_LEAVE_NOTIFY_MASK|GDK_FOCUS_CHANGE_MASK|
711 GDK_PROPERTY_CHANGE_MASK);
713 attributes_mask = GDK_WA_X|GDK_WA_Y|GDK_WA_VISUAL|GDK_WA_COLORMAP;
715 widget->window = gdk_window_new(gtk_widget_get_parent_window(widget),
716 &attributes, attributes_mask);
717 gdk_window_set_user_data(widget->window, widget);
719 widget->style = gtk_style_attach(widget->style, widget->window);
720 gtk_style_set_background(widget->style, widget->window, GTK_STATE_NORMAL);
723 * Create the crosshair cursor.
725 if (gwc->cursor == 0) {
726 gwc = GLYPHEDIT_GET_CLASS(widget);
727 cb = gdk_pixbuf_new_from_xpm_data(cross_xpm);
728 gwc->cursor = gdk_cursor_new_from_pixbuf(gdk_display_get_default(),
730 g_object_unref(G_OBJECT(cb));
733 glyphedit_create_gcs(widget, FALSE);
735 gdk_window_set_cursor(widget->window, gwc->cursor);
739 glyphedit_expose(GtkWidget *widget, GdkEventExpose *event)
742 * Paint the shadow first.
744 if (GTK_WIDGET_DRAWABLE(widget))
745 gtk_paint_shadow(widget->style, widget->window,
746 GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
747 &event->area, widget, "glyphedit",
749 widget->allocation.width,
750 widget->allocation.height);
752 glyphedit_draw(widget, event->region);
754 glyphedit_draw_focus(widget, &event->area);
760 glyphedit_focus_in(GtkWidget *widget, GdkEventFocus *event)
762 g_return_val_if_fail(widget != NULL, FALSE);
763 g_return_val_if_fail(IS_GLYPHEDIT(widget), FALSE);
764 g_return_val_if_fail(event != NULL, FALSE);
766 GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_FOCUS);
767 glyphedit_draw_focus(widget, 0);
773 glyphedit_focus_out(GtkWidget *widget, GdkEventFocus *event)
775 g_return_val_if_fail(widget != NULL, FALSE);
776 g_return_val_if_fail(IS_GLYPHEDIT(widget), FALSE);
777 g_return_val_if_fail(event != NULL, FALSE);
779 GTK_WIDGET_UNSET_FLAGS(widget, GTK_HAS_FOCUS);
780 glyphedit_draw_focus(widget, 0);
785 /**************************************************************************
787 * Class and object initialization routines.
789 **************************************************************************/
792 glyphedit_get_operation_type(void)
794 static GType etype = 0;
796 static const GEnumValue values[] = {
797 {GLYPHEDIT_NONE, "GLYPHEDIT_NONE", "none"},
798 {GLYPHEDIT_SELECT, "GLYPHEDIT_SELECT", "select"},
799 {GLYPHEDIT_DRAW, "GLYPHEDIT_DRAW", "draw"},
800 {GLYPHEDIT_MOVE, "GLYPHEDIT_MOVE", "move"},
801 {GLYPHEDIT_COPY, "GLYPHEDIT_COPY", "copy"},
802 {GLYPHEDIT_FLIP_HORIZONTAL,
803 "GLYPHEDIT_FLIP_HORIZONTAL",
805 {GLYPHEDIT_FLIP_VERTICAL,
806 "GLYPHEDIT_FLIP_VERTICAL",
808 {GLYPHEDIT_SHEAR, "GLYPHEDIT_SHEAR", "shear"},
809 {GLYPHEDIT_ROTATE_LEFT,
810 "GLYPHEDIT_ROTATE_LEFT",
812 {GLYPHEDIT_ROTATE_RIGHT,
813 "GLYPHEDIT_ROTATE_RIGHT",
818 {GLYPHEDIT_SHIFT_UP_LEFT,
819 "GLYPHEDIT_SHIFT_UP_LEFT",
822 "GLYPHEDIT_SHIFT_UP",
824 {GLYPHEDIT_SHIFT_UP_RIGHT,
825 "GLYPHEDIT_SHIFT_UP_RIGHT",
827 {GLYPHEDIT_SHIFT_LEFT,
828 "GLYPHEDIT_SHIFT_LEFT",
830 {GLYPHEDIT_SHIFT_RIGHT,
831 "GLYPHEDIT_SHIFT_RIGHT",
833 {GLYPHEDIT_SHIFT_DOWN_LEFT,
834 "GLYPHEDIT_SHIFT_DOWN_LEFT",
836 {GLYPHEDIT_SHIFT_DOWN,
837 "GLYPHEDIT_SHIFT_DOWN",
839 {GLYPHEDIT_SHIFT_DOWN_RIGHT,
840 "GLYPHEDIT_SHIFT_DOWN_RIGHT",
844 etype = g_enum_register_static("GlypheditOperation", values);
850 glyphedit_init(GTypeInstance *obj, gpointer g_class)
852 Glyphedit *gw = GLYPHEDIT(obj);
853 GlypheditClass *gwc = GLYPHEDIT_CLASS(g_class);
856 GTK_WIDGET_SET_FLAGS(gw, GTK_CAN_FOCUS);
858 gwc->gridgc = gwc->bbxgc = gwc->pixgc = gwc->selgc = 0;
860 gw->default_pixel_size = gw->pixel_size = DEFAULT_PIXEL_SIZE;
863 * Make sure the spot is the right size.
865 fpad = (gw->pixel_size + 1) * (gw->pixel_size + 1);
866 if (gw->spot_size < fpad) {
867 if (gw->spot_size == 0)
868 gw->spot = g_malloc(fpad);
870 gw->spot = g_realloc(gw->spot, fpad);
871 gw->spot_size = fpad;
873 gw->spot_used = fpad;
875 gw->owns_clipboard = FALSE;
879 gw->last_x = gw->last_y = 0;
881 memset((char *) &gw->sel_start, 0, sizeof(GdkPoint));
882 memset((char *) &gw->sel_end, 0, sizeof(GdkPoint));
885 * Always initialize to the first color.
890 * Initialize the last color seen.
894 gtk_widget_style_get(GTK_WIDGET(gw),
895 "focus-line-width", &fwidth,
896 "focus-padding", &fpad,
900 * Padding that will appear before and after the focus rectangle.
901 * Hardcode this for now.
905 gw->hmargin = gw->widget.style->xthickness + fwidth + fpad + gw->border;
906 gw->vmargin = gw->widget.style->ythickness + fwidth + fpad + gw->border;
908 gw->baselineColor.pixel = gw->selectionColor.pixel =
909 gw->cursorColor.pixel = 0;
911 gw->baselineColor.red = 0xffff;
912 gw->baselineColor.green = gw->baselineColor.blue = 0;
914 gw->op = GLYPHEDIT_DRAW;
918 * A convenience function for calling the GLYPH_MODIFIED signal because
919 * so many functions depend on it.
922 glyphedit_signal_glyph_change(Glyphedit *gw)
925 bdf_metrics_t metrics;
926 GlypheditSignalInfo si;
931 glyphedit_get_glyph_metrics(gw, &metrics);
932 bdf_grid_image(gw->grid, &image);
933 si.reason = GLYPHEDIT_GLYPH_MODIFIED;
934 si.metrics = &metrics;
938 g_signal_emit(G_OBJECT(gw), glyphedit_signals[GLYPH_MODIFIED], 0, &si);
943 /**************************************************************************
947 **************************************************************************/
950 glyphedit_new(const gchar *prop1, ...)
955 va_start(var_args, prop1);
956 w = GTK_WIDGET(g_object_new_valist(glyphedit_get_type(), prop1, var_args));
963 glyphedit_newv(bdf_glyph_grid_t *grid, guint16 default_pixel_size,
964 gboolean show_x_height, gboolean show_cap_height,
967 Glyphedit *ge = g_object_new(glyphedit_get_type(),
969 "pixelSize", default_pixel_size,
970 "showXHeight", show_x_height,
971 "showCapHeight", show_cap_height,
975 return GTK_WIDGET(ge);
979 glyphedit_get_encoding(Glyphedit *gw)
981 g_return_val_if_fail(gw != NULL, -1);
982 g_return_val_if_fail(IS_GLYPHEDIT(gw), -1);
984 return (gw->grid) ? gw->grid->encoding : -1;
988 glyphedit_get_glyph_metrics(Glyphedit *gw, bdf_metrics_t *metrics)
990 g_return_if_fail(gw != NULL);
991 g_return_if_fail(metrics != NULL);
992 g_return_if_fail(IS_GLYPHEDIT(gw));
995 memset(metrics, 0, sizeof(bdf_metrics_t));
997 metrics->font_spacing = gw->grid->spacing;
998 metrics->swidth = gw->grid->swidth;
999 metrics->dwidth = gw->grid->dwidth;
1000 metrics->width = gw->grid->glyph_bbx.width;
1001 metrics->height = gw->grid->glyph_bbx.height;
1002 metrics->x_offset = gw->grid->glyph_bbx.x_offset;
1003 metrics->y_offset = gw->grid->glyph_bbx.y_offset;
1004 metrics->ascent = gw->grid->glyph_bbx.ascent;
1005 metrics->descent = gw->grid->glyph_bbx.descent;
1010 glyphedit_get_font_metrics(Glyphedit *gw, bdf_metrics_t *metrics)
1012 g_return_if_fail(gw != NULL);
1013 g_return_if_fail(metrics != NULL);
1014 g_return_if_fail(IS_GLYPHEDIT(gw));
1017 memset(metrics, 0, sizeof(bdf_metrics_t));
1019 metrics->font_spacing = gw->grid->spacing;
1020 metrics->swidth = gw->grid->swidth;
1021 metrics->dwidth = gw->grid->dwidth;
1022 metrics->width = gw->grid->font_bbx.width;
1023 metrics->height = gw->grid->font_bbx.height;
1024 metrics->x_offset = gw->grid->font_bbx.x_offset;
1025 metrics->y_offset = gw->grid->font_bbx.y_offset;
1026 metrics->ascent = gw->grid->font_bbx.ascent;
1027 metrics->descent = gw->grid->font_bbx.descent;
1032 glyphedit_get_psf_mappings(Glyphedit *gw)
1034 g_return_val_if_fail(gw != NULL, 0);
1035 g_return_val_if_fail(IS_GLYPHEDIT(gw), 0);
1037 return (gw->grid) ? &gw->grid->unicode : 0;
1041 * Can set both font and glyph metrics.
1044 glyphedit_set_metrics(Glyphedit *gw, bdf_metrics_t *metrics)
1046 GtkWidget *w = GTK_WIDGET(gw);
1048 g_return_if_fail(gw != NULL);
1049 g_return_if_fail(metrics != NULL);
1050 g_return_if_fail(IS_GLYPHEDIT(gw));
1055 if (bdf_grid_resize(gw->grid, metrics)) {
1056 glyphedit_signal_glyph_change(gw);
1057 gtk_widget_queue_resize(GTK_WIDGET(gw));
1058 } else if (GTK_WIDGET_REALIZED(w))
1060 * The size didn't change, but we need to redraw if the widget
1061 * has been realized.
1063 gtk_widget_queue_draw(GTK_WIDGET(gw));
1067 glyphedit_get_spacing(Glyphedit *gw)
1069 g_return_val_if_fail(gw != NULL, -1);
1070 g_return_val_if_fail(IS_GLYPHEDIT(gw), -1);
1071 g_return_val_if_fail(gw->grid != NULL, -1);
1073 return gw->grid->spacing;
1077 glyphedit_set_spacing(Glyphedit *gw, gint spacing, guint16 monowidth)
1079 bdf_metrics_t metrics;
1081 g_return_if_fail(gw != NULL);
1082 g_return_if_fail(IS_GLYPHEDIT(gw));
1083 g_return_if_fail(gw->grid != NULL);
1085 gw->grid->spacing = spacing;
1086 if (spacing != BDF_PROPORTIONAL) {
1087 glyphedit_get_font_metrics(gw, &metrics);
1088 metrics.dwidth = metrics.width = monowidth;
1089 glyphedit_set_metrics(gw, &metrics);
1094 glyphedit_set_grid(Glyphedit *gw, bdf_glyph_grid_t *grid)
1096 g_return_if_fail(gw != NULL);
1097 g_return_if_fail(IS_GLYPHEDIT(gw));
1099 bdf_free_glyph_grid(gw->grid);
1103 gw->last_x = grid->base_x;
1104 gw->last_y = grid->base_y;
1106 gw->last_x = gw->last_y = 0;
1109 * If the widget is in Move or Copy mode, change back to Select mode.
1111 if (gw->op == GLYPHEDIT_MOVE || gw->op == GLYPHEDIT_COPY) {
1112 gw->pending_op = gw->op;
1113 gw->op = GLYPHEDIT_SELECT;
1119 gtk_widget_queue_resize(GTK_WIDGET(gw));
1123 glyphedit_get_modified(Glyphedit *gw)
1125 g_return_val_if_fail(gw != NULL, FALSE);
1126 g_return_val_if_fail(IS_GLYPHEDIT(gw), FALSE);
1128 return (gw->grid) ? gw->grid->modified : FALSE;
1132 glyphedit_set_modified(Glyphedit *gw, gboolean modified)
1134 g_return_if_fail(gw != NULL);
1135 g_return_if_fail(IS_GLYPHEDIT(gw));
1138 gw->grid->modified = ((modified == TRUE) ? 1 : 0);
1142 glyphedit_signal_modified(Glyphedit *gw)
1144 g_return_if_fail(gw != NULL);
1145 g_return_if_fail(IS_GLYPHEDIT(gw));
1147 glyphedit_signal_glyph_change(gw);
1151 glyphedit_get_selecting(Glyphedit *gw)
1153 g_return_val_if_fail(gw != NULL, FALSE);
1154 g_return_val_if_fail(IS_GLYPHEDIT(gw), FALSE);
1155 g_return_val_if_fail(gw->grid != NULL, FALSE);
1157 return bdf_has_selection(gw->grid, 0, 0, 0, 0) ? TRUE : FALSE;
1161 glyphedit_clipboard_empty(Glyphedit *gw)
1164 gboolean empty = TRUE;
1166 gint aformat, nitems;
1169 g_return_val_if_fail(gw != NULL, empty);
1170 g_return_val_if_fail(IS_GLYPHEDIT(gw), empty);
1172 if ((owner = gdk_selection_owner_get(GLYPHEDIT_CLIPBOARD)) == 0)
1176 * Check to see if the clipboard contents are empty or not.
1178 * This is handled specially to allow determination of this without
1179 * using up what might be a lot of memory to get the whole contents. It
1180 * will have to be changed for Windows.
1182 if (gdk_property_get(owner, GLYPHEDIT_CLIPBOARD, GLYPHEDIT_BITMAP,
1183 0, 16, FALSE, &atype, &aformat, &nitems, &data)) {
1186 free((char *) data);
1194 glyphedit_get_image(Glyphedit *gw, bdf_bitmap_t *image)
1196 g_return_if_fail(gw != NULL);
1197 g_return_if_fail(IS_GLYPHEDIT(gw));
1198 g_return_if_fail(image != NULL);
1201 bdf_grid_image(gw->grid, image);
1203 memset(image, 0, sizeof(bdf_bitmap_t));
1207 glyphedit_get_grid(Glyphedit *gw)
1209 g_return_val_if_fail(gw != NULL, 0);
1210 g_return_val_if_fail(IS_GLYPHEDIT(gw), 0);
1216 glyphedit_get_glyph(Glyphedit *gw, gboolean *unencoded)
1218 g_return_val_if_fail(gw != NULL, 0);
1219 g_return_val_if_fail(IS_GLYPHEDIT(gw), 0);
1223 *unencoded = (gw->grid->unencoded == 0) ? FALSE : TRUE;
1224 return bdf_grid_glyph(gw->grid);
1232 glyphedit_set_show_cap_height(Glyphedit *gw, gboolean show)
1234 g_return_if_fail(gw != NULL);
1235 g_return_if_fail(IS_GLYPHEDIT(gw));
1237 gw->show_cap_height = show;
1240 * Redraw the bounding box.
1242 glyphedit_draw_font_bbx(gw);
1246 glyphedit_set_show_x_height(Glyphedit *gw, gboolean show)
1248 g_return_if_fail(gw != NULL);
1249 g_return_if_fail(IS_GLYPHEDIT(gw));
1251 gw->show_x_height = show;
1254 * Redraw the bounding box.
1256 glyphedit_draw_font_bbx(gw);
1260 glyphedit_crop_glyph(Glyphedit *gw)
1262 g_return_if_fail(gw != NULL);
1263 g_return_if_fail(IS_GLYPHEDIT(gw));
1265 if (gw->grid && bdf_grid_crop(gw->grid, 1))
1266 glyphedit_signal_glyph_change(gw);
1268 glyphedit_draw_glyph(gw);
1272 glyphedit_shift_glyph(Glyphedit *gw, gint16 xcount, gint16 ycount)
1274 g_return_if_fail(gw != NULL);
1275 g_return_if_fail(IS_GLYPHEDIT(gw));
1277 if (gw->grid && bdf_grid_shift(gw->grid, xcount, ycount))
1278 glyphedit_signal_glyph_change(gw);
1280 glyphedit_draw_glyph(gw);
1284 glyphedit_rotate_glyph(Glyphedit *gw, gint16 degrees)
1288 g_return_if_fail(gw != NULL);
1289 g_return_if_fail(IS_GLYPHEDIT(gw));
1291 if (gw->grid && bdf_grid_rotate(gw->grid, degrees, &resize)) {
1292 glyphedit_signal_glyph_change(gw);
1294 gtk_widget_queue_resize(GTK_WIDGET(gw));
1296 glyphedit_draw_glyph(gw);
1301 glyphedit_shear_glyph(Glyphedit *gw, gint16 degrees)
1305 g_return_if_fail(gw != NULL);
1306 g_return_if_fail(IS_GLYPHEDIT(gw));
1308 if (gw->grid && bdf_grid_shear(gw->grid, degrees, &resize)) {
1309 glyphedit_signal_glyph_change(gw);
1311 gtk_widget_queue_resize(GTK_WIDGET(gw));
1313 glyphedit_draw_glyph(gw);
1318 glyphedit_embolden_glyph(Glyphedit *gw)
1320 g_return_if_fail(gw != NULL);
1321 g_return_if_fail(IS_GLYPHEDIT(gw));
1323 if (gw->grid && bdf_grid_embolden(gw->grid)) {
1324 glyphedit_signal_glyph_change(gw);
1327 * Simply redraw the glyph because the size didn't change,
1330 glyphedit_draw_glyph(gw);
1335 glyphedit_flip_glyph(Glyphedit *gw, GtkOrientation direction)
1339 g_return_if_fail(gw != NULL);
1340 g_return_if_fail(IS_GLYPHEDIT(gw));
1341 g_return_if_fail(gw->grid != NULL);
1343 flipped = (direction == GTK_ORIENTATION_HORIZONTAL) ?
1344 bdf_grid_flip(gw->grid, -1) : bdf_grid_flip(gw->grid, 1);
1347 glyphedit_signal_glyph_change(gw);
1350 * Simply redraw the glyph because the size didn't change,
1353 glyphedit_draw_glyph(gw);
1358 glyphedit_set_pixel_size(Glyphedit *gw, guint pixel_size)
1362 g_return_if_fail(gw != NULL);
1363 g_return_if_fail(IS_GLYPHEDIT(gw));
1365 if (pixel_size < MIN_PIXEL_SIZE || pixel_size > MAX_PIXEL_SIZE)
1369 * Queue up a resize to force the resize and redraw.
1371 gw->pixel_size = pixel_size;
1374 * Make sure the spot is the right size.
1376 bytes = (pixel_size + 1) * (pixel_size + 1);
1377 if (gw->spot_size < bytes) {
1378 if (gw->spot_size == 0)
1379 gw->spot = g_malloc(bytes);
1381 gw->spot = g_realloc(gw->spot, bytes);
1382 gw->spot_size = bytes;
1384 gw->spot_used = bytes;
1386 gtk_widget_queue_resize(GTK_WIDGET(gw));
1390 glyphedit_get_pixel_size(Glyphedit *gw)
1392 g_return_val_if_fail(gw != NULL, GLYPHEDIT_NONE);
1393 g_return_val_if_fail(IS_GLYPHEDIT(gw), GLYPHEDIT_NONE);
1394 g_return_val_if_fail(gw->grid != NULL, GLYPHEDIT_NONE);
1396 return gw->pixel_size;
1400 glyphedit_get_operation(Glyphedit *gw)
1402 g_return_val_if_fail(gw != NULL, GLYPHEDIT_NONE);
1403 g_return_val_if_fail(IS_GLYPHEDIT(gw), GLYPHEDIT_NONE);
1404 g_return_val_if_fail(gw->grid != NULL, GLYPHEDIT_NONE);
1410 glyphedit_set_operation(Glyphedit *gw, GlypheditOperation op)
1412 gint16 sx, sy, x, y, wd, ht;
1414 g_return_if_fail(gw != NULL);
1415 g_return_if_fail(IS_GLYPHEDIT(gw));
1416 g_return_if_fail(gw->grid != NULL);
1418 if (bdf_has_selection(gw->grid, &x, &y, &wd, &ht)) {
1419 if (op == GLYPHEDIT_MOVE)
1420 bdf_detach_selection(gw->grid);
1421 else if (op == GLYPHEDIT_COPY)
1422 bdf_attach_selection(gw->grid);
1424 if (op == GLYPHEDIT_DRAW) {
1426 * Attach the selected part of the bitmap.
1428 bdf_attach_selection(gw->grid);
1431 * Erase the selected rectangle.
1433 for (sy = y; sy < y + ht; sy++) {
1434 for (sx = x; sx < x + wd; sx++)
1435 glyphedit_draw_pixel(gw, sx, sy, FALSE);
1437 bdf_lose_selection(gw->grid);
1442 gw->pending_op = GLYPHEDIT_NONE;
1444 glyphedit_signal_glyph_change(gw);
1446 if (op == GLYPHEDIT_MOVE || op == GLYPHEDIT_COPY) {
1447 gw->op = GLYPHEDIT_SELECT;
1448 gw->pending_op = op;
1451 gw->pending_op = GLYPHEDIT_NONE;
1457 glyphedit_insert_bitmap(Glyphedit *gw, bdf_bitmap_t *bitmap)
1459 GtkWidget *w = GTK_WIDGET(gw);
1461 gint16 sx, sy, x, y, wd, ht;
1462 bdf_metrics_t metrics;
1463 GlypheditSignalInfo si;
1465 g_return_if_fail(gw != NULL);
1466 g_return_if_fail(IS_GLYPHEDIT(gw));
1468 if ((win = gdk_selection_owner_get(GLYPHEDIT_CLIPBOARD)) == 0) {
1469 gdk_selection_owner_set(w->window, GLYPHEDIT_CLIPBOARD,
1470 GDK_CURRENT_TIME, FALSE);
1472 } else if (win != w->window)
1473 gdk_selection_owner_set(w->window, GLYPHEDIT_CLIPBOARD,
1474 GDK_CURRENT_TIME, FALSE);
1476 if (bdf_has_selection(gw->grid, &x, &y, &wd, &ht)) {
1478 * This widget already has a selection, so release it.
1480 if (gw->op != GLYPHEDIT_SELECT)
1481 bdf_attach_selection(gw->grid);
1483 for (sy = y; sy < y + ht; sy++) {
1484 for (sx = x; sx < x + wd; sx++)
1485 glyphedit_draw_pixel(gw, sx, sy, FALSE);
1487 bdf_lose_selection(gw->grid);
1490 bitmap->x = gw->last_x;
1491 bitmap->y = gw->last_y;
1493 glyphedit_get_font_metrics(gw, &metrics);
1494 if (bitmap->width > metrics.width || bitmap->height > metrics.height) {
1496 * Adjust the insert position on the X axis if necessary.
1498 if (bitmap->width > metrics.width)
1499 bitmap->x = gw->grid->base_x + gw->grid->font_bbx.x_offset;
1501 * Adjust the insert position on the Y axis and the ascent if
1504 if (bitmap->height > metrics.height) {
1506 metrics.ascent = bitmap->height - gw->grid->font_bbx.descent;
1508 metrics.width = bitmap->width;
1509 metrics.height = bitmap->height;
1510 glyphedit_set_metrics(gw, &metrics);
1514 * Set the selection in the grid.
1516 bdf_add_selection(gw->grid, bitmap);
1519 * Now update the grid.
1521 if (bdf_has_selection(gw->grid, &x, &y, &wd, &ht)) {
1522 for (sy = y; sy < y + ht; sy++) {
1523 for (sx = x; sx < x + wd; sx++)
1524 glyphedit_draw_pixel(gw, sx, sy, TRUE);
1529 * Set up and call the operation change signal.
1531 si.reason = GLYPHEDIT_OPERATION_CHANGE;
1532 si.operation = GLYPHEDIT_MOVE;
1533 g_signal_emit(G_OBJECT(gw), glyphedit_signals[OPERATION_CHANGE], 0,
1537 * Set up and call the modified signal.
1539 glyphedit_signal_glyph_change(gw);
1542 * Make sure the widget goes into MOVE mode at this point.
1543 * This allows the user to position what was pasted without
1544 * destroying the glyph bitmap that was already there.
1546 if (gw->op != GLYPHEDIT_MOVE) {
1547 gw->op = GLYPHEDIT_MOVE;
1548 gw->pending_op = GLYPHEDIT_NONE;
1551 glyphedit_copy_selection(gw);
1555 glyphedit_own_clipboard(Glyphedit *gw)
1561 if (!GTK_WIDGET_REALIZED(w) || gw->owns_clipboard == TRUE)
1564 win = gdk_selection_owner_get(GLYPHEDIT_CLIPBOARD);
1565 gdk_selection_owner_set(w->window, GLYPHEDIT_CLIPBOARD,
1566 GDK_CURRENT_TIME, FALSE);
1568 gw->owns_clipboard =
1569 (gdk_selection_owner_get(GLYPHEDIT_CLIPBOARD) == w->window) ? TRUE : FALSE;
1572 * The Intrinsics may need to have a SelectionClear notice sent. Probably
1573 * won't be necessary on Windows.
1578 glyphedit_encode_selection(Glyphedit *gw, gint *bytes)
1585 if (!bdf_has_selection(gw->grid, 0, 0, &wd, &ht))
1588 size = bcount = (gint) gw->grid->sel.bytes >> 1;
1589 size += sizeof(guint16) * 3;
1590 bp = bmap = (guchar *) g_malloc(size);
1593 * Encode the width and height in Most Significant Byte order assuming
1594 * the width and height types are 16-bit values.
1596 if (!bdf_little_endian()) {
1597 *bp++ = (gw->grid->bpp >> 8) & 0xff;
1598 *bp++ = gw->grid->bpp & 0xff;
1599 *bp++ = (wd >> 8) & 0xff;
1601 *bp++ = (ht >> 8) & 0xff;
1604 *bp++ = gw->grid->bpp & 0xff;
1605 *bp++ = (gw->grid->bpp >> 8) & 0xff;
1607 *bp++ = (wd >> 8) & 0xff;
1609 *bp++ = (ht >> 8) & 0xff;
1612 (void) memcpy((char *) bp, (char *) gw->grid->sel.bitmap, bcount);
1619 glyphedit_copy_selection(Glyphedit *gw)
1621 GtkWidget *w = GTK_WIDGET(gw);
1625 g_return_if_fail(gw != NULL);
1626 g_return_if_fail(IS_GLYPHEDIT(gw));
1629 * If the widget has no selection, then this routine will return 0.
1631 if ((sel = glyphedit_encode_selection(gw, &bytes)) == 0)
1635 * Go ahead and actually write the data to the clipboard and then free the
1638 gdk_property_change(w->window, GLYPHEDIT_CLIPBOARD, GLYPHEDIT_BITMAP,
1639 8, GDK_PROP_MODE_REPLACE, sel, (gint) bytes);
1645 glyphedit_cut_selection(Glyphedit *gw)
1647 GtkWidget *w = GTK_WIDGET(gw);
1651 g_return_if_fail(gw != NULL);
1652 g_return_if_fail(IS_GLYPHEDIT(gw));
1655 * If the widget has no selection, then this routine will return 0.
1657 if ((sel = glyphedit_encode_selection(gw, &bytes)) == 0)
1661 * Go ahead and actually write the data to the clipboard and then free the
1664 gdk_property_change(w->window, GLYPHEDIT_CLIPBOARD, GLYPHEDIT_BITMAP,
1665 8, GDK_PROP_MODE_REPLACE, sel, (gint) bytes);
1670 * Now actually delete the selection and update the glyph.
1672 bdf_delete_selection(gw->grid);
1673 bdf_lose_selection(gw->grid);
1674 if (gw->op != GLYPHEDIT_DRAW) {
1675 gw->pending_op = gw->op;
1676 gw->op = GLYPHEDIT_SELECT;
1678 glyphedit_draw_glyph(gw);
1679 glyphedit_signal_glyph_change(gw);
1683 glyphedit_change_operation(Glyphedit *gw, GlypheditOperation op)
1685 gboolean call_modify;
1686 gint16 sx, sy, x, y, wd, ht;
1688 g_return_if_fail(gw != NULL);
1689 g_return_if_fail(IS_GLYPHEDIT(gw));
1694 * Special handling is needed for move and copy operations. If a
1695 * selection does not exist yet, then make the move/copy a pending
1696 * operation and set the operation to select. Once the selection is made,
1697 * the operation will be changed to the pending move/copy operation. If a
1698 * selection exists, then set the move/copy operation and detach/attach
1699 * the selection accordingly.
1701 if (bdf_has_selection(gw->grid, &x, &y, &wd, &ht)) {
1702 if (op == GLYPHEDIT_MOVE)
1703 bdf_detach_selection(gw->grid);
1704 else if (op == GLYPHEDIT_COPY)
1705 bdf_attach_selection(gw->grid);
1707 if (op == GLYPHEDIT_DRAW) {
1709 * Attach the selected part of the bitmap.
1711 bdf_attach_selection(gw->grid);
1714 * Erase the selected rectangle.
1716 for (sy = y; sy < y + ht; sy++) {
1717 for (sx = x; sx < x + wd; sx++)
1718 glyphedit_draw_pixel(gw, sx, sy, FALSE);
1720 bdf_lose_selection(gw->grid);
1723 call_modify = FALSE;
1726 gw->pending_op = GLYPHEDIT_NONE;
1727 glyphedit_signal_glyph_change(gw);
1729 if (op == GLYPHEDIT_MOVE || op == GLYPHEDIT_COPY) {
1730 gw->op = GLYPHEDIT_SELECT;
1731 gw->pending_op = op;
1734 gw->pending_op = GLYPHEDIT_NONE;
1740 glyphedit_set_color(Glyphedit *gw, gint idx)
1742 GlypheditSignalInfo si;
1744 g_return_if_fail(gw != NULL);
1745 g_return_if_fail(IS_GLYPHEDIT(gw));
1746 g_return_if_fail(gw->grid != 0);
1750 idx = (1 << gw->grid->bpp);
1751 else if (idx > (1 << gw->grid->bpp))
1756 if (idx != gw->cidx) {
1757 si.reason = GLYPHEDIT_COLOR_CHANGE;
1759 g_signal_emit(G_OBJECT(gw), glyphedit_signals[COLOR_CHANGE], 0, &si);
1766 glyphedit_paste_selection(Glyphedit *gw)
1768 GtkWidget *w = GTK_WIDGET(gw);
1771 gint aformat, nitems;
1773 gint16 sx, sy, x, y, wd, ht;
1774 bdf_metrics_t metrics;
1776 GlypheditSignalInfo si;
1778 g_return_if_fail(gw != NULL);
1779 g_return_if_fail(IS_GLYPHEDIT(gw));
1780 g_return_if_fail(gw->grid != NULL);
1782 if ((win = gdk_selection_owner_get(GLYPHEDIT_CLIPBOARD)) == 0) {
1783 gdk_selection_owner_set(w->window, GLYPHEDIT_CLIPBOARD,
1784 GDK_CURRENT_TIME, FALSE);
1789 gdk_property_get(win, GLYPHEDIT_CLIPBOARD, GLYPHEDIT_BITMAP,
1790 0, 10240, FALSE, &atype, &aformat, &nitems, &data);
1792 if (win != w->window)
1793 gdk_selection_owner_set(w->window, GLYPHEDIT_CLIPBOARD,
1794 GDK_CURRENT_TIME, FALSE);
1801 if (bdf_has_selection(gw->grid, &x, &y, &wd, &ht)) {
1803 * This widget already has a selection, so release it.
1805 if (gw->op != GLYPHEDIT_SELECT)
1806 bdf_attach_selection(gw->grid);
1808 for (sy = y; sy < y + ht; sy++) {
1809 for (sx = x; sx < x + wd; sx++)
1810 glyphedit_draw_pixel(gw, sx, sy, FALSE);
1812 bdf_lose_selection(gw->grid);
1817 if (!bdf_little_endian()) {
1818 image.bpp = (*bp++ << 8) & 0xff00;
1820 image.width = (*bp++ << 8) & 0xff00;
1821 image.width |= *bp++;
1822 image.height = (*bp++ << 8) & 0xff00;
1823 image.height |= *bp++;
1825 image.bpp = *bp++ & 0xff;
1826 image.bpp |= (*bp++ << 8) & 0xff00;
1827 image.width = *bp++ & 0xff;
1828 image.width |= (*bp++ << 8) & 0xff00;
1829 image.height = *bp++ & 0xff;
1830 image.height |= (*bp++ << 8) & 0xff00;
1833 image.bytes = (((image.width * image.bpp) + 7) >> 3) * image.height;
1836 image.x = gw->last_x;
1837 image.y = gw->last_y;
1840 * If the bitmap being pasted is larger than the current grid, then
1841 * resize the grid before doing anything else.
1843 glyphedit_get_font_metrics(gw, &metrics);
1844 if (image.width > metrics.width || image.height > metrics.height) {
1846 * Adjust the insert position on the X axis if necessary.
1848 if (image.width > metrics.width)
1849 image.x = gw->grid->base_x +
1850 gw->grid->font_bbx.x_offset;
1852 * Adjust the insert position on the Y axis and the ascent if
1855 if (image.height > metrics.height) {
1857 metrics.ascent = image.height - gw->grid->font_bbx.descent;
1859 metrics.width = image.width;
1860 metrics.height = image.height;
1861 glyphedit_set_metrics(gw, &metrics);
1865 * Set the selection in the grid.
1867 bdf_add_selection(gw->grid, &image);
1870 * Now update the grid.
1872 if (bdf_has_selection(gw->grid, &x, &y, &wd, &ht)) {
1873 for (sy = y; sy < y + ht; sy++) {
1874 for (sx = x; sx < x + wd; sx++)
1875 glyphedit_draw_pixel(gw, sx, sy, TRUE);
1880 * Set up and call the image update.
1882 glyphedit_signal_glyph_change(gw);
1885 * Free up the original value passed.
1890 * Alert the client that the widget is changing to the MOVE
1893 si.reason = GLYPHEDIT_OPERATION_CHANGE;
1894 si.operation = GLYPHEDIT_MOVE;
1895 g_signal_emit(G_OBJECT(gw), glyphedit_signals[OPERATION_CHANGE],
1899 * Make sure the widget goes into MOVE mode at this point.
1900 * This allows the user to position what was pasted without
1901 * destroying the glyph bitmap that was already there.
1903 if (gw->op != GLYPHEDIT_MOVE) {
1904 gw->op = GLYPHEDIT_MOVE;
1905 gw->pending_op = GLYPHEDIT_NONE;
1909 * Last, recopy the selection to the clipboard because changing owners
1910 * causes the data to be lost.
1912 glyphedit_copy_selection(gw);
1917 glyphedit_select_all(Glyphedit *gw)
1919 gint16 tx, ty, sx, sy, wd, ht;
1920 GlypheditSignalInfo si;
1922 g_return_if_fail(gw != NULL);
1923 g_return_if_fail(IS_GLYPHEDIT(gw));
1924 g_return_if_fail(gw->grid != NULL);
1927 * If a selection already exists, clear it.
1929 if (bdf_has_selection(gw->grid, &sx, &sy, &wd, &ht)) {
1930 if (gw->op != GLYPHEDIT_SELECT)
1931 bdf_attach_selection(gw->grid);
1933 for (ty = sy; ty < sy + ht; ty++) {
1934 for (tx = sx; tx < sx + wd; tx++)
1935 glyphedit_draw_pixel(gw, tx, ty, FALSE);
1937 bdf_lose_selection(gw->grid);
1940 wd = gw->grid->glyph_bbx.width;
1941 ht = gw->grid->glyph_bbx.height;
1943 sx = gw->sel_start.x = gw->grid->glyph_x;
1944 sy = gw->sel_start.y = gw->grid->glyph_y;
1945 gw->sel_end.x = gw->grid->glyph_x + wd;
1946 gw->sel_end.y = gw->grid->glyph_y + ht;
1949 * Gain control of the GLYPHEDIT_CLIPBOARD atom.
1951 glyphedit_own_clipboard(gw);
1953 bdf_set_selection(gw->grid, sx, sy, wd, ht);
1954 bdf_detach_selection(gw->grid);
1956 for (ty = sy; ty < sy + ht; ty++) {
1957 for (tx = sx; tx < sx + wd; tx++)
1958 glyphedit_draw_pixel(gw, tx, ty, TRUE);
1962 * Alert the client that the widget is changing to the MOVE
1965 si.reason = GLYPHEDIT_OPERATION_CHANGE;
1966 si.operation = GLYPHEDIT_MOVE;
1967 g_signal_emit(G_OBJECT(gw), glyphedit_signals[OPERATION_CHANGE],
1971 * Make sure the widget goes into MOVE mode at this point.
1972 * This allows the user to position what was pasted without
1973 * destroying the glyph bitmap that was already there.
1975 if (gw->op != GLYPHEDIT_MOVE) {
1976 gw->op = GLYPHEDIT_MOVE;
1977 gw->pending_op = GLYPHEDIT_NONE;
1982 glyphedit_encoding(Glyphedit *gw)
1984 g_return_val_if_fail(gw != NULL, -1);
1985 g_return_val_if_fail(IS_GLYPHEDIT(gw), -1);
1986 g_return_val_if_fail(gw->grid != NULL, -1);
1988 return (gw->grid->unencoded) ? -1 : gw->grid->encoding;
1992 glyphedit_get_pointer_coord(Glyphedit *gw, gint16 ex, gint16 ey,
1993 gint16 *px, gint16 *py)
1995 GtkWidget *w = GTK_WIDGET(gw);
1996 gint16 x, y, wd, ht;
1998 wd = (gw->pixel_size + 4) * gw->grid->grid_width;
1999 ht = (gw->pixel_size + 4) * gw->grid->grid_height;
2002 * Need the plus 1 to account for the outer rectangle.
2004 x = (w->allocation.width >> 1) - (wd >> 1) + 1;
2005 y = (w->allocation.height >> 1) - (ht >> 1) + 1;
2007 if (ex < x || ex > x + wd)
2010 *px = (ex - x) / (gw->pixel_size + 4);
2012 if (ey < y || ey > y + ht)
2015 *py = (ey - y) / (gw->pixel_size + 4);
2018 * Adjust for a possible overrun off the edges of the grid.
2020 if (*px >= gw->grid->grid_width)
2021 *px = gw->grid->grid_width - 1;
2022 if (*py >= gw->grid->grid_height)
2023 *py = gw->grid->grid_height - 1;
2027 glyphedit_in_selection(Glyphedit *gw, gint16 x, gint16 y)
2029 return (((gw->sel_start.y <= y && y <= gw->sel_end.y) ||
2030 (gw->sel_end.y <= y && y <= gw->sel_start.y)) &&
2031 ((gw->sel_start.x <= x && x <= gw->sel_end.x) ||
2032 (gw->sel_end.x <= x && x <= gw->sel_start.x)))
2037 glyphedit_in_intersection(Glyphedit *gw, gint16 ix, gint16 iy,
2040 return (((gw->sel_start.y <= y && y <= iy) ||
2041 (iy <= y && y <= gw->sel_start.y)) &&
2042 ((gw->sel_start.x <= x && x <= ix) ||
2043 (ix <= x && x <= gw->sel_start.x))) ? TRUE : FALSE;
2047 glyphedit_update_selection(Glyphedit *gw, gint16 x, gint16 y, gboolean set)
2051 for (ht = 0; ht < gw->grid->grid_height; ht++) {
2052 for (wd = 0; wd < gw->grid->grid_width; wd++) {
2053 if (glyphedit_in_intersection(gw, x, y, wd, ht) == FALSE &&
2054 glyphedit_in_selection(gw, wd, ht) == TRUE)
2056 * Clear or set the pixel.
2058 glyphedit_draw_pixel(gw, wd, ht, set);
2064 glyphedit_button_press(GtkWidget *w, GdkEventButton *event)
2067 gint16 x, y, sx, sy, tx, ty, wd, ht;
2072 glyphedit_get_pointer_coord(gw, (gint16) event->x, (gint16) event->y,
2075 if (event->button == 2 && (event->state & GDK_SHIFT_MASK)) {
2079 glyphedit_paste_selection(gw);
2084 if (gw->op == GLYPHEDIT_DRAW) {
2085 switch (event->button) {
2087 if ((changed = bdf_grid_set_pixel(gw->grid, x, y, gw->cidx)))
2088 glyphedit_draw_pixel(gw, x, y, FALSE);
2091 if ((changed = bdf_grid_invert_pixel(gw->grid, x, y, gw->cidx)))
2092 glyphedit_draw_pixel(gw, x, y, FALSE);
2095 if ((changed = bdf_grid_clear_pixel(gw->grid, x, y)))
2096 glyphedit_draw_pixel(gw, x, y, FALSE);
2099 if (changed == TRUE)
2100 glyphedit_signal_glyph_change(gw);
2101 } else if (gw->op == GLYPHEDIT_SELECT) {
2103 * If a selection already exists, clear it.
2105 if (bdf_has_selection(gw->grid, &sx, &sy, &wd, &ht)) {
2106 if (gw->pending_op != GLYPHEDIT_NONE)
2107 bdf_attach_selection(gw->grid);
2109 for (ty = sy; ty < sy + ht; ty++) {
2110 for (tx = sx; tx < sx + wd; tx++)
2111 glyphedit_draw_pixel(gw, tx, ty, FALSE);
2113 bdf_lose_selection(gw->grid);
2117 * Select the pixel at the point and initialize the selection
2120 glyphedit_draw_pixel(gw, x, y, TRUE);
2122 gw->sel_start.x = gw->sel_end.x = x;
2123 gw->sel_start.y = gw->sel_end.y = y;
2126 * Check to see if this is Button3 and a selection exists. If so,
2127 * then copy the selection to the clipboard and return.
2129 if (event->button == 3 &&
2130 bdf_has_selection(gw->grid, &sx, &sy, &wd, &ht)) {
2131 glyphedit_copy_selection(gw);
2138 * The operation is one of move or copy. If the button is clicked
2139 * outside the selection, remove the selection and start over.
2141 if (bdf_has_selection(gw->grid, &sx, &sy, &wd, &ht) &&
2142 !bdf_in_selection(gw->grid, x, y, 0)) {
2144 if (gw->op != GLYPHEDIT_SELECT)
2145 bdf_attach_selection(gw->grid);
2147 for (ty = sy; ty < sy + ht; ty++) {
2148 for (tx = sx; tx < sx + wd; tx++)
2149 glyphedit_draw_pixel(gw, tx, ty, FALSE);
2151 bdf_lose_selection(gw->grid);
2153 gw->pending_op = gw->op;
2154 gw->op = GLYPHEDIT_SELECT;
2157 * Select the pixel at the point and initialize the selection
2160 glyphedit_draw_pixel(gw, x, y, TRUE);
2162 gw->sel_start.x = gw->sel_end.x = x;
2163 gw->sel_start.y = gw->sel_end.y = y;
2168 * Set the last coordinate to the point just handled.
2177 glyphedit_button_release(GtkWidget *w, GdkEventButton *event)
2180 gint16 sx, sy, ex, ey;
2183 * Button releases on a widget without the focus is ignored.
2185 if (!GTK_WIDGET_HAS_FOCUS(w))
2190 sx = MIN(gw->sel_start.x, gw->sel_end.x);
2191 ex = MAX(gw->sel_start.x, gw->sel_end.x);
2192 sy = MIN(gw->sel_start.y, gw->sel_end.y);
2193 ey = MAX(gw->sel_start.y, gw->sel_end.y);
2195 if (gw->op == GLYPHEDIT_SELECT) {
2196 if (sx == ex && sy == ey)
2197 glyphedit_draw_pixel(gw, gw->sel_start.x, gw->sel_start.y, FALSE);
2200 * Gain control of the GLYPHEDIT_CLIPBOARD atom.
2202 glyphedit_own_clipboard(gw);
2204 bdf_set_selection(gw->grid, sx, sy, (ex - sx) + 1, (ey - sy) + 1);
2207 * Switch to a move/copy operations if necessary.
2209 if (gw->pending_op != GLYPHEDIT_NONE) {
2210 gw->op = gw->pending_op;
2211 gw->pending_op = GLYPHEDIT_NONE;
2213 * If the pending operation is a move, then make sure the
2214 * selection is detached.
2216 if (gw->op == GLYPHEDIT_MOVE)
2217 bdf_detach_selection(gw->grid);
2225 glyphedit_motion_notify(GtkWidget *w, GdkEventMotion *event)
2229 gint16 x, y, ix, iy;
2230 GlypheditSignalInfo si;
2234 glyphedit_get_pointer_coord(gw, (gint16) event->x, (gint16) event->y,
2238 * Return if the mouse is off the edges of the grid or the mouse is still
2239 * on the same point as the last one.
2241 if (x < 0 || y < 0 || (x == gw->last_x && y == gw->last_y))
2244 si.reason = GLYPHEDIT_POINTER_MOVED;
2245 si.x = x - gw->grid->base_x;
2246 si.y = -(y - gw->grid->base_y) - 1;
2247 si.color = bdf_grid_color_at(gw->grid, x, y);
2248 g_signal_emit(G_OBJECT(gw), glyphedit_signals[POINTER_MOVED],
2258 * If the event is a simple motion event with no button being pressed,
2259 * then simply return at this point.
2261 if (!GTK_WIDGET_HAS_FOCUS(w) ||
2262 !(event->state & (GDK_BUTTON1_MASK|GDK_BUTTON2_MASK|GDK_BUTTON3_MASK)))
2266 if (gw->op == GLYPHEDIT_DRAW) {
2270 if (event->state & GDK_BUTTON1_MASK) {
2271 if ((changed = bdf_grid_set_pixel(gw->grid, x, y, gw->cidx)))
2272 glyphedit_draw_pixel(gw, x, y, FALSE);
2273 } else if (event->state & GDK_BUTTON2_MASK) {
2274 if ((changed = bdf_grid_invert_pixel(gw->grid, x, y, gw->cidx)))
2275 glyphedit_draw_pixel(gw, x, y, FALSE);
2276 } else if (event->state & GDK_BUTTON3_MASK) {
2277 if ((changed = bdf_grid_clear_pixel(gw->grid, x, y)))
2278 glyphedit_draw_pixel(gw, x, y, FALSE);
2282 * If one of the pixels changed, then call the callback.
2285 glyphedit_signal_glyph_change(gw);
2286 } else if (gw->op == GLYPHEDIT_SELECT) {
2288 * Determine the other point on the intersection rectangle.
2290 ix = gw->sel_start.x;
2291 iy = gw->sel_start.y;
2294 ix = MIN(gw->sel_end.x, x);
2296 ix = MAX(gw->sel_end.x, x);
2299 iy = MIN(gw->sel_end.y, y);
2301 iy = MAX(gw->sel_end.y, y);
2304 * Clear the pixels outside the intersection of the old selection
2305 * rectangle and the new selection rectangle.
2307 glyphedit_update_selection(gw, ix, iy, FALSE);
2310 * Set the new endpoint of the selection rectangle.
2316 * Set all pixels outside the intersection of the old selection
2317 * rectangle and the new selection rectangle, but inside the new
2318 * selection rectangle.
2320 glyphedit_update_selection(gw, ix, iy, TRUE);
2323 * A move or copy is in progress.
2325 if (bdf_has_selection(gw->grid, 0, 0, 0, 0) &&
2326 bdf_grid_shift(gw->grid, x - ix, y - iy)) {
2327 glyphedit_draw_glyph(gw);
2328 glyphedit_signal_glyph_change(gw);
2336 glyphedit_key_press(GtkWidget *w, GdkEventKey *event)
2338 gboolean ret = FALSE;
2340 switch (event->keyval) {
2343 glyphedit_shift_glyph(GLYPHEDIT(w), -1, 0);
2347 glyphedit_shift_glyph(GLYPHEDIT(w), 1, 0);
2352 * For some reason, the Up arrow causes the focus to change to
2353 * other widgets. Returning TRUE insures that the up arrow works
2356 glyphedit_shift_glyph(GLYPHEDIT(w), 0, -1);
2361 glyphedit_shift_glyph(GLYPHEDIT(w), 0, 1);
2365 glyphedit_cut_selection(GLYPHEDIT(w));
2369 glyphedit_rotate_glyph(GLYPHEDIT(w), -90);
2372 glyphedit_rotate_glyph(GLYPHEDIT(w), 90);
2375 case GDK_KP_Subtract:
2376 glyphedit_flip_glyph(GLYPHEDIT(w), GTK_ORIENTATION_HORIZONTAL);
2380 glyphedit_flip_glyph(GLYPHEDIT(w), GTK_ORIENTATION_VERTICAL);
2385 /* Change to a lighter color. */
2386 glyphedit_set_color(GLYPHEDIT(w), GLYPHEDIT(w)->cidx - 1);
2391 /* Change to a darker color. */
2392 glyphedit_set_color(GLYPHEDIT(w), GLYPHEDIT(w)->cidx + 1);
2400 glyphedit_key_release(GtkWidget *w, GdkEventKey *event)
2406 glyphedit_class_init(gpointer g_class, gpointer class_data)
2408 GObjectClass *gocp = G_OBJECT_CLASS(g_class);
2409 GtkObjectClass *ocp = GTK_OBJECT_CLASS(g_class);
2410 GtkWidgetClass *wcp = GTK_WIDGET_CLASS(g_class);
2413 * Set the class global variables.
2415 parent_class = g_type_class_peek_parent(g_class);
2417 ocp->destroy = glyphedit_destroy;
2419 gocp->set_property = glyphedit_set_property;
2420 gocp->get_property = glyphedit_get_property;
2421 gocp->finalize = glyphedit_finalize;
2424 * Add argument (a.k.a. resource) types.
2426 g_object_class_install_property(gocp, GLYPH_GRID,
2427 g_param_spec_pointer("glyphGrid",
2429 _("The glyph in a grid structure."),
2430 G_PARAM_READWRITE));
2432 g_object_class_install_property(gocp, PIXEL_SIZE,
2433 g_param_spec_uint("pixelSize",
2435 _("The number of pixels to use to draw one grid pixel."),
2439 G_PARAM_READWRITE));
2441 g_object_class_install_property(gocp, SHOW_X_HEIGHT,
2442 g_param_spec_boolean("showXHeight",
2444 _("Draw a line at the x height."),
2446 G_PARAM_READWRITE));
2448 g_object_class_install_property(gocp, SHOW_CAP_HEIGHT,
2449 g_param_spec_boolean("showCapHeight",
2450 _("Show Cap Height"),
2451 _("Draw a line at the cap height."),
2453 G_PARAM_READWRITE));
2455 g_object_class_install_property(gocp, OPERATION,
2456 g_param_spec_enum("operation",
2457 _("Edit Operation"),
2458 _("Glyph edit operation."),
2459 glyphedit_get_operation_type(),
2461 G_PARAM_READWRITE));
2463 g_object_class_install_property(gocp, COLOR_LIST,
2464 g_param_spec_pointer("colorList",
2466 _("Colors to be used for glyphs having bits-per-pixel > 1."),
2467 G_PARAM_READWRITE));
2471 * Add the signals these objects emit.
2473 glyphedit_signals[GLYPH_MODIFIED] =
2474 g_signal_new("glyph-modified",
2475 G_TYPE_FROM_CLASS(gocp),
2477 G_STRUCT_OFFSET(GlypheditClass, glyph_modified),
2479 g_cclosure_marshal_VOID__POINTER,
2480 G_TYPE_NONE, 1, G_TYPE_POINTER);
2482 glyphedit_signals[POINTER_MOVED] =
2483 g_signal_new("pointer-moved",
2484 G_TYPE_FROM_CLASS(gocp),
2486 G_STRUCT_OFFSET(GlypheditClass, pointer_moved),
2488 g_cclosure_marshal_VOID__POINTER,
2489 G_TYPE_NONE, 1, G_TYPE_POINTER);
2491 glyphedit_signals[OPERATION_CHANGE] =
2492 g_signal_new("operation-change",
2493 G_TYPE_FROM_CLASS(gocp),
2495 G_STRUCT_OFFSET(GlypheditClass, operation_change),
2497 g_cclosure_marshal_VOID__POINTER,
2498 G_TYPE_NONE, 1, G_TYPE_POINTER);
2500 glyphedit_signals[COLOR_CHANGE] =
2501 g_signal_new("color-change",
2502 G_TYPE_FROM_CLASS(gocp),
2504 G_STRUCT_OFFSET(GlypheditClass, color_change),
2506 g_cclosure_marshal_VOID__POINTER,
2507 G_TYPE_NONE, 1, G_TYPE_POINTER);
2510 * Set all the functions for handling events for objects of this class.
2512 wcp->size_request = glyphedit_preferred_size;
2513 wcp->size_allocate = glyphedit_actual_size;
2514 wcp->realize = glyphedit_realize;
2515 wcp->expose_event = glyphedit_expose;
2516 wcp->focus_in_event = glyphedit_focus_in;
2517 wcp->focus_out_event = glyphedit_focus_out;
2518 wcp->button_press_event = glyphedit_button_press;
2519 wcp->button_release_event = glyphedit_button_release;
2520 wcp->motion_notify_event = glyphedit_motion_notify;
2521 wcp->key_press_event = glyphedit_key_press;
2522 wcp->key_release_event = glyphedit_key_release;
2526 glyphedit_get_type(void)
2528 static GType glyphedit_type = 0;
2530 if (!glyphedit_type) {
2531 static const GTypeInfo glyphedit_info = {
2532 sizeof(GlypheditClass),
2535 glyphedit_class_init,
2544 glyphedit_type = g_type_register_static(GTK_TYPE_WIDGET, "Glyphedit",
2545 &glyphedit_info, 0);
2548 return glyphedit_type;