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.
24 #include <gdk/gdkkeysyms.h>
25 #include <gtk/gtkselection.h>
26 #include <gtk/gtkwidget.h>
34 #define _(s) dgettext(GETTEXT_PACKAGE,s)
40 * Macros that represent the properties used by this type of object.
42 #define FONTGRID_CLIPBOARD gdk_atom_intern("FONTGRID_CLIPBOARD", FALSE)
43 #define FONTGRID_GLYPHLIST gdk_atom_intern("FONTGRID_GLYPHLIST", FALSE)
46 * Set several defaults.
48 #define FGRID_MAX_COLS 16
49 #define FGRID_MAX_ROWS 16
50 #define FGRID_DEFAULT_COLS 16
51 #define FGRID_DEFAULT_ROWS 8
52 #define FGRID_DEFAULT_CELL_HEIGHT 18
55 * Enums used for identifying properties.
74 /**************************************************************************
76 * Selection macros for toggling & testing glyph selected state.
78 **************************************************************************/
81 * Macros for dealing with the selected state of glyphs in the font grid.
83 #define IsSelected(code, map) (map[(code) >> 5] & (1 << ((code) & 31)))
84 #define Select(code, map) (map[(code) >> 5] |= (1 << ((code) & 31)))
85 #define Unselect(code, map) (map[(code) >> 5] &= ~(1 << ((code) & 31)))
87 /**************************************************************************
91 **************************************************************************/
94 * Enums that represent the signals these objects send out.
105 static GtkWidgetClass *parent_class = 0;
106 static guint fontgrid_signals[TURN_TO_PAGE + 1];
108 static bdf_glyph_t empty_glyph;
110 /**************************************************************************
112 * Digits for displaying the cell encoding.
114 **************************************************************************/
117 * Lists of points that describe the encoding digits.
124 static GdkPoint digit00[] = {{2, 0}, {1, 1}, {3, 1}, {0, 2}, {4, 2}, {0, 3},
125 {4, 3}, {0, 4}, {4, 4}, {1, 5}, {3, 5}, {2, 6}};
127 static GdkPoint digit01[] = {{2, 0}, {1, 1}, {2, 1}, {0, 2}, {2, 2}, {2, 3},
128 {2, 4}, {2, 5}, {0, 6}, {1, 6}, {2, 6}, {3, 6},
131 static GdkPoint digit02[] = {{1, 0}, {2, 0}, {3, 0}, {0, 1}, {4, 1}, {4, 2},
132 {2, 3}, {3, 3}, {1, 4}, {0, 5}, {0, 6}, {1, 6},
133 {2, 6}, {3, 6}, {4, 6}};
135 static GdkPoint digit03[] = {{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}, {4, 1},
136 {3, 2}, {2, 3},{3, 3}, {4, 4}, {0, 5}, {4, 5},
137 {1, 6}, {2, 6}, {3, 6}};
139 static GdkPoint digit04[] = {{3, 0}, {2, 1}, {3, 1}, {1, 2}, {3, 2}, {0, 3},
140 {3, 3}, {0, 4}, {1, 4}, {2, 4}, {3, 4}, {4, 4},
143 static GdkPoint digit05[] = {{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}, {0, 1},
144 {0, 2}, {2, 2}, {3, 2}, {0, 3}, {1, 3}, {4, 3},
145 {4, 4}, {0, 5}, {4, 5}, {1, 6}, {2, 6}, {3, 6}};
147 static GdkPoint digit06[] = {{2, 0}, {3, 0}, {1, 1}, {0, 2}, {0, 3}, {2, 3},
148 {3, 3}, {0, 4}, {1, 4}, {4, 4}, {0, 5}, {4, 5},
149 {1, 6}, {2, 6}, {3, 6}};
151 static GdkPoint digit07[] = {{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}, {4, 1},
152 {3, 2}, {3, 3}, {2, 4}, {1, 5}, {1, 6}};
154 static GdkPoint digit08[] = {{1, 0}, {2, 0}, {3, 0}, {0, 1}, {4, 1}, {0, 2},
155 {4, 2}, {1, 3}, {2, 3}, {3, 3}, {0, 4}, {4, 4},
156 {0, 5}, {4, 5}, {1, 6}, {2, 6}, {3, 6}};
158 static GdkPoint digit09[] = {{1, 0}, {2, 0}, {3, 0}, {0, 1}, {4, 1}, {0, 2},
159 {3, 2}, {4, 2}, {1, 3}, {2, 3}, {4, 3}, {4, 4},
160 {3, 5}, {1, 6}, {2, 6}};
162 static GdkPoint digit10[] = {{2, 0}, {1, 1}, {3, 1}, {0, 2}, {4, 2}, {0, 3},
163 {4, 3}, {0, 4}, {1, 4}, {2, 4}, {3, 4}, {4, 4},
164 {0, 5}, {4, 5}, {0, 6}, {4, 6}};
166 static GdkPoint digit11[] = {{0, 0}, {1, 0}, {2, 0}, {3, 0}, {1, 1}, {4, 1},
167 {1, 2}, {4, 2}, {1, 3}, {2, 3}, {3, 3}, {1, 4},
168 {4, 4}, {1, 5}, {4, 5}, {0, 6}, {1, 6}, {2, 6},
171 static GdkPoint digit12[] = {{1, 0}, {2, 0}, {3, 0}, {0, 1}, {4, 1}, {0, 2},
172 {0, 3}, {0, 4},{0, 5}, {4, 5}, {1, 6}, {2, 6},
175 static GdkPoint digit13[] = {{0, 0}, {1, 0}, {2, 0}, {3, 0}, {1, 1}, {4, 1},
176 {1, 2}, {4, 2}, {1, 3}, {4, 3}, {1, 4}, {4, 4},
177 {1, 5}, {4, 5}, {0, 6}, {1, 6}, {2, 6}, {3, 6}};
179 static GdkPoint digit14[] = {{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}, {0, 1},
180 {0, 2}, {0, 3}, {1, 3}, {2, 3}, {3, 3}, {0, 4},
181 {0, 5}, {0, 6}, {1, 6}, {2, 6}, {3, 6}, {4, 6}};
183 static GdkPoint digit15[] = {{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}, {0, 1},
184 {0, 2}, {0, 3}, {1, 3}, {2, 3}, {3, 3}, {0, 4},
186 static GdkPoint minus[] = {{1, 3}, {2, 3}, {3, 3}, {4,3}};
188 static fontgrid_digit digits[] = {
189 {digit00, sizeof(digit00)/sizeof(GdkPoint)},
190 {digit01, sizeof(digit01)/sizeof(GdkPoint)},
191 {digit02, sizeof(digit02)/sizeof(GdkPoint)},
192 {digit03, sizeof(digit03)/sizeof(GdkPoint)},
193 {digit04, sizeof(digit04)/sizeof(GdkPoint)},
194 {digit05, sizeof(digit05)/sizeof(GdkPoint)},
195 {digit06, sizeof(digit06)/sizeof(GdkPoint)},
196 {digit07, sizeof(digit07)/sizeof(GdkPoint)},
197 {digit08, sizeof(digit08)/sizeof(GdkPoint)},
198 {digit09, sizeof(digit09)/sizeof(GdkPoint)},
199 {digit10, sizeof(digit10)/sizeof(GdkPoint)},
200 {digit11, sizeof(digit11)/sizeof(GdkPoint)},
201 {digit12, sizeof(digit12)/sizeof(GdkPoint)},
202 {digit13, sizeof(digit13)/sizeof(GdkPoint)},
203 {digit14, sizeof(digit14)/sizeof(GdkPoint)},
204 {digit15, sizeof(digit15)/sizeof(GdkPoint)},
205 {minus, sizeof(minus)/sizeof(GdkPoint)},
209 * This array is used to hold a set of digits that will be displayed. It
210 * provides for a max of 19 points per digit and a max of 6 digits.
212 static GdkPoint encoding_digits[19*6];
215 * Used to determine spacing between digits when displaying.
217 #define FONTGRID_DIGIT_WIDTH 6
218 #define FONTGRID_DIGIT_HEIGHT 10
221 * A macro for getting the current foreground GC.
223 #define WIDGET_FG_GC(w) ((w)->style->fg_gc[GTK_WIDGET_STATE(w)])
225 #define HMARGINS(fw) ((fw)->hmargin << 1)
226 #define VMARGINS(fw) ((fw)->vmargin << 1)
229 fontgrid_set_cell_geometry(Fontgrid *fw)
236 lw = FONTGRID_DIGIT_WIDTH * 7;
239 * The labels will always be numbers in base 8, 10, or 16, so we are only
240 * interested in the max ascent. Add a 2-pixel margin on top and bottom.
242 fw->label_height = FONTGRID_DIGIT_HEIGHT + 4;
245 * We want a minumum padding of 3 pixels on each side of the glyph bitmap
246 * in each cell. Thus the addition of 6 to each dimension.
249 fw->cell_width = font->bbx.width + 6;
250 fw->cell_height = font->bbx.height + 6;
253 * Hard-code a minimum size for NULL fonts. The initial height of
254 * an empty cell is 20 to give it a better visual appearance.
256 fw->cell_width = lw + 6;
257 fw->cell_height = FGRID_DEFAULT_CELL_HEIGHT + 6;
260 fw->cell_width = MAX(fw->cell_width, lw);
261 fw->cell_height = MAX(fw->cell_height, fw->label_height);
264 * Now add the label size into the picture.
266 fw->cell_height += fw->label_height - 1;
270 fontgrid_set_rows_cols(Fontgrid *fw, GtkAllocation *core)
273 guint16 dw, dh, wd, ht;
276 * Limit the window size to 7/8 of the actual screen dimensions.
278 dw = (gdk_screen_width() * 7) >> 3;
279 dh = (gdk_screen_height() * 7) >> 3;
283 * Adjust the rows and columns based on the preferred geometry.
285 wd = (fw->cell_width * fw->cell_cols) + HMARGINS(fw);
286 ht = (fw->cell_height * fw->cell_rows) + VMARGINS(fw);
289 fw->cell_cols = (dw - HMARGINS(fw)) / fw->cell_width;
292 fw->cell_rows = (dh - VMARGINS(fw)) / fw->cell_height;
295 * Adjust the rows and columns based on the current geometry.
297 fw->cell_cols = (core->width - HMARGINS(fw)) / fw->cell_width;
298 fw->cell_rows = (core->height - VMARGINS(fw)) / fw->cell_height;
302 * Adjust rows and columns to powers of two if necessary.
306 * Make sure the columns are a power of 2.
308 for (i = 15; i >= 0; i--) {
309 if (fw->cell_cols & (1 << i)) {
310 fw->cell_cols = 1 << i;
316 * Make sure the rows are a power of 2.
318 for (i = 15; i >= 0; i--) {
319 if (fw->cell_rows & (1 << i)) {
320 fw->cell_rows = 1 << i;
327 * Fall back to a minimum of two rows.
329 if (fw->cell_rows == 0)
333 * Fall back to a minimum of two columns.
335 if (fw->cell_cols == 0)
339 * Make sure the number of rows and cols are within the max limits.
341 if (fw->cell_cols > FGRID_MAX_COLS)
342 fw->cell_cols = FGRID_MAX_COLS;
344 if (fw->cell_rows > FGRID_MAX_ROWS)
345 fw->cell_rows = FGRID_MAX_ROWS;
348 * Set the new page size based on the calculated rows and columns.
350 fw->pagesize = fw->cell_rows * fw->cell_cols;
353 /**************************************************************************
355 * GObjectClass functions.
357 **************************************************************************/
360 fontgrid_set_property(GObject *obj, guint prop_id, const GValue *value,
366 widget = GTK_WIDGET(obj);
371 fw->base = g_value_get_uint(value);
373 * Force the encodings to be redisplayed here?
377 fw->power2 = g_value_get_boolean(value);
379 case PROP_ORIENTATION:
380 fontgrid_set_orientation(fw, g_value_get_enum(value));
384 * Need to set the rows and columns back to their defaults when
385 * a new font is passed in case it is NULL.
387 fw->font = (bdf_font_t *) g_value_get_pointer(value);
389 fontgrid_set_cell_geometry(fw);
390 fontgrid_set_rows_cols(fw, 0);
392 case PROP_POINT_SIZE:
393 fw->point_size = g_value_get_uint(value);
396 fw->spacing = g_value_get_int(value);
398 case PROP_SKIP_BLANKS:
399 fw->noblanks = g_value_get_boolean(value);
402 fw->overwrite = g_value_get_boolean(value);
405 fw->colors = (guint16 *) g_value_get_pointer(value);
407 case PROP_INITIAL_GLYPH:
408 fw->initial_glyph = g_value_get_int(value);
411 fw->bpp = g_value_get_int(value);
414 fw->hres = g_value_get_int(value);
417 fw->vres = g_value_get_int(value);
423 fontgrid_get_property(GObject *obj, guint prop_id, GValue *value,
432 g_value_set_uint(value, f->base);
435 g_value_set_boolean(value, f->power2);
437 case PROP_ORIENTATION:
438 g_value_set_enum(value, f->orientation);
441 g_value_set_pointer(value, f->font);
443 case PROP_POINT_SIZE:
444 g_value_set_uint(value, f->point_size);
447 g_value_set_int(value, f->spacing);
449 case PROP_SKIP_BLANKS:
450 g_value_set_boolean(value, f->noblanks);
453 g_value_set_pointer(value, f->colors);
455 case PROP_INITIAL_GLYPH:
456 g_value_set_int(value, f->initial_glyph);
459 g_value_set_int(value, f->bpp);
462 g_value_set_int(value, f->hres);
465 g_value_set_int(value, f->vres);
470 /**************************************************************************
472 * GtkObjectClass functions.
474 **************************************************************************/
477 fontgrid_destroy(GtkObject *obj)
484 * Do some checks to make sure the incoming object exists and is the right
487 g_return_if_fail(obj != 0);
488 g_return_if_fail(IS_FONTGRID(obj));
493 * Clean up this object instance.
496 bdf_free_font(f->font);
500 g_object_unref(G_OBJECT(f->xor_gc));
503 if (f->points_size > 0)
505 f->points_size = f->points_used = 0;
509 f->rgb_used = f->rgb_size = 0;
512 * Remove all ownership of selections.
514 gtk_selection_remove_all(GTK_WIDGET(obj));
517 * Free up the clipboard contents if there are any.
520 for (i = 0; i < gl->glyphs_used; i++) {
521 if (gl->glyphs[i].name)
522 free(gl->glyphs[i].name);
523 if (gl->glyphs[i].bytes > 0)
524 free((char *) gl->glyphs[i].bitmap);
526 if (gl->glyphs_size > 0)
527 free((char *) gl->glyphs);
528 gl->glyphs_size = gl->glyphs_used = 0;
531 * Follow the class chain back up to free up resources allocated in the
534 GTK_OBJECT_CLASS(parent_class)->destroy(obj);
538 fontgrid_finalize(GObject *obj)
541 * Do some checks to make sure the incoming object exists and is the right
544 g_return_if_fail(obj != 0);
545 g_return_if_fail(IS_FONTGRID(obj));
548 * Follow the class chain back up to free up resources allocated in the
551 G_OBJECT_CLASS(parent_class)->finalize(obj);
554 /**************************************************************************
556 * GtkWidgetClass functions.
558 **************************************************************************/
561 fontgrid_preferred_size(GtkWidget *widget, GtkRequisition *preferred)
565 fw = FONTGRID(widget);
566 preferred->width = (fw->cell_width * fw->cell_cols) + HMARGINS(fw);
567 preferred->height = (fw->cell_height * fw->cell_rows) + VMARGINS(fw);
571 fontgrid_actual_size(GtkWidget *widget, GtkAllocation *actual)
575 fw = FONTGRID(widget);
577 widget->allocation = *actual;
580 * Make sure the rows and columns are adjusted to fit the actual allocated
583 fontgrid_set_rows_cols(fw, actual);
585 if (GTK_WIDGET_REALIZED(widget))
586 gdk_window_move_resize(widget->window, actual->x, actual->y,
587 actual->width, actual->height);
591 fontgrid_realize(GtkWidget *widget)
594 GdkWindowAttr attributes;
596 gint attributes_mask;
598 g_return_if_fail(widget != NULL);
599 g_return_if_fail(IS_FONTGRID(widget));
601 fw = FONTGRID(widget);
602 GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED);
604 attributes.window_type = GDK_WINDOW_CHILD;
605 attributes.x = widget->allocation.x;
606 attributes.y = widget->allocation.y;
607 attributes.width = widget->allocation.width;
608 attributes.height = widget->allocation.height;
609 attributes.wclass = GDK_INPUT_OUTPUT;
610 attributes.visual = gtk_widget_get_visual(widget);
611 attributes.colormap = gtk_widget_get_colormap(widget);
612 attributes.event_mask = gtk_widget_get_events(widget);
613 attributes.event_mask |= (GDK_EXPOSURE_MASK|GDK_BUTTON_PRESS_MASK|
614 GDK_BUTTON_RELEASE_MASK|GDK_ENTER_NOTIFY_MASK|
615 GDK_POINTER_MOTION_MASK|
616 GDK_KEY_PRESS_MASK|GDK_KEY_RELEASE_MASK|
617 GDK_LEAVE_NOTIFY_MASK|GDK_FOCUS_CHANGE_MASK|
618 GDK_PROPERTY_CHANGE_MASK);
620 attributes_mask = GDK_WA_X|GDK_WA_Y|GDK_WA_VISUAL|GDK_WA_COLORMAP;
622 widget->window = gdk_window_new(gtk_widget_get_parent_window(widget),
623 &attributes, attributes_mask);
624 gdk_window_set_user_data(widget->window, widget);
626 widget->style = gtk_style_attach(widget->style, widget->window);
627 gtk_style_set_background(widget->style, widget->window, GTK_STATE_NORMAL);
630 g_object_unref(G_OBJECT(fw->xor_gc));
633 * Create the GC used to display selected cells.
635 values.foreground.pixel =
636 widget->style->fg[GTK_WIDGET_STATE(widget)].pixel ^
637 widget->style->bg[GTK_WIDGET_STATE(widget)].pixel;
638 (void) memset((char *) &values.background, 0, sizeof(GdkColor));
639 values.function = GDK_XOR;
640 fw->xor_gc = gdk_gc_new_with_values(widget->window, &values,
642 GDK_GC_BACKGROUND|GDK_GC_FUNCTION);
646 fontgrid_locate_glyph(bdf_glyph_t *glyphs, guint32 nglyphs, gint32 code,
647 gboolean exact_match)
651 if (code < 0 || glyphs == 0 || nglyphs == 0)
654 for (l = 0, r = (gint32) (nglyphs - 1); l <= r; ) {
656 if (glyphs[m].encoding < code)
658 else if (glyphs[m].encoding > code)
671 * Adjust to the beginning or end if nothing was found in the search.
673 while (m > 0 && glyphs[m].encoding > code)
675 while (m < (gint32) nglyphs && glyphs[m].encoding < code)
678 return (m < (gint32) nglyphs) ? glyphs + m : 0;
682 fontgrid_get_glyph_points(Fontgrid *fw, gint x, gint y, gint rx, gint by,
686 unsigned char *bmap, *masks = 0;
689 case 1: masks = bdf_onebpp; break;
690 case 2: masks = bdf_twobpp; break;
691 case 4: masks = bdf_fourbpp; break;
692 case 8: masks = bdf_eightbpp; break;
696 bmap = glyph->bitmap;
697 bpr = ((glyph->bbx.width * fw->bpp) + 7) >> 3;
699 for (i = 0; i + y - glyph->bbx.ascent < by && i < glyph->bbx.height; i++) {
700 for (col = j = 0; j + x < rx && j < glyph->bbx.width;
701 j++, col += fw->bpp) {
702 if (bmap[(i * bpr) + (col >> 3)] &
703 masks[(col & 7) / fw->bpp]) {
704 if (fw->points_used == fw->points_size) {
705 if (fw->points_size == 0)
707 (GdkPoint *) g_malloc(sizeof(GdkPoint) << 7);
710 (GdkPoint *) g_realloc(fw->points,
712 (fw->points_size + 128));
713 fw->points_size += 128;
716 fw->points[fw->points_used].x = j + x;
717 fw->points[fw->points_used].y = i + y - glyph->bbx.ascent;
726 fontgrid_get_glyph_points_color(Fontgrid *fw, gint x, gint y, gint rx, gint by,
727 gint color_index, bdf_glyph_t *glyph)
729 gint i, j, bpr, col, byte, di = 0, si, cidx = 0;
730 unsigned char *bmap, *masks = 0;
733 case 1: masks = bdf_onebpp; di = 7; break;
734 case 2: masks = bdf_twobpp; di = 3; break;
735 case 4: masks = bdf_fourbpp; di = 1; break;
736 case 8: masks = bdf_eightbpp; di = 0; break;
740 bmap = glyph->bitmap;
741 bpr = ((glyph->bbx.width * fw->bpp) + 7) >> 3;
743 for (i = 0; i + y - glyph->bbx.ascent < by && i < glyph->bbx.height; i++) {
744 for (col = j = 0; j + x < rx && j < glyph->bbx.width;
745 j++, col += fw->bpp) {
746 si = (col & 7) / fw->bpp;
747 byte = bmap[(i * bpr) + (col >> 3)] & masks[si];
750 * Check to see if the byte matches the color index being
754 byte >>= (di - si) * fw->bpp;
757 if (fw->points_used == fw->points_size) {
758 if (fw->points_size == 0)
759 fw->points = (GdkPoint *)
760 g_malloc(sizeof(GdkPoint) << 6);
762 fw->points = (GdkPoint *)
763 g_realloc(fw->points, sizeof(GdkPoint) *
764 (fw->points_size + 64));
765 fw->points_size += 64;
768 fw->points[fw->points_used].x = j + x;
769 fw->points[fw->points_used].y = i + y - glyph->bbx.ascent;
779 * This routine creates a 24 bits per pixel image of a glyph so it can be
780 * drawn using GtkRGB. This is less complicated than the old method of
781 * collecting and drawing individual pixels of each different color.
784 fontgrid_make_rgb_image(Fontgrid *fw, bdf_glyph_t *glyph)
786 GtkWidget *w = GTK_WIDGET(fw);
787 gint x, y, bpr, rgb_bpr, col, byte, di = 0, si;
788 guchar bg[4], pix[4], *bmap, *masks = 0;
791 * Figure out the background color.
793 bg[0] = (guchar) w->style->bg[GTK_WIDGET_STATE(w)].red;
794 bg[1] = (guchar) w->style->bg[GTK_WIDGET_STATE(w)].green;
795 bg[2] = (guchar) w->style->bg[GTK_WIDGET_STATE(w)].blue;
798 case 1: masks = bdf_onebpp; di = 7; break;
799 case 2: masks = bdf_twobpp; di = 3; break;
800 case 4: masks = bdf_fourbpp; di = 1; break;
801 case 8: masks = bdf_eightbpp; di = 0; break;
804 bmap = glyph->bitmap;
805 bpr = ((glyph->bbx.width * fw->bpp) + 7) >> 3;
807 rgb_bpr = glyph->bbx.width * 3;
808 fw->rgb_used = rgb_bpr * glyph->bbx.height;
810 if (fw->rgb_size < fw->rgb_used) {
811 if (fw->rgb_size == 0)
812 fw->rgb = g_malloc(fw->rgb_used);
814 fw->rgb = g_realloc(fw->rgb, fw->rgb_used);
815 fw->rgb_size = fw->rgb_used;
818 for (y = 0; y < glyph->bbx.height; y++) {
819 for (col = x = 0; x < glyph->bbx.width; x++, col += fw->bpp) {
820 si = (col & 7) / fw->bpp;
822 byte = bmap[(y * bpr) + (col >> 3)] & masks[si];
824 byte >>= (di - si) * fw->bpp;
830 case 1: memset(pix, 0, 3); break;
831 case 2: memset(pix, fw->colors[byte-1], 3); break;
832 case 4: memset(pix, fw->colors[byte-1+4], 3); break;
833 case 8: memset(pix, byte, 3); break;
837 * Set the pixel to the background color.
841 memcpy(&fw->rgb[(y * rgb_bpr) + (x * 3)], pix, 3);
847 fontgrid_draw_encoding(GtkWidget *w, GdkGC *gc, gint x, gint y, gchar *num,
853 if (!GTK_WIDGET_REALIZED(w))
856 dp = encoding_digits;
857 for (i = 0; i < numlen; i++) {
860 else if (num[i] <= '9')
863 d = (num[i] - 'A') + 10;
866 * Copy the next digit into the display array.
868 (void) memcpy((char *) dp, (char *) digits[d].points,
869 sizeof(GdkPoint) * digits[d].npoints);
871 * Position the points.
873 for (j = 0; j < digits[d].npoints; j++) {
877 dp += digits[d].npoints;
884 gdk_draw_points(w->window, gc, encoding_digits, dp - encoding_digits);
888 fontgrid_draw_cells(GtkWidget *widget, gint32 start, gint32 end,
889 gboolean labels, gboolean glyphs)
892 gint x, y, wd, as, ds, len, lx, ly;
897 bdf_glyph_t *glyph, *gp;
898 FontgridInternalPageInfo *pi;
903 if (!GTK_WIDGET_REALIZED(widget) || (labels == FALSE && glyphs == FALSE))
906 fw = FONTGRID(widget);
913 if (!fw->unencoded) {
916 glyph = font->glyphs;
917 nglyphs = font->glyphs_used;
921 * When viewing the unencoded glyph pages, all glyphs are labelled
922 * with an encoding of -1.
928 glyph = font->unencoded;
929 nglyphs = font->unencoded_used;
934 * The initial code to work from.
939 * Locate the glyph closest to the starting code.
941 if ((glyph = fontgrid_locate_glyph(glyph, nglyphs, start, FALSE)) == 0)
946 gc = widget->style->fg_gc[GTK_WIDGET_STATE(widget)];
948 for (ng = 0, i = start; i <= end; i++) {
950 * Only draw those cells that are on the current page.
952 if (i < pi->bcode || i >= pi->bcode + fw->pagesize)
955 if (fw->orientation == GTK_ORIENTATION_HORIZONTAL) {
956 r = (i - n) / fw->cell_cols;
957 c = (i - n) % fw->cell_cols;
959 c = (i - n) / fw->cell_rows;
960 r = (i - n) % fw->cell_rows;
963 x = fw->xoff + (c * fw->cell_width);
964 y = fw->yoff + (r * fw->cell_height);
967 if (!fw->unencoded) {
969 case 8: sprintf(nbuf, "%o", i); break;
970 case 10: sprintf(nbuf, "%d", i); break;
971 case 16: sprintf(nbuf, "%X", i); break;
976 rect.width = fw->cell_width - 2;
977 rect.height = fw->label_height - 2;
978 gdk_draw_rectangle(widget->window, gc, FALSE,
979 rect.x, rect.y, rect.width, rect.height);
986 lx = (x + ((fw->cell_width >> 1) - (wd >> 1))) + 1;
987 ly = (y + ((fw->label_height >> 1) - ((as + ds) >> 1))) + 1;
991 mod = (!fw->unencoded) ? bdf_glyph_modified(font, i, 0) :
992 bdf_glyph_modified(font, i, 1);
994 gdk_window_clear_area(widget->window, rect.x + 1, rect.y + 1,
995 rect.width - 1, rect.height - 1);
997 if (!fw->unencoded && mod) {
998 gdk_draw_rectangle(widget->window, gc, TRUE,
999 rect.x + 2, rect.y + 2,
1000 rect.width - 3, rect.height - 3);
1001 fontgrid_draw_encoding(widget, fw->xor_gc, lx, ly, nbuf, len);
1002 if (gp && gp->encoding == i) {
1010 * If the glyph exists, then darken the rectangle to indicate
1013 if (gp && gp->encoding == i) {
1014 gdk_draw_rectangle(widget->window, gc, FALSE,
1015 rect.x + 1, rect.y + 1,
1016 rect.width - 2, rect.height - 2);
1022 fontgrid_draw_encoding(widget, gc, lx, ly, nbuf, len);
1028 rect.y = y + fw->label_height + 1;
1029 rect.width = fw->cell_width - 2;
1030 rect.height = (fw->cell_height - fw->label_height) - 2;
1032 if (i <= 0xffff && nglyphs > 0 && glyph->encoding == i) {
1038 * Set the right and left limits for generating points.
1040 lx = x + fw->cell_width - 2;
1041 ly = y + fw->cell_height - 2;
1044 * Adjust the X,Y coordinate pair so the bitmap points will
1045 * be generated to center the glyphs horizontally and align
1046 * them to the BDF font's baseline vertically.
1048 x += (fw->cell_width >> 1) -
1049 ((font->bbx.width + font->bbx.x_offset) >> 1) + 1;
1050 y += fw->label_height + font->bbx.ascent + 3;
1052 if (IsSelected(glyph->encoding, pi->selmap)) {
1053 gdk_draw_rectangle(widget->window, gc, TRUE,
1054 rect.x + 1, rect.y + 1,
1055 rect.width - 1, rect.height - 1);
1056 if (glyph->bytes > 0) {
1057 fontgrid_get_glyph_points(fw, x, y, lx, ly, glyph);
1058 if (fw->points_used > 0)
1059 gdk_draw_points(widget->window, fw->xor_gc,
1060 fw->points, fw->points_used);
1064 * The glyph is not selected, so draw it according to
1065 * the bytes-per-pixel of the font.
1067 gdk_window_clear_area(widget->window, rect.x, rect.y,
1068 rect.width, rect.height);
1069 if (glyph->bytes > 0) {
1070 fontgrid_make_rgb_image(fw, glyph);
1071 gdk_draw_rgb_image(widget->window, gc,
1072 x, y - glyph->bbx.ascent,
1075 GDK_RGB_DITHER_NONE,
1076 fw->rgb, glyph->bbx.width * 3);
1080 if (ng == nglyphs) {
1086 * Clear the empty cell.
1088 if (i <= 0xffff && IsSelected(i, pi->selmap))
1089 gdk_draw_rectangle(widget->window, gc, TRUE,
1090 rect.x + 1, rect.y + 1,
1091 rect.width - 1, rect.height - 1);
1093 gdk_window_clear_area(widget->window, rect.x, rect.y,
1094 rect.width, rect.height);
1096 gdk_draw_line(widget->window, gc, rect.x, rect.y,
1097 rect.x + rect.width,
1098 rect.y + rect.height);
1099 gdk_draw_line(widget->window, gc,
1100 rect.x + rect.width, rect.y,
1101 rect.x, rect.y + rect.height);
1110 fontgrid_draw(GtkWidget *widget, GdkRegion *region)
1114 guint16 wd, ht, gw, gh;
1118 g_return_if_fail(widget != NULL);
1119 g_return_if_fail(IS_FONTGRID(widget));
1121 fw = FONTGRID(widget);
1123 gc = widget->style->fg_gc[GTK_WIDGET_STATE(widget)];
1125 gw = fw->cell_width * fw->cell_cols;
1126 gh = fw->cell_height * fw->cell_rows;
1127 wd = widget->allocation.width;
1128 ht = widget->allocation.height;
1129 x = fw->xoff = ((wd >> 1) - (gw >> 1)) - 1;
1130 y = fw->yoff = ((ht >> 1) - (gh >> 1)) - 1;
1133 * Draw the horizontal lines.
1135 for (i = 0; i <= fw->cell_rows; i++) {
1136 gdk_draw_line(widget->window, gc, x, y, x + gw, y);
1139 * Only draw the second line if this is not the last line.
1141 if (i < fw->cell_rows)
1142 gdk_draw_line(widget->window, gc, x, y + fw->label_height,
1143 x + gw, y + fw->label_height);
1145 y += fw->cell_height;
1149 * Draw the vertical lines.
1154 for (i = 0; i <= fw->cell_cols; i++) {
1155 gdk_draw_line(widget->window, gc, x, y, x, y + gh);
1156 x += fw->cell_width;
1159 start = (!fw->unencoded) ? fw->npage.bcode : fw->upage.bcode;
1160 end = start + (gint32) (fw->pagesize - 1);
1162 fontgrid_draw_cells(widget, start, end, TRUE, TRUE);
1166 fontgrid_select_range(Fontgrid *fw, gint32 start, gint32 end)
1169 FontgridInternalPageInfo *pi;
1177 pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
1179 for (i = start; i <= end; i++)
1180 Select(i, pi->selmap);
1183 * Adjust the start and end values to the current page to determine which
1184 * cells need to be redrawn.
1186 tmp = pi->bcode + (fw->pagesize - 1);
1187 if (start >= tmp || end < pi->bcode)
1190 if (start < pi->bcode)
1194 fontgrid_draw_cells(GTK_WIDGET(fw), start, end, FALSE, TRUE);
1198 fontgrid_deselect_range(Fontgrid *fw, gint32 start, gint32 end)
1201 FontgridInternalPageInfo *pi;
1209 pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
1210 for (i = start; i <= end; i++) {
1211 if (IsSelected(i, pi->selmap)) {
1212 Unselect(i, pi->selmap);
1213 if (i >= pi->bcode && i <= pi->bcode + (fw->pagesize - 1))
1214 fontgrid_draw_cells(GTK_WIDGET(fw), i, i, FALSE, TRUE);
1220 fontgrid_deselect_all(Fontgrid *fw)
1222 FontgridInternalPageInfo *pi, *opi;
1224 if (!fw->unencoded) {
1232 if (pi->sel_start != -1 || pi->sel_end != -1)
1233 fontgrid_deselect_range(fw, pi->bcode, pi->bcode + fw->pagesize - 1);
1234 else if (opi->sel_start != -1 || opi->sel_end != -1)
1235 fontgrid_deselect_range(fw, opi->bcode, opi->bcode + fw->pagesize - 1);
1238 * Now clear the selected bitmaps.
1240 (void) memset((char *) pi->selmap, 0, sizeof(guint32) * 2048);
1241 (void) memset((char *) opi->selmap, 0, sizeof(guint32) * 2048);
1244 * Reset the selection start and end points.
1246 pi->sel_start = pi->sel_end = opi->sel_start = opi->sel_end = -1;
1250 fontgrid_draw_focus(GtkWidget *widget, GdkRectangle *area)
1253 gint x, y, wd, ht, fwidth, fpad;
1256 * Do something with this later to make sure the focus line width
1257 * is set in the GC's.
1259 gtk_widget_style_get(widget,
1260 "focus-line-width", &fwidth,
1261 "focus-padding", &fpad, NULL);
1263 gc = widget->style->bg_gc[GTK_WIDGET_STATE(widget)];
1265 x = (widget->style->xthickness + fwidth + fpad) - 1;
1266 y = (widget->style->ythickness + fwidth + fpad) - 1;
1267 wd = (widget->allocation.width - (x * 2));
1268 ht = (widget->allocation.height - (y * 2));
1270 if (GTK_WIDGET_HAS_FOCUS(widget))
1271 gtk_paint_focus(widget->style, widget->window, GTK_WIDGET_STATE(widget),
1272 area, widget, "fontgrid", x, y, wd, ht);
1274 gdk_gc_set_clip_rectangle(gc, area);
1275 gdk_draw_rectangle(widget->window, gc, FALSE, x, y, wd - 1, ht - 1);
1276 gdk_gc_set_clip_rectangle(gc, 0);
1281 fontgrid_expose(GtkWidget *widget, GdkEventExpose *event)
1284 * Paint the shadow first.
1286 if (GTK_WIDGET_DRAWABLE(widget))
1287 gtk_paint_shadow(widget->style, widget->window,
1288 GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
1289 &event->area, widget, "fontgrid",
1291 widget->allocation.width,
1292 widget->allocation.height);
1294 fontgrid_draw(widget, event->region);
1296 fontgrid_draw_focus(widget, &event->area);
1302 fontgrid_focus_in(GtkWidget *widget, GdkEventFocus *event)
1304 g_return_val_if_fail(widget != NULL, FALSE);
1305 g_return_val_if_fail(IS_FONTGRID(widget), FALSE);
1306 g_return_val_if_fail(event != NULL, FALSE);
1308 GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_FOCUS);
1309 fontgrid_draw_focus(widget, 0);
1315 fontgrid_focus_out(GtkWidget *widget, GdkEventFocus *event)
1317 g_return_val_if_fail(widget != NULL, FALSE);
1318 g_return_val_if_fail(IS_FONTGRID(widget), FALSE);
1319 g_return_val_if_fail(event != NULL, FALSE);
1321 GTK_WIDGET_UNSET_FLAGS(widget, GTK_HAS_FOCUS);
1322 fontgrid_draw_focus(widget, 0);
1328 fontgrid_lose_selection(GtkWidget *widget, GdkEventSelection *event)
1331 FontgridInternalPageInfo *pi;
1334 fw = FONTGRID(widget);
1336 pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
1338 if (pi->sel_start != pi->sel_end) {
1339 code = pi->sel_start;
1340 fontgrid_deselect_all(fw);
1341 pi->sel_end = pi->sel_start = code;
1342 Select(pi->sel_start, pi->selmap);
1343 fontgrid_draw_cells(widget, code, code, FALSE, TRUE);
1349 /**************************************************************************
1353 **************************************************************************/
1356 fontgrid_neighbor_pages(Fontgrid *fw, gint32 page, gint32 *prev, gint32 *next)
1358 gint32 bcode, l, r, m;
1360 bdf_glyph_t *glyphs;
1361 FontgridInternalPageInfo *pip;
1363 pip = (!fw->unencoded) ? &fw->npage : &fw->upage;
1365 if (fw->noblanks == FALSE ||
1366 (fw->unencoded == FALSE &&
1367 (fw->font == 0 || fw->font->glyphs_used == 0))) {
1369 *next = (page < pip->maxpage) ? page + 1 : -1;
1373 bcode = page * fw->pagesize;
1375 if (!fw->unencoded) {
1376 glyphs = fw->font->glyphs;
1377 nglyphs = fw->font->glyphs_used;
1379 glyphs = fw->font->unencoded;
1380 nglyphs = fw->font->unencoded_used;
1384 * Do a binary search to find the the preceding page number.
1386 for (l = m = 0, r = nglyphs - 1; l < r; ) {
1388 if (glyphs[m].encoding < bcode)
1390 else if (glyphs[m].encoding > bcode)
1402 * In case the search ends on a code in the specified page.
1404 while (r >= 0 && glyphs[r].encoding >= bcode)
1408 * Set the previous page code.
1410 *prev = (r >= 0) ? glyphs[r].encoding / fw->pagesize : -1;
1413 * Determine the following page code.
1417 while (r < nglyphs && glyphs[r].encoding < bcode + fw->pagesize)
1420 *next = (r < nglyphs) ? glyphs[r].encoding / fw->pagesize : -1;
1423 /**************************************************************************
1425 * Selection routines.
1427 **************************************************************************/
1430 start_selection(GtkWidget *widget, GdkEventButton *event)
1433 gint16 x, y, row, col;
1436 FontgridInternalPageInfo *pi, *opi;
1437 FontgridSelectionInfo sinfo;
1439 fw = FONTGRID(widget);
1442 * Deal with the focus issue first.
1444 if (!GTK_WIDGET_HAS_FOCUS(widget)) {
1445 GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_FOCUS);
1446 (void) fontgrid_draw_focus(widget, NULL);
1449 x = (gint16) event->x;
1450 y = (gint16) event->y;
1452 col = fw->xoff + (fw->cell_width * fw->cell_cols);
1453 row = fw->yoff + (fw->cell_height * fw->cell_rows);
1456 * If the button press is not in the font grid proper, just return.
1458 if (x < fw->xoff || x >= col || y < fw->yoff || y >= row)
1462 * Calculate the row and column that was clicked.
1464 row = (y - fw->yoff) / fw->cell_height;
1465 col = (x - fw->xoff) / fw->cell_width;
1467 if (!fw->unencoded) {
1475 if (fw->orientation == GTK_ORIENTATION_HORIZONTAL)
1476 code = pi->bcode + (row * fw->cell_cols) + col;
1478 code = pi->bcode + (col * fw->cell_rows) + row;
1481 * Any code greater than the maximum is ignored.
1489 gp = fontgrid_locate_glyph(fw->font->glyphs, fw->font->glyphs_used,
1492 gp = fontgrid_locate_glyph(fw->font->unencoded,
1493 fw->font->unencoded_used,
1498 empty_glyph.encoding = code;
1502 if (code != pi->sel_start || code != pi->sel_end) {
1504 * Clear any existing selection.
1506 if (pi->sel_start != -1 || pi->sel_end != -1 ||
1507 opi->sel_start != -1 || opi->sel_end != -1)
1508 fontgrid_deselect_all(fw);
1510 Select(code, pi->selmap);
1512 fontgrid_draw_cells(widget, code, code, FALSE, TRUE);
1514 pi->sel_start = pi->sel_end = code;
1517 * Clear the last click time to avoid situations where the second
1518 * click on a different cell will cause the select callback to be
1525 sinfo.num_glyphs = 1;
1526 sinfo.start = pi->sel_start;
1527 sinfo.end = pi->sel_end;
1528 sinfo.base = fw->base;
1529 sinfo.unencoded = fw->unencoded;
1530 if (event->type == GDK_BUTTON_PRESS &&
1531 event->time - fw->last_click >= fw->mclick_time) {
1532 sinfo.reason = FONTGRID_START_SELECTION;
1533 g_signal_emit(G_OBJECT(fw), fontgrid_signals[SELECTION_START], 0,
1535 } else if (event->type == GDK_2BUTTON_PRESS) {
1536 sinfo.reason = FONTGRID_ACTIVATE;
1537 g_signal_emit(G_OBJECT(fw), fontgrid_signals[ACTIVATE], 0,
1540 fw->last_click = event->time;
1544 extend_selection(GtkWidget *widget, gint16 x, gint16 y)
1550 gboolean call_extend;
1551 FontgridInternalPageInfo *pi;
1552 FontgridSelectionInfo sinfo;
1554 fw = FONTGRID(widget);
1557 * Deal with the focus issue first.
1559 if (!GTK_WIDGET_HAS_FOCUS(widget)) {
1560 GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_FOCUS);
1561 (void) fontgrid_draw_focus(widget, NULL);
1564 col = fw->xoff + (fw->cell_width * fw->cell_cols);
1565 row = fw->yoff + (fw->cell_height * fw->cell_rows);
1568 * If the button press is not in the font grid proper, just return.
1570 if (x < fw->xoff || x >= col || y < fw->yoff || y >= row)
1574 * Calculate the row and column that was clicked.
1576 row = (y - fw->yoff) / fw->cell_height;
1577 col = (x - fw->xoff) / fw->cell_width;
1579 pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
1581 if (fw->orientation == GTK_ORIENTATION_HORIZONTAL)
1582 code = pi->bcode + (row * fw->cell_cols) + col;
1584 code = pi->bcode + (col * fw->cell_rows) + row;
1587 * Any code greater than the maximum is ignored.
1595 gp = fontgrid_locate_glyph(fw->font->glyphs, fw->font->glyphs_used,
1598 gp = fontgrid_locate_glyph(fw->font->unencoded,
1599 fw->font->unencoded_used,
1602 empty_glyph.encoding = code;
1607 call_extend = FALSE;
1608 if (code > pi->sel_end) {
1610 if (code <= pi->sel_start)
1611 fontgrid_deselect_range(fw, pi->sel_end, code - 1);
1613 if (pi->sel_end < pi->sel_start) {
1614 fontgrid_deselect_range(fw, pi->sel_end, pi->sel_start - 1);
1615 fontgrid_select_range(fw, pi->sel_start + 1, code);
1617 fontgrid_select_range(fw, pi->sel_end, code);
1619 } else if (code < pi->sel_end) {
1621 if (code < pi->sel_start) {
1622 if (pi->sel_end > pi->sel_start) {
1623 fontgrid_deselect_range(fw, pi->sel_start + 1, pi->sel_end);
1624 fontgrid_select_range(fw, code, pi->sel_start);
1626 fontgrid_select_range(fw, code, pi->sel_end);
1628 fontgrid_deselect_range(fw, code + 1, pi->sel_end);
1633 if (call_extend == TRUE) {
1634 if (pi->sel_start == pi->sel_end) {
1636 sinfo.num_glyphs = 1;
1639 sinfo.num_glyphs = 0;
1641 sinfo.start = pi->sel_start;
1642 sinfo.end = pi->sel_end;
1643 sinfo.base = fw->base;
1644 sinfo.unencoded = fw->unencoded;
1645 sinfo.reason = FONTGRID_EXTEND_SELECTION;
1646 g_signal_emit(G_OBJECT(fw), fontgrid_signals[SELECTION_EXTEND], 0,
1652 end_selection(GtkWidget *widget, GdkEventButton *event)
1656 FontgridInternalPageInfo *pi;
1657 FontgridSelectionInfo sinfo;
1659 fw = FONTGRID(widget);
1661 pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
1663 if (pi->sel_start != pi->sel_end) {
1665 * Assert ownership of the clipboard if there is a selection of
1666 * more than one glyph.
1668 gdk_selection_owner_set(widget->window, FONTGRID_CLIPBOARD,
1669 GDK_CURRENT_TIME, FALSE);
1671 sinfo.num_glyphs = 0;
1676 gp = fontgrid_locate_glyph(fw->font->glyphs,
1677 fw->font->glyphs_used,
1678 pi->sel_start, TRUE);
1680 gp = fontgrid_locate_glyph(fw->font->unencoded,
1681 fw->font->unencoded_used,
1682 pi->sel_start, TRUE);
1684 empty_glyph.encoding = pi->sel_start;
1690 sinfo.num_glyphs = 1;
1692 sinfo.start = pi->sel_start;
1693 sinfo.end = pi->sel_end;
1694 sinfo.base = fw->base;
1695 sinfo.unencoded = fw->unencoded;
1696 sinfo.reason = FONTGRID_END_SELECTION;
1697 g_signal_emit(G_OBJECT(fw), fontgrid_signals[SELECTION_END], 0,
1702 paste_selection(GtkWidget *widget, GdkEventButton *event)
1704 start_selection(widget, event);
1706 if (event->state & GDK_SHIFT_MASK)
1707 fontgrid_paste_selection(FONTGRID(widget), FONTGRID_INSERT_PASTE);
1708 else if (event->state & GDK_CONTROL_MASK)
1709 fontgrid_paste_selection(FONTGRID(widget), FONTGRID_MERGE_PASTE);
1711 fontgrid_paste_selection(FONTGRID(widget), FONTGRID_NORMAL_PASTE);
1715 copy_selection(GtkWidget *widget, GdkEventButton *event)
1717 fontgrid_copy_selection(FONTGRID(widget));
1720 /**************************************************************************
1722 * Button, pointer motion, and keyboard handling routines.
1724 **************************************************************************/
1727 fontgrid_button_press(GtkWidget *widget, GdkEventButton *event)
1729 switch (event->button) {
1731 if (event->state & GDK_SHIFT_MASK)
1732 extend_selection(widget, (gint16) event->x, (gint16) event->y);
1734 start_selection(widget, event);
1736 case 2: paste_selection(widget, event); break;
1737 case 3: copy_selection(widget, event); break;
1744 fontgrid_button_release(GtkWidget *widget, GdkEventButton *event)
1746 switch (event->button) {
1747 case 1: end_selection(widget, event); break;
1755 fontgrid_motion_notify(GtkWidget *widget, GdkEventMotion *event)
1757 if (event->state & GDK_BUTTON1_MASK)
1758 extend_selection(widget, (gint16) event->x, (gint16) event->y);
1761 * Don't need these at the moment.
1763 if (event->state & GDK_BUTTON2_MASK) {
1765 if (event->state & GDK_BUTTON3_MASK) {
1772 fontgrid_shift_key_press(GtkWidget *widget, GdkEventKey *event)
1777 gint32 code, pageno;
1779 gboolean signal_extend, activate;
1780 FontgridInternalPageInfo *pi, *opi;
1781 FontgridSelectionInfo sinfo;
1783 g_return_val_if_fail(widget != NULL, FALSE);
1784 g_return_val_if_fail(IS_FONTGRID(widget), FALSE);
1785 g_return_val_if_fail(event != NULL, FALSE);
1787 fw = FONTGRID(widget);
1790 * For number keys, use them to add up a count that will effect the
1791 * behavior of the other keys.
1793 if (event->keyval >= GDK_0 && event->keyval <= GDK_9) {
1794 fw->count = (fw->count * 10) + (event->keyval - GDK_0);
1798 if (!fw->unencoded) {
1801 gp = (fw->font && fw->font->glyphs_used) ?
1802 (fw->font->glyphs + (fw->font->glyphs_used - 1)) : 0;
1806 gp = (fw->font && fw->font->unencoded_used) ?
1807 (fw->font->unencoded + (fw->font->unencoded_used - 1)) : 0;
1814 if ((count = fw->count) == 0)
1817 keyval = event->keyval;
1818 switch (event->keyval) {
1820 case GDK_KP_Page_Up:
1821 count *= fw->pagesize;
1825 case GDK_KP_Page_Down:
1826 count *= fw->pagesize;
1831 count = (pi->pageno - pi->minpage) * fw->pagesize;
1836 count = (pi->maxpage - pi->pageno) * fw->pagesize;
1849 if (fw->orientation == GTK_ORIENTATION_VERTICAL)
1850 code -= (fw->cell_rows * count);
1861 * Make sure that when on the unencoded pages, the final glyph is
1862 * the limit unlike the encoded pages where the max value is 0xffff.
1864 if ((fw->unencoded &&
1865 (gp == 0 || code == gp->encoding)) ||
1871 if (fw->orientation == GTK_ORIENTATION_VERTICAL)
1872 code += (fw->cell_rows * count);
1876 if (fw->unencoded && code > gp->encoding)
1877 code = gp->encoding;
1878 else if (code > 0xffff)
1889 if (fw->orientation == GTK_ORIENTATION_HORIZONTAL)
1890 code -= (fw->cell_cols * count);
1901 * Make sure that when on the unencoded pages, the final glyph is
1902 * the limit unlike the encoded pages where the max value is 0xffff.
1904 if ((fw->unencoded &&
1905 (gp == 0 || code == gp->encoding)) ||
1911 if (fw->orientation == GTK_ORIENTATION_HORIZONTAL)
1912 code += (fw->cell_cols * count);
1916 if (fw->unencoded && code > gp->encoding)
1917 code = gp->encoding;
1918 else if (code > 0xffff)
1924 pi->sel_end = pi->sel_start;
1931 signal_extend = FALSE;
1932 if (code > pi->sel_end) {
1933 signal_extend = TRUE;
1934 if (code <= pi->sel_start)
1935 fontgrid_deselect_range(fw, pi->sel_end, code - 1);
1937 if (pi->sel_end < pi->sel_start) {
1938 fontgrid_deselect_range(fw, pi->sel_end, pi->sel_start - 1);
1939 fontgrid_select_range(fw, pi->sel_start + 1, code);
1941 fontgrid_select_range(fw, pi->sel_end, code);
1943 } else if (code < pi->sel_end) {
1944 signal_extend = TRUE;
1945 if (code < pi->sel_start) {
1946 if (pi->sel_end > pi->sel_start) {
1947 fontgrid_deselect_range(fw, pi->sel_start + 1, pi->sel_end);
1948 fontgrid_select_range(fw, code, pi->sel_start);
1950 fontgrid_select_range(fw, code, pi->sel_end);
1952 fontgrid_deselect_range(fw, code + 1, pi->sel_end);
1958 * If the selection endpoint is on some page other than the current
1959 * page, make sure the page holding the end point is made visible.
1961 pageno = code / fw->pagesize;
1962 if (pageno != pi->pageno) {
1963 fw->no_sel_callback = TRUE;
1964 fontgrid_goto_page(fw, pageno);
1972 if (signal_extend) {
1973 if (pi->sel_start == pi->sel_end) {
1975 * Set up and emit the selection start signal.
1978 gp = fontgrid_locate_glyph(fw->font->glyphs,
1979 fw->font->glyphs_used,
1982 gp = fontgrid_locate_glyph(fw->font->unencoded,
1983 fw->font->unencoded_used,
1986 empty_glyph.encoding = code;
1990 sinfo.num_glyphs = 1;
1993 sinfo.num_glyphs = 0;
1995 sinfo.start = pi->sel_start;
1996 sinfo.end = pi->sel_end;
1997 sinfo.base = fw->base;
1998 sinfo.unencoded = fw->unencoded;
2001 sinfo.reason = FONTGRID_EXTEND_SELECTION;
2002 g_signal_emit(G_OBJECT(fw), fontgrid_signals[SELECTION_EXTEND],
2005 sinfo.reason = FONTGRID_ACTIVATE;
2006 g_signal_emit(G_OBJECT(fw), fontgrid_signals[ACTIVATE], 0,
2015 fontgrid_key_press(GtkWidget *widget, GdkEventKey *event)
2019 gint32 code, pageno;
2022 FontgridInternalPageInfo *pi, *opi;
2023 FontgridSelectionInfo sinfo;
2025 g_return_val_if_fail(widget != NULL, FALSE);
2026 g_return_val_if_fail(IS_FONTGRID(widget), FALSE);
2027 g_return_val_if_fail(event != NULL, FALSE);
2029 if (event->state & GDK_SHIFT_MASK)
2030 return fontgrid_shift_key_press(widget, event);
2032 fw = FONTGRID(widget);
2035 * For number keys, use them to add up a count that will effect the
2036 * behavior of the other keys.
2038 if (event->keyval >= GDK_0 && event->keyval <= GDK_9) {
2039 fw->count = (fw->count * 10) + (event->keyval - GDK_0);
2043 if (!fw->unencoded) {
2046 gp = (fw->font && fw->font->glyphs_used) ?
2047 (fw->font->glyphs + (fw->font->glyphs_used - 1)) : 0;
2051 gp = (fw->font && fw->font->unencoded_used) ?
2052 (fw->font->unencoded + (fw->font->unencoded_used - 1)) : 0;
2057 code = pi->sel_start;
2059 if ((count = fw->count) == 0)
2062 switch (event->keyval) {
2070 if (fw->orientation == GTK_ORIENTATION_VERTICAL)
2071 code -= (fw->cell_rows * count);
2082 * Make sure that when on the unencoded pages, the final glyph is
2083 * the limit unlike the encoded pages where the max value is 0xffff.
2085 if ((fw->unencoded &&
2086 (gp == 0 || code == gp->encoding)) ||
2092 if (fw->orientation == GTK_ORIENTATION_VERTICAL)
2093 code += (fw->cell_rows * count);
2097 if (fw->unencoded && code > gp->encoding)
2098 code = gp->encoding;
2099 else if (code > 0xffff)
2110 if (fw->orientation == GTK_ORIENTATION_HORIZONTAL)
2111 code -= (fw->cell_cols * count);
2122 * Make sure that when on the unencoded pages, the final glyph is
2123 * the limit unlike the encoded pages where the max value is 0xffff.
2125 if ((fw->unencoded &&
2126 (gp == 0 || code == gp->encoding)) ||
2132 if (fw->orientation == GTK_ORIENTATION_HORIZONTAL)
2133 code += (fw->cell_cols * count);
2137 if (fw->unencoded && code > gp->encoding)
2138 code = gp->encoding;
2139 else if (code > 0xffff)
2144 case GDK_KP_Page_Up:
2145 fw->from_keyboard = TRUE;
2146 fontgrid_goto_previous_page(fw);
2150 case GDK_KP_Page_Down:
2151 fw->from_keyboard = TRUE;
2152 fontgrid_goto_next_page(fw);
2157 fw->from_keyboard = TRUE;
2158 fontgrid_goto_first_page(fw);
2163 fw->from_keyboard = TRUE;
2164 fontgrid_goto_last_page(fw);
2169 pi->sel_end = pi->sel_start;
2175 fontgrid_cut_selection(fw);
2182 * This turns off the selection which means the cursor is effectively
2183 * turned off even for the fontgrid_goto_page() call. The reason is that
2184 * for keyboard navigation, the cursor should move up and down by rows and
2185 * not whole pages when a page change occurs.
2187 fontgrid_deselect_all(fw);
2189 pageno = code / fw->pagesize;
2190 if (pageno != pi->pageno) {
2191 fw->no_sel_callback = TRUE;
2192 fontgrid_goto_page(fw, pageno);
2195 pi->sel_start = pi->sel_end = code;
2196 Select(code, pi->selmap);
2197 fontgrid_draw_cells(widget, code, code, FALSE, TRUE);
2205 * Set up and emit the selection start signal.
2208 gp = fontgrid_locate_glyph(fw->font->glyphs, fw->font->glyphs_used,
2211 gp = fontgrid_locate_glyph(fw->font->unencoded, fw->font->unencoded_used,
2214 empty_glyph.encoding = code;
2218 sinfo.num_glyphs = 1;
2219 sinfo.start = pi->sel_start;
2220 sinfo.end = pi->sel_end;
2221 sinfo.base = fw->base;
2222 sinfo.unencoded = fw->unencoded;
2225 sinfo.reason = FONTGRID_START_SELECTION;
2226 g_signal_emit(G_OBJECT(fw), fontgrid_signals[SELECTION_START], 0,
2229 sinfo.reason = FONTGRID_ACTIVATE;
2230 g_signal_emit(G_OBJECT(fw), fontgrid_signals[ACTIVATE], 0, &sinfo);
2236 /**************************************************************************
2238 * Class and instance setup.
2240 **************************************************************************/
2243 fontgrid_class_init(gpointer g_class, gpointer class_data)
2245 GObjectClass *gocp = G_OBJECT_CLASS(g_class);
2246 GtkObjectClass *ocp = GTK_OBJECT_CLASS(g_class);
2247 GtkWidgetClass *wcp = GTK_WIDGET_CLASS(g_class);
2250 * Set the class global variables.
2252 parent_class = g_type_class_peek_parent(g_class);
2255 * GObject class functions.
2257 gocp->set_property = fontgrid_set_property;
2258 gocp->get_property = fontgrid_get_property;
2259 gocp->finalize = fontgrid_finalize;
2262 * GtkObjectClass functions.
2264 ocp->destroy = fontgrid_destroy;
2267 * Instance functions.
2269 wcp->size_request = fontgrid_preferred_size;
2270 wcp->size_allocate = fontgrid_actual_size;
2271 wcp->realize = fontgrid_realize;
2272 wcp->expose_event = fontgrid_expose;
2273 wcp->focus_in_event = fontgrid_focus_in;
2274 wcp->focus_out_event = fontgrid_focus_out;
2275 wcp->button_press_event = fontgrid_button_press;
2276 wcp->button_release_event = fontgrid_button_release;
2277 wcp->motion_notify_event = fontgrid_motion_notify;
2278 wcp->key_press_event = fontgrid_key_press;
2279 wcp->selection_clear_event = fontgrid_lose_selection;
2282 * Add parameters (a.k.a. resource) types.
2284 g_object_class_install_property(gocp, PROP_CODE_BASE,
2285 g_param_spec_uint("codeBase",
2287 _("Override for the code base (oct, dec, hex) for glyph codes."),
2291 G_PARAM_READWRITE));
2292 g_object_class_install_property(gocp, PROP_POWER2,
2293 g_param_spec_boolean("powersOfTwo",
2295 _("Indicate whether the grid display should be a power-of-two rows."),
2297 G_PARAM_READWRITE));
2299 g_object_class_install_property(gocp, PROP_ORIENTATION,
2300 g_param_spec_enum("orientation",
2302 _("Should the grid display vertically or horizontally."),
2303 GTK_TYPE_ORIENTATION,
2304 GTK_ORIENTATION_HORIZONTAL,
2305 G_PARAM_READWRITE));
2307 g_object_class_install_property(gocp, PROP_FONT,
2308 g_param_spec_pointer("font",
2310 _("Font to be displayed."),
2311 G_PARAM_READWRITE));
2313 g_object_class_install_property(gocp, PROP_POINT_SIZE,
2314 g_param_spec_uint("pointSize",
2316 _("Set the default point size for new fonts."),
2320 G_PARAM_READWRITE));
2322 g_object_class_install_property(gocp, PROP_SPACING,
2323 g_param_spec_int("spacing",
2325 _("Set the default glyph spacing."),
2329 G_PARAM_READWRITE));
2331 g_object_class_install_property(gocp, PROP_SKIP_BLANKS,
2332 g_param_spec_boolean("skipBlankPages",
2333 _("Skip blank pages"),
2334 _("Avoid displaying pages with no glyphs."),
2336 G_PARAM_READWRITE));
2338 g_object_class_install_property(gocp, PROP_OVERWRITE,
2339 g_param_spec_boolean("overwriteMode",
2340 _("Overwrite mode"),
2341 _("Pasting the selection overwrites."),
2343 G_PARAM_READWRITE));
2345 g_object_class_install_property(gocp, PROP_COLORS,
2346 g_param_spec_pointer("colorList",
2348 _("Colors to be used for glyphs having bits-per-pixel > 1."),
2349 G_PARAM_READWRITE));
2351 g_object_class_install_property(gocp, PROP_INITIAL_GLYPH,
2352 g_param_spec_int("initialGlyph",
2354 _("Code of the glyph to be displayed first."),
2358 G_PARAM_READWRITE));
2360 g_object_class_install_property(gocp, PROP_BPP,
2361 g_param_spec_int("bitsPerPixel",
2362 _("Bits per pixel"),
2363 _("Number of bits per pixel for grayscale glyphs."),
2367 G_PARAM_READWRITE));
2369 g_object_class_install_property(gocp, PROP_HRES,
2370 g_param_spec_int("horizontalResolution",
2371 _("Horizontal resolution"),
2372 _("Set the default horizontal resolution for new fonts."),
2376 G_PARAM_READWRITE));
2378 g_object_class_install_property(gocp, PROP_VRES,
2379 g_param_spec_int("verticalResolution",
2380 _("Vertical resolution"),
2381 _("Set the default vertical resolution for new fonts."),
2385 G_PARAM_READWRITE));
2388 * Add the signals these objects emit.
2390 fontgrid_signals[SELECTION_START] =
2391 g_signal_new("selection-start",
2392 G_TYPE_FROM_CLASS(gocp),
2394 G_STRUCT_OFFSET(FontgridClass, selection_start),
2396 g_cclosure_marshal_VOID__POINTER,
2400 fontgrid_signals[SELECTION_EXTEND] =
2401 g_signal_new("selection-extend",
2402 G_TYPE_FROM_CLASS(gocp),
2404 G_STRUCT_OFFSET(FontgridClass, selection_extend),
2406 g_cclosure_marshal_VOID__POINTER,
2410 fontgrid_signals[SELECTION_END] =
2411 g_signal_new("selection-end",
2412 G_TYPE_FROM_CLASS(gocp),
2414 G_STRUCT_OFFSET(FontgridClass, selection_end),
2416 g_cclosure_marshal_VOID__POINTER,
2420 fontgrid_signals[ACTIVATE] =
2421 g_signal_new("activate",
2422 G_TYPE_FROM_CLASS(gocp),
2424 G_STRUCT_OFFSET(FontgridClass, activate),
2426 g_cclosure_marshal_VOID__POINTER,
2430 fontgrid_signals[MODIFIED] =
2431 g_signal_new("modified",
2432 G_TYPE_FROM_CLASS(gocp),
2434 G_STRUCT_OFFSET(FontgridClass, modified),
2436 g_cclosure_marshal_VOID__POINTER,
2440 fontgrid_signals[TURN_TO_PAGE] =
2441 g_signal_new("turn_to_page",
2442 G_TYPE_FROM_CLASS(gocp),
2444 G_STRUCT_OFFSET(FontgridClass, page),
2446 g_cclosure_marshal_VOID__POINTER,
2453 fontgrid_init(GTypeInstance *obj, gpointer g_class)
2455 Fontgrid *fw = FONTGRID(obj);
2456 FontgridInternalPageInfo *pi;
2460 GTK_WIDGET_SET_FLAGS(fw, GTK_CAN_FOCUS);
2462 gtk_widget_style_get(GTK_WIDGET(fw),
2463 "focus-line-width", &fwidth,
2464 "focus-padding", &fpad,
2469 fw->overwrite = TRUE;
2470 fw->noblanks = TRUE;
2471 fw->orientation = GTK_ORIENTATION_HORIZONTAL;
2472 fw->point_size = 12;
2473 fw->spacing = BDF_CHARCELL;
2475 fw->initial_glyph = 0;
2479 gdk_drawable_get_screen(GDK_DRAWABLE(gdk_get_default_root_window()));
2480 fw->hres = (gint32) ((((double) gdk_screen_get_width(screen)) * 25.4) /
2481 ((double) gdk_screen_get_width_mm(screen)) + 0.5);
2482 fw->vres = (gint32) ((((double) gdk_screen_get_height(screen)) * 25.4) /
2483 ((double) gdk_screen_get_height_mm(screen)) + 0.5);
2485 fw->cell_rows = FGRID_DEFAULT_ROWS;
2486 fw->cell_cols = FGRID_DEFAULT_COLS;
2488 fw->hmargin = fw->widget.style->xthickness + fwidth + fpad + fw->border;
2489 fw->vmargin = fw->widget.style->ythickness + fwidth + fpad + fw->border;
2491 fontgrid_set_cell_geometry(fw);
2492 fontgrid_set_rows_cols(fw, 0);
2495 * Private variables.
2497 fw->unencoded = FALSE;
2500 fw->points_used = 0;
2501 fw->points_size = 0;
2506 fw->mclick_time = 0;
2509 memset((char *) &fw->clipboard, 0, sizeof(bdf_glyphlist_t));
2512 * Initialize the page information.
2516 pi->maxpage = 0xffff / fw->pagesize;
2517 pi->npage = pi->ppage = -1;
2518 pi->pageno = pi->bcode = 0;
2519 pi->sel_start = pi->sel_end = -1;
2520 (void) memset((char *) pi->selmap, 0, sizeof(guint32) * 2048);
2523 pi->maxpage = 0xffff / fw->pagesize;
2524 pi->npage = pi->ppage = -1;
2525 pi->pageno = pi->bcode = 0;
2526 pi->sel_start = pi->sel_end = -1;
2527 (void) memset((char *) pi->selmap, 0, sizeof(guint32) * 2048);
2530 /**************************************************************************
2534 **************************************************************************/
2537 * Type instantiation routines.
2540 fontgrid_get_type(void)
2542 static GType fontgrid_type = 0;
2544 if (!fontgrid_type) {
2545 static const GTypeInfo fontgrid_info = {
2546 sizeof (FontgridClass), /* class_size */
2548 0, /* base_finalize */
2549 fontgrid_class_init, /* class_init */
2550 0, /* class_finalize */
2552 sizeof(Fontgrid), /* instance_size */
2553 0, /* n_preallocs */
2554 fontgrid_init, /* instance_init */
2555 0, /* value_table */
2557 fontgrid_type = g_type_register_static(GTK_TYPE_WIDGET,
2558 "Fontgrid", &fontgrid_info, 0);
2561 return fontgrid_type;
2565 fontgrid_new(const gchar *prop1, ...)
2570 va_start(var_args, prop1);
2571 w = GTK_WIDGET(g_object_new_valist(fontgrid_get_type(), prop1, var_args));
2578 fontgrid_newv(bdf_font_t *font, guint32 pointSize, gint32 spacing,
2579 gboolean skipBlankPages, gboolean overwriteMode,
2580 gboolean powersOfTwo, guint16 *colorList, gint32 initialGlyph,
2581 guint codeBase, GtkOrientation orientation,
2582 gint32 bitsPerPixel, gint32 horizontalResolution,
2583 gint32 verticalResolution, FontgridPageInfo *initialPageInfo)
2585 Fontgrid *fw = FONTGRID(g_object_new(fontgrid_get_type(), NULL));
2587 FontgridInternalPageInfo *pi;
2590 fw->point_size = pointSize;
2591 fw->spacing = spacing;
2592 fw->colors = colorList;
2593 fw->noblanks = skipBlankPages;
2594 fw->overwrite = overwriteMode;
2595 fw->power2 = powersOfTwo;
2596 fw->initial_glyph = initialGlyph;
2597 fw->base = codeBase;
2598 fw->orientation = orientation;
2599 fw->bpp = (font) ? font->bpp : bitsPerPixel;
2600 fw->hres = horizontalResolution;
2601 fw->vres = verticalResolution;
2604 * If no font has been provided, make sure a default is created.
2605 * Too many other things depend on a font existing.
2608 fw->font = bdf_new_font(0, fw->point_size, fw->hres, fw->vres,
2609 fw->spacing, fw->bpp);
2610 if (fw->font->name == 0)
2611 fw->font->name = bdf_make_xlfd_name(fw->font, g_get_prgname(),
2615 fontgrid_set_cell_geometry(fw);
2616 fontgrid_set_rows_cols(fw, 0);
2619 * Initialize the page information.
2623 pi->maxpage = 0xffff / fw->pagesize;
2624 pi->npage = pi->ppage = -1;
2625 pi->pageno = pi->bcode = 0;
2626 pi->sel_start = pi->sel_end = -1;
2627 (void) memset((char *) pi->selmap, 0, sizeof(guint32) * 2048);
2630 pi->maxpage = 0xffff / fw->pagesize;
2631 pi->npage = pi->ppage = -1;
2632 pi->pageno = pi->bcode = 0;
2633 pi->sel_start = pi->sel_end = -1;
2634 (void) memset((char *) pi->selmap, 0, sizeof(guint32) * 2048);
2637 * Determine the page info from the initial glyph setting.
2640 if (fw->initial_glyph == -1)
2641 fw->initial_glyph = (font->glyphs_used > 0) ?
2642 font->glyphs->encoding : 0;
2645 pi->pageno = fw->initial_glyph / fw->pagesize;
2646 pi->bcode = pi->pageno * fw->pagesize;
2647 pi->sel_start = pi->sel_end = fw->initial_glyph;
2648 Select(fw->initial_glyph, pi->selmap);
2649 fontgrid_neighbor_pages(fw, pi->pageno, &pi->ppage, &pi->npage);
2652 * Set the min/max page numbers for the encoded glyphs.
2654 if (font->glyphs_used > 0) {
2656 pi->minpage = font->glyphs->encoding / fw->pagesize;
2658 font->glyphs[font->glyphs_used-1].encoding / fw->pagesize;
2661 pi->maxpage = 0xffff / fw->pagesize;
2666 * Set the min/max page numbers for the unencoded glyphs.
2668 if (font->unencoded_used > 0) {
2672 pi->pageno = pi->minpage =
2673 font->glyphs->encoding / fw->pagesize;
2675 font->unencoded[font->unencoded_used-1].encoding /
2677 pi->bcode = pi->pageno * fw->pagesize;
2681 * Lower boundary for the next page.
2683 boundary = pi->bcode + fw->pagesize;
2684 for (i = 0; i < font->unencoded_used &&
2685 font->unencoded[i].encoding < boundary; i++) ;
2686 pi->npage = (i == font->unencoded_used) ?
2687 -1 : font->unencoded[i].encoding / fw->pagesize;
2690 pi->pageno = pi->minpage = 0;
2691 pi->maxpage = 0xffff / fw->pagesize;
2693 pi->npage = pi->pageno + 1;
2699 * Provide the initial page info the calling application will need
2700 * to set up the page changing labels.
2702 initialPageInfo->unencoded_page = fw->unencoded;
2703 initialPageInfo->encoded_glyphs = (fw->font) ? fw->font->glyphs_used : 0;
2704 initialPageInfo->unencoded_glyphs =
2705 (fw->font) ? fw->font->unencoded_used : 0;
2707 if (!fw->unencoded) {
2708 initialPageInfo->previous_page = fw->npage.ppage;
2709 initialPageInfo->current_page = fw->npage.pageno;
2710 initialPageInfo->next_page = fw->npage.npage;
2712 initialPageInfo->previous_page = fw->upage.ppage;
2713 initialPageInfo->current_page = fw->upage.pageno;
2714 initialPageInfo->next_page = fw->upage.npage;
2717 return GTK_WIDGET(fw);
2721 fontgrid_has_selection(Fontgrid *fw, FontgridSelectionInfo *sinfo)
2723 FontgridInternalPageInfo *pi;
2725 g_return_val_if_fail(fw != 0, FALSE);
2727 pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
2730 * Set up the selection info to alert the application that the
2735 * Initialize the selection info structure.
2737 (void) memset((char *) sinfo, 0, sizeof(FontgridSelectionInfo));
2739 if (pi->sel_start == pi->sel_end) {
2743 fontgrid_locate_glyph(fw->font->glyphs,
2744 fw->font->glyphs_used,
2745 pi->sel_start, TRUE);
2748 fontgrid_locate_glyph(fw->font->unencoded,
2749 fw->font->unencoded_used,
2750 pi->sel_start, TRUE);
2751 if (sinfo->glyphs == 0) {
2752 empty_glyph.encoding = pi->sel_start;
2753 sinfo->glyphs = &empty_glyph;
2755 sinfo->num_glyphs = 1;
2759 sinfo->num_glyphs = 0;
2762 sinfo->start = pi->sel_start;
2763 sinfo->end = pi->sel_end;
2764 sinfo->base = fw->base;
2765 sinfo->unencoded = fw->unencoded;
2766 sinfo->reason = FONTGRID_START_SELECTION;
2769 return (pi->sel_start == -1) ? FALSE : TRUE;
2773 fontgrid_get_font(Fontgrid *fw)
2775 g_return_val_if_fail(fw != 0, 0);
2781 fontgrid_set_font(Fontgrid *fw, bdf_font_t *font, gint32 initial_glyph)
2785 FontgridInternalPageInfo *pi;
2786 FontgridPageInfo pageinfo;
2788 g_return_if_fail(fw != 0);
2790 if (font == fw->font)
2796 * Free up the existing font.
2799 bdf_free_font(fw->font);
2803 * Make sure the encoded pages are the default for newly loaded fonts.
2805 fw->unencoded = FALSE;
2808 * Set the bits-per-pixel from the font.
2810 fw->bpp = (font != 0) ? font->bpp : 1;
2813 * Set the initial glyph code.
2815 fw->initial_glyph = initial_glyph;
2818 * Calculate the cell geometry and the rows and columns.
2820 fontgrid_set_cell_geometry(fw);
2821 fontgrid_set_rows_cols(fw, 0);
2824 * Initialize the page information.
2828 pi->maxpage = 0xffff / fw->pagesize;
2829 pi->npage = pi->ppage = -1;
2830 pi->pageno = pi->bcode = 0;
2831 pi->sel_start = pi->sel_end = -1;
2832 (void) memset((char *) pi->selmap, 0, sizeof(guint32) * 2048);
2835 pi->maxpage = 0xffff / fw->pagesize;
2836 pi->npage = pi->ppage = -1;
2837 pi->pageno = pi->bcode = 0;
2838 pi->sel_start = pi->sel_end = -1;
2839 (void) memset((char *) pi->selmap, 0, sizeof(guint32) * 2048);
2842 * Determine the page info from the initial glyph setting.
2845 if (fw->initial_glyph == -1)
2846 fw->initial_glyph = (font->glyphs_used > 0) ?
2847 font->glyphs->encoding : 0;
2850 pi->pageno = fw->initial_glyph / fw->pagesize;
2851 pi->bcode = pi->pageno * fw->pagesize;
2852 pi->sel_start = pi->sel_end = fw->initial_glyph;
2853 Select(fw->initial_glyph, pi->selmap);
2854 fontgrid_neighbor_pages(fw, pi->pageno, &pi->ppage, &pi->npage);
2857 * Set the min/max page numbers for the encoded glyphs.
2859 if (font->glyphs_used > 0) {
2861 pi->minpage = font->glyphs->encoding / fw->pagesize;
2863 font->glyphs[font->glyphs_used-1].encoding / fw->pagesize;
2866 pi->maxpage = 0xffff / fw->pagesize;
2871 * Set the min/max page numbers for the unencoded glyphs.
2873 if (font->unencoded_used > 0) {
2877 pi->pageno = pi->minpage =
2878 font->glyphs->encoding / fw->pagesize;
2880 font->unencoded[font->unencoded_used-1].encoding /
2882 pi->bcode = pi->pageno * fw->pagesize;
2886 * Lower boundary for the next page.
2888 boundary = pi->bcode + fw->pagesize;
2889 for (i = 0; i < font->unencoded_used &&
2890 font->unencoded[i].encoding < boundary; i++) ;
2891 pi->npage = (i == font->unencoded_used) ?
2892 -1 : font->unencoded[i].encoding / fw->pagesize;
2895 pi->pageno = pi->minpage = 0;
2896 pi->maxpage = 0xffff / fw->pagesize;
2898 pi->npage = pi->pageno + 1;
2904 * Signal that a page change has taken place so the application can do
2905 * setup that it needs.
2907 pageinfo.unencoded_page = fw->unencoded;
2908 pageinfo.encoded_glyphs = (fw->font) ? fw->font->glyphs_used : 0;
2909 pageinfo.unencoded_glyphs = (fw->font) ? fw->font->unencoded_used : 0;
2911 if (!fw->unencoded) {
2912 pageinfo.previous_page = fw->npage.ppage;
2913 pageinfo.current_page = fw->npage.pageno;
2914 pageinfo.next_page = fw->npage.npage;
2916 pageinfo.previous_page = fw->upage.ppage;
2917 pageinfo.current_page = fw->upage.pageno;
2918 pageinfo.next_page = fw->upage.npage;
2921 g_signal_emit(G_OBJECT(fw), fontgrid_signals[TURN_TO_PAGE], 0, &pageinfo);
2924 * Queue up a resize so the grid will change size.
2926 gtk_widget_queue_resize(w);
2930 fontgrid_get_font_messages(Fontgrid *fw)
2932 g_return_val_if_fail(fw != 0, 0);
2934 return (fw->font) ? fw->font->acmsgs : 0;
2938 fontgrid_get_code_base(Fontgrid *fw)
2940 g_return_val_if_fail(fw != 0, 0);
2946 fontgrid_set_code_base(Fontgrid *fw, guint base)
2948 FontgridInternalPageInfo *pi;
2949 FontgridSelectionInfo sinfo;
2951 g_return_if_fail(fw != 0);
2954 case 8: case 10: case 16:
2955 if (fw->base != base) {
2957 if (!fw->unencoded) {
2959 fontgrid_draw_cells(GTK_WIDGET(fw), fw->npage.bcode,
2960 fw->npage.bcode + fw->pagesize,
2966 * Set up the selection info to alert the application that the
2969 if (pi->sel_start == pi->sel_end) {
2973 fontgrid_locate_glyph(fw->font->glyphs,
2974 fw->font->glyphs_used,
2975 pi->sel_start, TRUE);
2978 fontgrid_locate_glyph(fw->font->unencoded,
2979 fw->font->unencoded_used,
2980 pi->sel_start, TRUE);
2981 if (sinfo.glyphs == 0) {
2982 empty_glyph.encoding = pi->sel_start;
2983 sinfo.glyphs = &empty_glyph;
2985 sinfo.num_glyphs = 1;
2989 sinfo.num_glyphs = 0;
2992 sinfo.start = pi->sel_start;
2993 sinfo.end = pi->sel_end;
2994 sinfo.base = fw->base;
2995 sinfo.unencoded = fw->unencoded;
2996 sinfo.reason = FONTGRID_BASE_CHANGE;
2997 g_signal_emit(G_OBJECT(fw), fontgrid_signals[SELECTION_START], 0,
3005 fontgrid_get_orientation(Fontgrid *fw)
3007 g_return_val_if_fail(fw != 0, GTK_ORIENTATION_HORIZONTAL);
3009 return fw->orientation;
3013 fontgrid_set_orientation(Fontgrid *fw, GtkOrientation dir)
3017 g_return_if_fail(fw != 0);
3019 if (dir != fw->orientation) {
3020 fw->orientation = dir;
3023 * Need to swap rows and cols and attempt a resize if the object
3024 * has been constructed.
3026 tmp = fw->cell_rows;
3027 fw->cell_rows = fw->cell_cols;
3028 fw->cell_cols = tmp;
3030 gtk_widget_queue_resize(GTK_WIDGET(fw));
3035 fontgrid_get_page_info(Fontgrid *fw, FontgridPageInfo *pageinfo)
3037 g_return_if_fail(fw != 0);
3038 g_return_if_fail(pageinfo != 0);
3040 pageinfo->unencoded_page = fw->unencoded;
3041 pageinfo->encoded_glyphs = (fw->font) ? fw->font->glyphs_used : 0;
3042 pageinfo->unencoded_glyphs = (fw->font) ? fw->font->unencoded_used : 0;
3044 if (!fw->unencoded) {
3045 pageinfo->previous_page = fw->npage.ppage;
3046 pageinfo->current_page = fw->npage.pageno;
3047 pageinfo->next_page = fw->npage.npage;
3049 pageinfo->previous_page = fw->upage.ppage;
3050 pageinfo->current_page = fw->upage.pageno;
3051 pageinfo->next_page = fw->upage.npage;
3056 * This is the routine that does the majority of the work for updating
3060 fontgrid_page_change_update(Fontgrid *fw, FontgridInternalPageInfo *pi)
3063 FontgridPageInfo pageinfo;
3064 FontgridSelectionInfo selinfo;
3066 code = pi->sel_start - pi->bcode;
3067 pi->bcode = pi->pageno * fw->pagesize;
3069 if (fw->from_keyboard) {
3070 fontgrid_deselect_all(fw);
3072 pi->sel_start = pi->sel_end = code;
3073 Select(code, pi->selmap);
3074 fw->from_keyboard = FALSE;
3076 fontgrid_neighbor_pages(fw, pi->pageno, &pi->ppage, &pi->npage);
3078 fontgrid_draw_cells(GTK_WIDGET(fw), pi->bcode,
3079 pi->bcode + (fw->pagesize - 1), TRUE, TRUE);
3081 pageinfo.unencoded_page = fw->unencoded;
3082 pageinfo.encoded_glyphs = (fw->font) ? fw->font->glyphs_used : 0;
3083 pageinfo.unencoded_glyphs = (fw->font) ? fw->font->unencoded_used : 0;
3085 pageinfo.previous_page = pi->ppage;
3086 pageinfo.current_page = pi->pageno;
3087 pageinfo.next_page = pi->npage;
3089 g_signal_emit(G_OBJECT(fw), fontgrid_signals[TURN_TO_PAGE], 0, &pageinfo);
3092 * If this was called from the keyboard, then indicate the changed
3095 if (!fw->no_sel_callback && fw->from_keyboard) {
3097 selinfo.num_glyphs = 1;
3099 selinfo.glyphs = (!fw->unencoded) ?
3100 fontgrid_locate_glyph(fw->font->glyphs,
3101 fw->font->glyphs_used,
3103 fontgrid_locate_glyph(fw->font->unencoded,
3104 fw->font->unencoded_used,
3107 if (selinfo.glyphs == 0) {
3108 empty_glyph.encoding = code;
3109 selinfo.glyphs = &empty_glyph;
3112 selinfo.reason = FONTGRID_START_SELECTION;
3113 selinfo.start = pi->sel_start;
3114 selinfo.end = pi->sel_end;
3115 selinfo.base = fw->base;
3116 selinfo.unencoded = fw->unencoded;
3117 g_signal_emit(G_OBJECT(fw), fontgrid_signals[SELECTION_START], 0,
3123 fontgrid_goto_page(Fontgrid *fw, gint32 pageno)
3126 FontgridInternalPageInfo *pi;
3128 g_return_if_fail(fw != 0);
3130 pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
3132 mpage = 0xffff / fw->pagesize;
3139 if (pageno != pi->pageno) {
3140 pi->pageno = pageno;
3141 fontgrid_page_change_update(fw, pi);
3146 fontgrid_goto_code(Fontgrid *fw, gint32 code)
3149 FontgridInternalPageInfo *pi;
3150 FontgridSelectionInfo selinfo;
3152 g_return_if_fail(fw != 0);
3154 pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
3161 pageno = code / fw->pagesize;
3163 if (pageno != pi->pageno) {
3164 fw->no_sel_callback = TRUE;
3165 pi->pageno = pageno;
3166 fontgrid_page_change_update(fw, pi);
3169 fontgrid_deselect_all(fw);
3170 Select(code, pi->selmap);
3171 pi->sel_start = pi->sel_end = code;
3172 fontgrid_draw_cells(GTK_WIDGET(fw), code, code, FALSE, TRUE);
3175 selinfo.num_glyphs = 1;
3177 selinfo.glyphs = (!fw->unencoded) ?
3178 fontgrid_locate_glyph(fw->font->glyphs,
3179 fw->font->glyphs_used,
3181 fontgrid_locate_glyph(fw->font->unencoded,
3182 fw->font->unencoded_used,
3185 if (selinfo.glyphs == 0) {
3186 empty_glyph.encoding = code;
3187 selinfo.glyphs = &empty_glyph;
3190 selinfo.reason = FONTGRID_START_SELECTION;
3191 selinfo.start = pi->sel_start;
3192 selinfo.end = pi->sel_end;
3193 selinfo.base = fw->base;
3194 selinfo.unencoded = fw->unencoded;
3195 g_signal_emit(G_OBJECT(fw), fontgrid_signals[SELECTION_START], 0,
3200 fontgrid_goto_first_page(Fontgrid *fw)
3202 FontgridInternalPageInfo *pi;
3204 g_return_if_fail(fw != 0);
3206 pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
3208 if (pi->pageno == pi->minpage)
3211 pi->pageno = pi->minpage;
3212 fontgrid_page_change_update(fw, pi);
3216 fontgrid_goto_last_page(Fontgrid *fw)
3218 FontgridInternalPageInfo *pi;
3220 g_return_if_fail(fw != 0);
3222 pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
3224 if (pi->pageno == pi->maxpage)
3227 pi->pageno = pi->maxpage;
3228 fontgrid_page_change_update(fw, pi);
3232 fontgrid_goto_next_page(Fontgrid *fw)
3234 FontgridInternalPageInfo *pi;
3236 g_return_if_fail(fw != 0);
3238 pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
3240 if (pi->pageno == pi->maxpage)
3243 pi->pageno = pi->npage;
3244 fontgrid_page_change_update(fw, pi);
3248 fontgrid_goto_previous_page(Fontgrid *fw)
3250 FontgridInternalPageInfo *pi;
3252 g_return_if_fail(fw != 0);
3254 pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
3256 if (pi->pageno == pi->minpage)
3259 pi->pageno = pi->ppage;
3260 fontgrid_page_change_update(fw, pi);
3264 fontgrid_viewing_unencoded(Fontgrid *fw)
3266 g_return_val_if_fail(fw != 0, FALSE);
3268 return fw->unencoded;
3272 fontgrid_switch_encoding_view(Fontgrid *fw)
3274 FontgridInternalPageInfo *pi;
3276 g_return_if_fail(fw != 0);
3278 fw->unencoded = !fw->unencoded;
3279 pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
3280 fontgrid_draw_cells(GTK_WIDGET(fw), pi->bcode, pi->bcode + fw->pagesize,
3285 fontgrid_get_font_name(Fontgrid *fw)
3287 g_return_val_if_fail(fw != 0, 0);
3289 return (fw->font) ? fw->font->name : "";
3293 fontgrid_set_font_name(Fontgrid *fw, gchar *name)
3295 FontgridModificationInfo minfo;
3297 g_return_if_fail(fw != 0);
3298 g_return_if_fail(fw->font != 0);
3300 if (fw->font->name != 0)
3301 free(fw->font->name);
3303 if (name == 0 || *name == 0)
3304 fw->font->name = bdf_make_xlfd_name(fw->font, g_get_prgname(),
3307 fw->font->name = g_strdup(name);
3309 bdf_set_modified(fw->font, 1);
3311 minfo.reason = FONTGRID_MODIFIED;
3312 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3316 fontgrid_get_font_modified(Fontgrid *fw)
3318 g_return_val_if_fail(fw != 0, FALSE);
3320 return (fw->font) ? ((fw->font->modified) ? TRUE : FALSE) : FALSE;
3324 fontgrid_set_font_modified(Fontgrid *fw, gboolean mod)
3326 FontgridInternalPageInfo *pi;
3328 g_return_if_fail(fw != 0);
3330 if (fw->font && fw->font->modified != mod) {
3331 bdf_set_modified(fw->font, mod);
3335 * Redraw all the labels to clear those that were showing as
3338 pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
3339 fontgrid_draw_cells(GTK_WIDGET(fw), pi->bcode,
3340 (pi->bcode + fw->pagesize) - 1, TRUE, FALSE);
3343 * If the font is being marked as modified, then signal the
3344 * application of this state.
3346 fprintf(stderr, "MOD\n");
3352 fontgrid_set_unicode_glyph_names(Fontgrid *fw, FILE *in)
3354 FontgridModificationInfo minfo;
3356 g_return_if_fail(fw != 0);
3357 g_return_if_fail(in != 0);
3359 if (bdf_set_unicode_glyph_names(in, fw->font, 0)) {
3361 * Redraw the labels.
3363 fontgrid_draw_cells(GTK_WIDGET(fw), fw->npage.bcode,
3364 fw->npage.bcode + fw->pagesize, TRUE, FALSE);
3365 minfo.reason = FONTGRID_GLYPH_NAMES_MODIFIED;
3366 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3371 fontgrid_set_adobe_glyph_names(Fontgrid *fw, FILE *in)
3373 FontgridModificationInfo minfo;
3375 g_return_if_fail(fw != 0);
3376 g_return_if_fail(in != 0);
3378 if (bdf_set_adobe_glyph_names(in, fw->font, 0)) {
3380 * Redraw the labels.
3382 fontgrid_draw_cells(GTK_WIDGET(fw), fw->npage.bcode,
3383 fw->npage.bcode + fw->pagesize, TRUE, FALSE);
3384 minfo.reason = FONTGRID_GLYPH_NAMES_MODIFIED;
3385 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3390 fontgrid_set_code_glyph_names(Fontgrid *fw, gint ch)
3392 FontgridModificationInfo minfo;
3394 g_return_if_fail(fw != 0);
3396 if (bdf_set_glyph_code_names(ch, fw->font, 0)) {
3398 * Redraw the labels.
3400 fontgrid_draw_cells(GTK_WIDGET(fw), fw->npage.bcode,
3401 fw->npage.bcode + fw->pagesize, TRUE, FALSE);
3402 minfo.reason = FONTGRID_GLYPH_NAMES_MODIFIED;
3403 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3408 fontgrid_make_xlfd_font_name(Fontgrid *fw)
3410 FontgridModificationInfo minfo;
3412 g_return_if_fail(fw != 0);
3414 if ((minfo.name = bdf_make_xlfd_name(fw->font, "Foundry",
3415 "FaceName")) != 0) {
3416 minfo.reason = FONTGRID_NAME_MODIFIED;
3417 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3422 fontgrid_update_font_name_from_properties(Fontgrid *fw)
3424 FontgridModificationInfo minfo;
3426 g_return_if_fail(fw != 0);
3428 if (bdf_has_xlfd_name(fw->font)) {
3429 bdf_update_name_from_properties(fw->font);
3431 minfo.reason = FONTGRID_NAME_MODIFIED;
3432 minfo.name = fw->font->name;
3433 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3438 fontgrid_update_properties_from_font_name(Fontgrid *fw)
3440 FontgridModificationInfo minfo;
3442 g_return_if_fail(fw != 0);
3444 if (bdf_update_properties_from_name(fw->font)) {
3445 minfo.reason = FONTGRID_PROPERTIES_MODIFIED;
3446 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3451 fontgrid_set_font_property(Fontgrid *fw, bdf_property_t *prop)
3453 FontgridModificationInfo minfo;
3457 g_return_if_fail(fw != 0);
3458 g_return_if_fail(prop != 0);
3462 if ((p = bdf_get_font_property(fw->font, prop->name)) == 0)
3464 else if (p->format == prop->format) {
3465 switch (p->format) {
3468 * If the atoms are different or one is NULL and the other isn't,
3469 * then the property will be changed.
3471 if ((p->value.atom && prop->value.atom &&
3472 strcmp(p->value.atom, prop->value.atom) != 0) ||
3473 p->value.atom != prop->value.atom)
3477 if (p->value.int32 != prop->value.int32)
3481 if (p->value.card32 != prop->value.card32)
3488 * If this causes no change, just return.
3490 if (changed == FALSE)
3493 bdf_add_font_property(fw->font, prop);
3494 minfo.reason = FONTGRID_PROPERTIES_MODIFIED;
3495 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3499 fontgrid_delete_font_property(Fontgrid *fw, gchar *prop_name)
3501 FontgridModificationInfo minfo;
3504 g_return_if_fail(fw != 0);
3505 g_return_if_fail(prop_name != 0);
3508 * If the property doesn't exist, then just return.
3510 if ((p = bdf_get_font_property(fw->font, prop_name)) == 0)
3513 bdf_delete_font_property(fw->font, prop_name);
3514 minfo.reason = FONTGRID_PROPERTIES_MODIFIED;
3515 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3519 fontgrid_get_font_comments(Fontgrid *fw, gchar **comments)
3521 g_return_val_if_fail(fw != 0, 0);
3524 *comments = fw->font->comments;
3526 return fw->font->comments_len;
3530 fontgrid_set_font_comments(Fontgrid *fw, gchar *comments)
3532 FontgridModificationInfo minfo;
3535 g_return_if_fail(fw != 0);
3537 len = (comments) ? (unsigned int) strlen(comments) : 0;
3538 if (bdf_replace_comments(fw->font, comments, len)) {
3539 minfo.reason = FONTGRID_COMMENTS_MODIFIED;
3540 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3545 fontgrid_get_font_spacing(Fontgrid *fw)
3547 g_return_val_if_fail(fw != 0, -1);
3549 return fw->font->spacing;
3553 fontgrid_set_font_spacing(Fontgrid *fw, gint spacing)
3555 FontgridModificationInfo minfo;
3558 g_return_if_fail(fw != 0);
3560 if (spacing < BDF_PROPORTIONAL || spacing > BDF_CHARCELL ||
3561 fw->font->spacing == spacing)
3565 p.format = BDF_ATOM;
3567 case BDF_PROPORTIONAL: p.value.atom = "P"; break;
3568 case BDF_MONOWIDTH: p.value.atom = "M"; break;
3569 case BDF_CHARCELL: p.value.atom = "C"; break;
3572 bdf_add_font_property(fw->font, &p);
3573 minfo.reason = FONTGRID_PROPERTIES_MODIFIED;
3574 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3578 fontgrid_get_font_device_width(Fontgrid *fw)
3580 g_return_val_if_fail(fw != 0, 0);
3582 return fw->font->monowidth;
3586 fontgrid_set_font_device_width(Fontgrid *fw, guint16 dwidth)
3588 FontgridModificationInfo minfo;
3590 g_return_if_fail(fw != 0);
3593 * Only set the global device width if this is not a proportional font or
3594 * if there the device width changed.
3596 if (fw->font->spacing == BDF_PROPORTIONAL ||
3597 fw->font->monowidth == dwidth)
3600 fw->font->monowidth = dwidth;
3601 fw->font->modified = 1;
3603 minfo.reason = FONTGRID_DEVICE_WIDTH_MODIFIED;
3604 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3608 fontgrid_get_font_info(Fontgrid *fw, FontgridFontInfo *info)
3610 g_return_if_fail(fw != 0);
3611 g_return_if_fail(fw->font != 0);
3612 g_return_if_fail(info != 0);
3614 info->name = fw->font->name;
3615 info->comments = fw->font->comments;
3616 info->messages = fw->font->acmsgs;
3617 info->default_char = fw->font->default_glyph;
3618 info->monowidth = fw->font->monowidth;
3619 info->spacing = (guint16) fw->font->spacing;
3620 info->font_ascent = fw->font->font_ascent;
3621 info->font_descent = fw->font->font_descent;
3622 info->font_descent = fw->font->font_descent;
3623 info->resolution_x = fw->font->resolution_x;
3624 info->resolution_y = fw->font->resolution_y;
3625 info->bits_per_pixel = fw->font->bpp;
3626 memcpy((char *) &info->bbx, (char *) &fw->font->bbx, sizeof(bdf_bbx_t));
3630 fontgrid_set_font_info(Fontgrid *fw, FontgridFontInfo *info)
3634 bdf_property_t prop;
3635 FontgridModificationInfo minfo;
3637 g_return_if_fail(fw != 0);
3638 g_return_if_fail(fw->font != 0);
3639 g_return_if_fail(info != 0);
3643 minfo.reason = FONTGRID_MODIFIED;
3646 * Do some special stuff with the modified field so we know whether to
3647 * call the modified callback or not.
3653 * Handle the default character field. If it happens to be -1, then
3654 * delete the font property. Otherwise add it.
3656 if (info->default_char < 0)
3657 bdf_delete_font_property(f, "DEFAULT_CHAR");
3659 prop.name = "DEFAULT_CHAR";
3660 prop.format = BDF_CARDINAL;
3661 prop.value.card32 = info->default_char;
3662 bdf_add_font_property(f, &prop);
3665 prop.name = "FONT_ASCENT";
3666 prop.format = BDF_INTEGER;
3667 prop.value.int32 = info->font_ascent;
3668 bdf_add_font_property(f, &prop);
3670 prop.name = "FONT_DESCENT";
3671 prop.format = BDF_INTEGER;
3672 prop.value.int32 = info->font_descent;
3673 bdf_add_font_property(f, &prop);
3675 prop.name = "RESOLUTION_X";
3676 prop.format = BDF_CARDINAL;
3677 prop.value.int32 = info->resolution_x;
3678 bdf_add_font_property(f, &prop);
3680 prop.name = "RESOLUTION_Y";
3681 prop.format = BDF_CARDINAL;
3682 prop.value.int32 = info->resolution_y;
3683 bdf_add_font_property(f, &prop);
3685 prop.name = "SPACING";
3686 prop.format = BDF_ATOM;
3687 prop.value.atom = 0;
3688 switch (info->spacing) {
3689 case BDF_PROPORTIONAL: prop.value.atom = "P"; break;
3690 case BDF_MONOWIDTH: prop.value.atom = "M"; break;
3691 case BDF_CHARCELL: prop.value.atom = "C"; break;
3693 if (prop.value.atom != 0)
3694 bdf_add_font_property(f, &prop);
3697 * If the font was modified, and has an XLFD name, make sure the XLFD name
3698 * gets updated from the properties and the appropriate callback is
3701 if (f->modified && bdf_has_xlfd_name(f))
3702 fontgrid_update_font_name_from_properties(fw);
3705 * Now determine if the monowidth field will have a resize affect on
3708 if (f->spacing != BDF_PROPORTIONAL) {
3709 if (f->monowidth == 0) {
3711 * Handle the special case of a proportional font being changed to
3712 * some other spacing.
3714 f->monowidth = f->bbx.width;
3717 if (info->monowidth != f->monowidth) {
3719 * Go ahead and queue up a resize in case the monowidth
3720 * really does change the size.
3722 gtk_widget_queue_resize(GTK_WIDGET(fw));
3723 f->monowidth = f->bbx.width = info->monowidth;
3728 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3733 fontgrid_translate_glyphs(Fontgrid *fw, gint16 dx, gint16 dy,
3734 gboolean all_glyphs)
3736 GtkWidget *w = (GtkWidget *) fw;
3738 FontgridInternalPageInfo *pi;
3739 FontgridModificationInfo minfo;
3741 g_return_if_fail(fw != 0);
3743 pi = (!fw->unencoded) ? &fw->npage: &fw->upage;
3746 start = pi->minpage * fw->pagesize;
3747 end = (pi->maxpage * fw->pagesize) + fw->pagesize;
3749 start = pi->sel_start;
3753 if (bdf_translate_glyphs(fw->font, dx, dy, start, end, 0, 0,
3755 gtk_widget_queue_resize(w);
3756 if (GTK_WIDGET_REALIZED(w))
3757 gdk_window_clear(w->window);
3759 gtk_widget_queue_resize(w);
3760 if (GTK_WIDGET_REALIZED(w))
3761 gdk_window_clear(w->window);
3763 minfo.reason = FONTGRID_GLYPHS_MODIFIED;
3764 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3769 fontgrid_rotate_glyphs(Fontgrid *fw, gint16 degrees, gboolean all_glyphs)
3771 GtkWidget *w = (GtkWidget *) fw;
3773 FontgridInternalPageInfo *pi;
3774 FontgridModificationInfo minfo;
3776 g_return_if_fail(fw != 0);
3778 pi = (!fw->unencoded) ? &fw->npage: &fw->upage;
3781 start = pi->minpage * fw->pagesize;
3782 end = (pi->maxpage * fw->pagesize) + fw->pagesize;
3784 start = pi->sel_start;
3788 if (bdf_rotate_glyphs(fw->font, degrees, start, end, 0, 0,
3790 gtk_widget_queue_resize(w);
3791 if (GTK_WIDGET_REALIZED(w))
3792 gdk_window_clear(w->window);
3794 minfo.reason = FONTGRID_GLYPHS_MODIFIED;
3795 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3800 fontgrid_shear_glyphs(Fontgrid *fw, gint16 degrees, gboolean all_glyphs)
3802 GtkWidget *w = (GtkWidget *) fw;
3804 FontgridInternalPageInfo *pi;
3805 FontgridModificationInfo minfo;
3807 g_return_if_fail(fw != 0);
3809 pi = (!fw->unencoded) ? &fw->npage: &fw->upage;
3812 start = pi->minpage * fw->pagesize;
3813 end = (pi->maxpage * fw->pagesize) + fw->pagesize;
3815 start = pi->sel_start;
3819 if (bdf_shear_glyphs(fw->font, degrees, start, end, 0, 0,
3821 gtk_widget_queue_resize(w);
3822 if (GTK_WIDGET_REALIZED(w))
3823 gdk_window_clear(w->window);
3825 minfo.reason = FONTGRID_GLYPHS_MODIFIED;
3826 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3831 fontgrid_embolden_glyphs(Fontgrid *fw, gboolean all_glyphs)
3833 GtkWidget *w = (GtkWidget *) fw;
3836 FontgridInternalPageInfo *pi;
3837 FontgridModificationInfo minfo;
3839 g_return_if_fail(fw != 0);
3841 pi = (!fw->unencoded) ? &fw->npage: &fw->upage;
3844 start = pi->minpage * fw->pagesize;
3845 end = (pi->maxpage * fw->pagesize) + fw->pagesize;
3847 start = pi->sel_start;
3852 if (bdf_embolden_glyphs(fw->font, start, end, 0, 0,
3853 fw->unencoded, &resize)) {
3855 gtk_widget_queue_resize(w);
3856 if (GTK_WIDGET_REALIZED(w))
3857 gdk_window_clear(w->window);
3860 * Just redisplay the selection.
3862 fontgrid_draw_cells(w, start, end, TRUE, TRUE);
3864 minfo.reason = FONTGRID_GLYPHS_MODIFIED;
3865 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3870 fontgrid_clipboard_empty(Fontgrid *fw)
3873 gboolean empty = TRUE;
3875 gint aformat, nitems;
3878 g_return_val_if_fail(fw != 0, empty);
3880 if ((owner = gdk_selection_owner_get(FONTGRID_CLIPBOARD)) == 0)
3884 * Check to see if the clipboard contents are empty or not.
3886 * This is handled specially to allow determination of this without
3887 * using up what might be a lot of memory to get the whole contents. It
3888 * will have to be changed for Windows.
3890 if (gdk_property_get(owner, FONTGRID_CLIPBOARD, FONTGRID_GLYPHLIST,
3891 0, 4, FALSE, &atype, &aformat, &nitems, &data)) {
3894 free((char *) data);
3901 static unsigned char *
3902 fontgrid_encode_selection(Fontgrid *fw, guint32 *bytes)
3904 FontgridInternalPageInfo *pi;
3906 bdf_glyphlist_t *gl;
3908 guint32 i, nlen, bcount;
3913 gl = &fw->clipboard;
3914 pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
3915 bdf_copy_glyphs(fw->font, pi->sel_start, pi->sel_end, gl, fw->unencoded);
3918 * Calculate the number of bytes that will be needed for everything except
3919 * the name strings and the bitmap data.
3921 bcount = (sizeof(unsigned int) << 1) + (6 * sizeof(unsigned short)) +
3922 (((6 * sizeof(unsigned short)) + sizeof(unsigned int)) *
3926 * Figure out how much extra will be needed for the names, bitmaps, and
3927 * PSF Unicode mappings.
3929 for (i = 0, gp = gl->glyphs; i < gl->glyphs_used; i++, gp++) {
3930 nlen = (gp->name) ? (guint32) (strlen(gp->name) + 1) : 0;
3932 * The extra 2 bytes is for encoding the number of bytes used for the
3933 * Unicode mappings, even if it is 0. This could be a problem later
3934 * if a set of mappings legitimately exceeds 2^16 in length.
3936 bcount += nlen + gp->bytes + 2 + gp->unicode.map_used;
3940 * Allocate the storage space needed for the encoded form.
3942 sel = sp = g_malloc(bcount);
3945 * Set the returned byte count.
3950 * Encode the 20-byte header.
3952 a = (guint16) gl->bpp;
3953 *sp++ = (a >> 8) & 0xff;
3956 nlen = (guint32) gl->start;
3957 *sp++ = (nlen >> 24) & 0xff;
3958 *sp++ = (nlen >> 16) & 0xff;
3959 *sp++ = (nlen >> 8) & 0xff;
3960 *sp++ = nlen & 0xff;
3962 nlen = (guint32) gl->end;
3963 *sp++ = (nlen >> 24) & 0xff;
3964 *sp++ = (nlen >> 16) & 0xff;
3965 *sp++ = (nlen >> 8) & 0xff;
3966 *sp++ = nlen & 0xff;
3968 a = (guint16) gl->glyphs_used;
3969 *sp++ = (a >> 8) & 0xff;
3972 a = (guint16) gl->bbx.width;
3973 *sp++ = (a >> 8) & 0xff;
3976 a = (guint16) gl->bbx.x_offset;
3977 *sp++ = (a >> 8) & 0xff;
3980 a = (guint16) gl->bbx.ascent;
3981 *sp++ = (a >> 8) & 0xff;
3984 a = (guint16) gl->bbx.descent;
3985 *sp++ = (a >> 8) & 0xff;
3989 * Go through each glyph entry and encode the data.
3991 for (i = 0, gp = gl->glyphs; i < gl->glyphs_used; i++, gp++) {
3993 * Encode the glyph encoding.
3995 nlen = (guint32) gp->encoding;
3996 *sp++ = (nlen >> 24) & 0xff;
3997 *sp++ = (nlen >> 16) & 0xff;
3998 *sp++ = (nlen >> 8) & 0xff;
3999 *sp++ = nlen & 0xff;
4002 * Encode the glyph device width.
4004 a = (guint16) gp->dwidth;
4005 *sp++ = (a >> 8) & 0xff;
4009 * Encode the glyph name length.
4011 nlen = (gp->name) ? (guint32) (strlen(gp->name) + 1) : 0;
4013 *sp++ = (a >> 8) & 0xff;
4017 * Encode the four bounding box values needed.
4019 a = (guint16) gp->bbx.width;
4020 *sp++ = (a >> 8) & 0xff;
4023 a = (guint16) gp->bbx.x_offset;
4024 *sp++ = (a >> 8) & 0xff;
4027 a = (guint16) gp->bbx.ascent;
4028 *sp++ = (a >> 8) & 0xff;
4031 a = (guint16) gp->bbx.descent;
4032 *sp++ = (a >> 8) & 0xff;
4036 * Encode the name if it exists.
4039 (void) memcpy((char *) sp, gp->name, nlen);
4044 * Encode the bitmap.
4046 if (gp->bytes > 0) {
4047 (void) memcpy((char *) sp, (char *) gp->bitmap, gp->bytes);
4052 * Encode the PSF Unicode mappings. Even if there aren't any, add
4055 *sp++ = (gp->unicode.map_used >> 8) & 0xff;
4056 *sp++ = gp->unicode.map_used & 0xff;
4057 if (gp->unicode.map_used > 0) {
4058 (void) memcpy((char *) sp, (char *) gp->unicode.map,
4059 sizeof(unsigned char) * gp->unicode.map_used);
4060 sp += gp->unicode.map_used;
4065 * Return the selection encoded as a byte stream.
4070 #define GETSHORT(s) ((s[0] << 8) | s[1])
4071 #define GETLONG(s) ((s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3])
4074 fontgrid_decode_selection(Fontgrid *fw, guchar *sel)
4076 guint32 i, range, nlen;
4078 bdf_glyphlist_t *gl;
4083 gl = &fw->clipboard;
4086 * Clear out the bitmaps and names from the existing glyphs.
4088 for (gp = gl->glyphs, i = 0; i < gl->glyphs_size; i++, gp++) {
4092 free((char *) gp->bitmap);
4096 * Extract the glyph list bits per pixel.
4098 gl->bpp = GETSHORT(sel);
4102 * Extract the glyph list starting and ending encodings.
4104 gl->start = (int) GETLONG(sel);
4107 gl->end = (int) GETLONG(sel);
4111 * Extract the number of encoded glyphs.
4113 range = (guint32) GETSHORT(sel);
4117 * Resize the internal glyph list clipboard if necessary.
4119 if (range > gl->glyphs_size) {
4120 if (gl->glyphs_size == 0)
4121 gl->glyphs = (bdf_glyph_t *) malloc(sizeof(bdf_glyph_t) * range);
4123 gl->glyphs = (bdf_glyph_t *) realloc((char *) gl->glyphs,
4124 sizeof(bdf_glyph_t) * range);
4125 gl->glyphs_size = range;
4129 * Initialize the glyph list.
4131 (void) memset((char *) &gl->bbx, 0, sizeof(bdf_bbx_t));
4132 (void) memset((char *) gl->glyphs, 0,
4133 sizeof(bdf_glyph_t) * gl->glyphs_size);
4135 gl->glyphs_used = range;
4138 * Decode the overall metrics of the glyph list.
4140 gl->bbx.width = GETSHORT(sel);
4142 gl->bbx.x_offset = GETSHORT(sel);
4144 gl->bbx.ascent = GETSHORT(sel);
4146 gl->bbx.descent = GETSHORT(sel);
4148 gl->bbx.height = gl->bbx.ascent + gl->bbx.descent;
4149 gl->bbx.y_offset = -gl->bbx.descent;
4152 * Decode the glyphs.
4154 for (i = 0, gp = gl->glyphs; i < range; i++, gp++) {
4156 * Get the glyph encoding.
4158 gp->encoding = (int) GETLONG(sel);
4162 * Get the device width.
4164 gp->dwidth = GETSHORT(sel);
4168 * Get the name length.
4170 nlen = GETSHORT(sel);
4174 * Get the bounding box.
4176 gp->bbx.width = GETSHORT(sel);
4178 gp->bbx.x_offset = GETSHORT(sel);
4180 gp->bbx.ascent = GETSHORT(sel);
4182 gp->bbx.descent = GETSHORT(sel);
4184 gp->bbx.height = gp->bbx.ascent + gp->bbx.descent;
4185 gp->bbx.y_offset = -gp->bbx.descent;
4191 gp->name = (char *) malloc(nlen);
4192 (void) memcpy(gp->name, (char *) sel, nlen);
4202 gp->bytes = ((gp->bbx.width + 7) >> 3) * gp->bbx.height;
4205 gp->bytes = (((gp->bbx.width << 1) + 7) >> 3) * gp->bbx.height;
4208 gp->bytes = (((gp->bbx.width << 2) + 7) >> 3) * gp->bbx.height;
4211 gp->bytes = gp->bbx.width * gp->bbx.height;
4215 if (gp->bytes > 0) {
4216 gp->bitmap = (unsigned char *) malloc(gp->bytes);
4217 (void) memcpy((char *) gp->bitmap, (char *) sel, gp->bytes);
4222 * Get the Unicode mappings.
4224 gp->unicode.map_used = GETSHORT(sel);
4226 if (gp->unicode.map_used > 0) {
4227 gp->unicode.map_size = ((gp->unicode.map_used >> 2) +
4228 ((gp->unicode.map_used & 3) ? 1 : 0)) << 2;
4229 gp->unicode.map = (unsigned char *) malloc(gp->unicode.map_size);
4230 (void) memcpy((char *) gp->unicode.map, (char *) sel,
4231 gp->unicode.map_used);
4232 sel += gp->unicode.map_used;
4238 * This function assumes the fontgrid is realized so a GdkWindow exists.
4241 fontgrid_copy_selection(Fontgrid *fw)
4248 g_return_if_fail(fw != 0);
4253 * Make sure the widget owns the clipboard property.
4255 if ((win = gdk_selection_owner_get(FONTGRID_CLIPBOARD)) == 0 ||
4257 gdk_selection_owner_set(w->window, FONTGRID_CLIPBOARD, GDK_CURRENT_TIME,
4261 * Encode the selection as a byte stream for the clipboard.
4263 if ((sel = fontgrid_encode_selection(fw, &bytes)) == 0)
4266 gdk_property_change(w->window, FONTGRID_CLIPBOARD, FONTGRID_GLYPHLIST,
4267 8, GDK_PROP_MODE_REPLACE, sel, (gint) bytes);
4270 * Free the data because the property now has control over it.
4276 fontgrid_cut_selection(Fontgrid *fw)
4278 gint32 code, start, end;
4280 FontgridInternalPageInfo *pi;
4281 FontgridModificationInfo minfo;
4282 FontgridSelectionInfo sinfo;
4284 g_return_if_fail(fw != 0);
4286 fontgrid_copy_selection(fw);
4288 pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
4289 code = pi->sel_start;
4291 if (bdf_delete_glyphs(fw->font, pi->sel_start, pi->sel_end,
4293 start = pi->sel_start;
4296 fontgrid_deselect_all(fw);
4297 Select(code, pi->selmap);
4298 pi->sel_start = pi->sel_end = code;
4299 fontgrid_draw_cells(GTK_WIDGET(fw), start, end, TRUE, TRUE);
4302 * Set up and emit the modified signal.
4304 minfo.reason = FONTGRID_GLYPHS_DELETED;
4305 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
4308 * Set up and call the selection start signal.
4310 gp = (!fw->unencoded) ?
4311 fontgrid_locate_glyph(fw->font->glyphs, fw->font->glyphs_used,
4313 fontgrid_locate_glyph(fw->font->unencoded,
4314 fw->font->unencoded_used, code, TRUE);
4316 empty_glyph.encoding = code;
4321 sinfo.num_glyphs = 1;
4322 sinfo.start = sinfo.end = code;
4323 sinfo.base = fw->base;
4324 sinfo.unencoded = fw->unencoded;
4325 sinfo.reason = FONTGRID_START_SELECTION;
4326 g_signal_emit(G_OBJECT(fw), fontgrid_signals[SELECTION_START], 0,
4332 fontgrid_paste_selection(Fontgrid *fw, FontgridPasteType paste_type)
4334 GtkWidget *w = GTK_WIDGET(fw);
4337 gint afmt, nitems, unenc, doresize;
4343 bdf_glyphlist_t *gl;
4344 FontgridInternalPageInfo *pi;
4345 bdf_glyphlist_t overflow;
4346 FontgridModificationInfo minfo;
4347 FontgridSelectionInfo sinfo;
4349 g_return_if_fail(fw != 0);
4350 g_return_if_fail(GTK_WIDGET_REALIZED(w));
4352 if ((win = gdk_selection_owner_get(FONTGRID_CLIPBOARD)) == 0) {
4353 gdk_selection_owner_set(w->window, FONTGRID_CLIPBOARD,
4354 GDK_CURRENT_TIME, FALSE);
4356 * Return here because there was no owner of the selection.
4362 unenc = fw->unencoded;
4364 pi = (!unenc) ? &fw->npage : &fw->upage;
4367 (void) gdk_property_get(win, FONTGRID_CLIPBOARD, FONTGRID_GLYPHLIST,
4368 0, 102400, FALSE, &atype, &afmt, &nitems, &data);
4371 * Attempt to own the clipboard after getting the value if this widget
4374 if (win != w->window)
4375 gdk_selection_owner_set(w->window, FONTGRID_CLIPBOARD, GDK_CURRENT_TIME,
4380 gl = &fw->clipboard;
4383 * Convert the encoded selection into a glyph list in the internal
4384 * glyph list clipboard.
4386 fontgrid_decode_selection(fw, data);
4389 * If the paste is occuring in the unencoded section, make sure the
4390 * paste is appended as opposed to being inserted. Also turn off
4391 * the selected cell before doing the paste.
4394 fontgrid_deselect_all(fw);
4395 pi->sel_start = font->unencoded_used;
4397 gl->end = gl->glyphs_used - 1;
4401 * Set the end point of the selection.
4403 pi->sel_end = pi->sel_start + (gl->end - gl->start);
4406 * First, check to see if pasting the glyphs will exceed the maximum
4407 * encoding value of 0xffff. If some of them do, then transfer the
4408 * extra glyphs to the unencoded area before doing anything else.
4409 * This means that a new glyph list needs to be constructed to do the
4410 * insert into the unencoded area.
4412 if (!unenc && pi->sel_end > 0xffff) {
4414 * Determine if any of the glyphs would actually get encoded after
4415 * 0xffff or if those are all empty glyphs.
4417 for (ng = 0, gp = gl->glyphs; ng < gl->glyphs_used; ng++, gp++) {
4418 if (pi->sel_start + (gp->encoding - gl->start) > 0xffff)
4420 * The glyph list does contain glyphs that will overflow.
4425 if (ng < gl->glyphs_used) {
4427 * Construct a new glyph list containing only the glyphs that
4428 * overflow the 0xffff boundary. There is no need to
4429 * recalculate the bounding box for the new glyph list. Any
4430 * resize will be handled correctly anyway.
4432 (void) memcpy((char *) &overflow.bbx, (char *) &gl->bbx,
4434 overflow.bpp = font->bpp;
4435 overflow.glyphs_used = gl->glyphs_used - ng;
4436 overflow.glyphs = gp;
4438 overflow.end = overflow.glyphs_used - 1;
4441 * Add the glyphs to the unencoded area.
4443 doresize = bdf_replace_glyphs(font, font->unencoded_used,
4448 * Adjust the glyph list and selection to fit within the 0xffff
4449 * limit before pasting the glyphs into the font.
4451 gl->glyphs_used = ng;
4452 gl->end -= pi->sel_end - 0xffff;
4453 pi->sel_end = 0xffff;
4457 * If the grid is in insert mode, then determine if moving glyphs
4458 * forward from the insert location would cause an overflow.
4461 (!fw->overwrite || paste_type == FONTGRID_INSERT_PASTE)) {
4462 doresize += bdf_insert_glyphs(font, pi->sel_start, gl);
4464 * Force a page recalculation to be done so the application can
4467 fontgrid_goto_page(fw, fw->npage.pageno);
4468 } else if (paste_type == FONTGRID_MERGE_PASTE)
4469 doresize += bdf_merge_glyphs(font, pi->sel_start, gl, unenc);
4471 doresize += bdf_replace_glyphs(font, pi->sel_start, gl, unenc);
4474 * If the paste has more than one glyph, make sure the whole
4475 * range is selected.
4477 for (i = pi->sel_start; i <= pi->sel_end; i++)
4478 Select(i, pi->selmap);
4481 * If the incoming glyphs changed the font bounding box, then
4482 * determine the new geometry and attempt a resize.
4485 fontgrid_set_cell_geometry(fw);
4486 fontgrid_set_rows_cols(fw, 0);
4487 gtk_widget_queue_resize(w);
4489 fontgrid_draw_cells(w, pi->sel_start, pi->sel_end, TRUE, TRUE);
4492 * Update the number of pages used.
4496 if (font->unencoded_used == 0)
4499 gp = font->unencoded + (font->unencoded_used - 1);
4500 pi->maxpage = gp->encoding / fw->pagesize;
4505 if (font->glyphs_used == 0)
4508 gp = font->glyphs + (font->glyphs_used - 1);
4509 pi->maxpage = gp->encoding / fw->pagesize;
4515 * Set up and call the modified callback.
4518 * Set up and emit the modified signal.
4520 minfo.reason = FONTGRID_GLYPHS_PASTED;
4521 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
4523 if (pi->sel_start == pi->sel_end) {
4525 * Set up and call the selection start signal.
4527 gp = (!fw->unencoded) ?
4528 fontgrid_locate_glyph(fw->font->glyphs, fw->font->glyphs_used,
4529 pi->sel_start, TRUE) :
4530 fontgrid_locate_glyph(fw->font->unencoded,
4531 fw->font->unencoded_used, pi->sel_start,
4534 empty_glyph.encoding = pi->sel_start;
4539 sinfo.num_glyphs = 1;
4542 sinfo.num_glyphs = 0;
4544 sinfo.start = pi->sel_start;
4545 sinfo.end = pi->sel_end;
4546 sinfo.base = fw->base;
4547 sinfo.unencoded = fw->unencoded;
4548 sinfo.reason = FONTGRID_START_SELECTION;
4549 g_signal_emit(G_OBJECT(fw), fontgrid_signals[SELECTION_START], 0,
4553 * And last, since the change of the selection owner caused the
4554 * clipboard to lose its data, add the data to it again so
4555 * it can be pasted in some other font editor.
4557 gdk_property_change(w->window, FONTGRID_CLIPBOARD,
4558 FONTGRID_GLYPHLIST, 8, GDK_PROP_MODE_REPLACE,
4559 data, (gint) nitems);
4561 g_free((char *) data);
4566 fontgrid_update_metrics(Fontgrid *fw, bdf_metrics_t *metrics)
4568 FontgridModificationInfo mi;
4570 g_return_if_fail(fw != 0);
4571 g_return_if_fail(fw->font != 0);
4573 if (bdf_set_font_bbx(fw->font, metrics)) {
4579 * Calculate the cell geometry and the rows and columns.
4581 fontgrid_set_cell_geometry(fw);
4582 fontgrid_set_rows_cols(fw, 0);
4584 gtk_widget_queue_resize(GTK_WIDGET(fw));
4586 mi.reason = FONTGRID_FONT_METRICS_MODIFIED;
4588 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &mi);
4593 fontgrid_update_glyph(Fontgrid *fw, bdf_glyph_t *glyph, gboolean unencoded)
4595 FontgridInternalPageInfo *pi;
4598 FontgridModificationInfo mi;
4600 g_return_if_fail(fw != 0);
4601 g_return_if_fail(fw->font != 0);
4603 gl.bpp = fw->font->bpp;
4604 gl.start = gl.end = glyph->encoding;
4607 memcpy((char *) &gl.bbx, (char *) &glyph->bbx, sizeof(bdf_bbx_t));
4609 if (bdf_replace_glyphs(fw->font, glyph->encoding, &gl, unencoded)) {
4611 * The font geometry was changed by the glyph being pasted.
4612 * A resize will be needed.
4616 * Calculate the cell geometry and the rows and columns.
4618 fontgrid_set_cell_geometry(fw);
4619 fontgrid_set_rows_cols(fw, 0);
4621 gtk_widget_queue_resize(GTK_WIDGET(fw));
4623 mi.reason = FONTGRID_FONT_METRICS_MODIFIED;
4625 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &mi);
4628 * Simply redraw the cells that were modified.
4630 fontgrid_draw_cells(GTK_WIDGET(fw), glyph->encoding, glyph->encoding,
4633 pi = (fw->unencoded) ? &fw->upage : &fw->npage;
4636 if (fw->font->unencoded_used == 0)
4639 gp = fw->font->unencoded + (fw->font->unencoded_used - 1);
4640 pi->maxpage = gp->encoding / fw->pagesize;
4645 if (fw->font->glyphs_used == 0)
4648 gp = fw->font->glyphs + (fw->font->glyphs_used - 1);
4649 pi->maxpage = gp->encoding / fw->pagesize;
4654 mi.reason = FONTGRID_GLYPHS_MODIFIED;
4656 mi.start = mi.end = glyph->encoding;
4657 mi.unencoded = fw->unencoded;
4658 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &mi);
4662 fontgrid_update_psf_mappings(Fontgrid *fw, gint32 encoding,
4663 bdf_psf_unimap_t *mappings)
4665 FontgridModificationInfo mi;
4667 g_return_if_fail(fw != 0);
4668 g_return_if_fail(fw->font != 0);
4670 if (bdf_replace_mappings(fw->font, encoding, mappings, fw->unencoded)) {
4671 mi.reason = FONTGRID_PSF_MAPPINGS_MODIFIED;
4673 mi.start = mi.end = encoding;
4674 mi.unencoded = fw->unencoded;
4675 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &mi);
4680 fontgrid_select_next_glyph(Fontgrid *fw, gint32 code)
4685 FontgridInternalPageInfo *pi;
4686 FontgridSelectionInfo sinfo;
4688 g_return_val_if_fail(fw != NULL, FALSE);
4689 g_return_val_if_fail(IS_FONTGRID(fw), FALSE);
4691 if (!fw->unencoded) {
4693 gp = (fw->font && fw->font->glyphs_used) ?
4694 (fw->font->glyphs + (fw->font->glyphs_used - 1)) : 0;
4697 gp = (fw->font && fw->font->unencoded_used) ?
4698 (fw->font->unencoded + (fw->font->unencoded_used - 1)) : 0;
4701 if ((count = fw->count) == 0)
4705 * Make sure that when on the unencoded pages, the final glyph is
4706 * the limit unlike the encoded pages where the max value is 0xffff.
4708 if ((fw->unencoded &&
4709 (gp == 0 || code == gp->encoding)) ||
4715 if (fw->orientation == GTK_ORIENTATION_VERTICAL)
4716 code += (fw->cell_rows * count);
4720 if (fw->unencoded && code > gp->encoding)
4721 code = gp->encoding;
4722 else if (code > 0xffff)
4725 fontgrid_deselect_all(fw);
4727 pageno = code / fw->pagesize;
4728 if (pageno != pi->pageno) {
4729 fw->no_sel_callback = TRUE;
4730 fontgrid_goto_page(fw, pageno);
4733 pi->sel_start = pi->sel_end = code;
4734 Select(code, pi->selmap);
4735 fontgrid_draw_cells(GTK_WIDGET(fw), code, code, FALSE, TRUE);
4743 * Set up and emit the selection start signal.
4746 gp = fontgrid_locate_glyph(fw->font->glyphs, fw->font->glyphs_used,
4749 gp = fontgrid_locate_glyph(fw->font->unencoded, fw->font->unencoded_used,
4752 empty_glyph.encoding = code;
4756 sinfo.num_glyphs = 1;
4757 sinfo.start = pi->sel_start;
4758 sinfo.end = pi->sel_end;
4759 sinfo.base = fw->base;
4760 sinfo.unencoded = fw->unencoded;
4762 sinfo.reason = FONTGRID_START_SELECTION;
4763 g_signal_emit(G_OBJECT(fw), fontgrid_signals[SELECTION_START], 0,
4769 fontgrid_select_previous_glyph(Fontgrid *fw, gint32 code)
4774 FontgridInternalPageInfo *pi;
4775 FontgridSelectionInfo sinfo;
4777 g_return_val_if_fail(fw != NULL, FALSE);
4778 g_return_val_if_fail(IS_FONTGRID(fw), FALSE);
4780 if (!fw->unencoded) {
4782 gp = (fw->font && fw->font->glyphs_used) ?
4783 (fw->font->glyphs + (fw->font->glyphs_used - 1)) : 0;
4786 gp = (fw->font && fw->font->unencoded_used) ?
4787 (fw->font->unencoded + (fw->font->unencoded_used - 1)) : 0;
4790 if ((count = fw->count) == 0)
4798 if (fw->orientation == GTK_ORIENTATION_VERTICAL)
4799 code -= (fw->cell_rows * count);
4806 fontgrid_deselect_all(fw);
4808 pageno = code / fw->pagesize;
4809 if (pageno != pi->pageno) {
4810 fw->no_sel_callback = TRUE;
4811 fontgrid_goto_page(fw, pageno);
4814 pi->sel_start = pi->sel_end = code;
4815 Select(code, pi->selmap);
4816 fontgrid_draw_cells(GTK_WIDGET(fw), code, code, FALSE, TRUE);
4824 * Set up and emit the selection start signal.
4827 gp = fontgrid_locate_glyph(fw->font->glyphs, fw->font->glyphs_used,
4830 gp = fontgrid_locate_glyph(fw->font->unencoded, fw->font->unencoded_used,
4833 empty_glyph.encoding = code;
4837 sinfo.num_glyphs = 1;
4838 sinfo.start = pi->sel_start;
4839 sinfo.end = pi->sel_end;
4840 sinfo.base = fw->base;
4841 sinfo.unencoded = fw->unencoded;
4843 sinfo.reason = FONTGRID_START_SELECTION;
4844 g_signal_emit(G_OBJECT(fw), fontgrid_signals[SELECTION_START], 0,