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>
33 #define _(s) dgettext(GETTEXT_PACKAGE,s)
39 * Macros that represent the properties used by this type of object.
41 #define FONTGRID_CLIPBOARD gdk_atom_intern("FONTGRID_CLIPBOARD", FALSE)
42 #define FONTGRID_GLYPHLIST gdk_atom_intern("FONTGRID_GLYPHLIST", FALSE)
45 * Set several defaults.
47 #define FGRID_MAX_COLS 16
48 #define FGRID_MAX_ROWS 16
49 #define FGRID_DEFAULT_COLS 16
50 #define FGRID_DEFAULT_ROWS 8
51 #define FGRID_DEFAULT_CELL_HEIGHT 18
54 * Enums used for identifying properties.
73 /**************************************************************************
75 * Selection macros for toggling & testing glyph selected state.
77 **************************************************************************/
80 * Macros for dealing with the selected state of glyphs in the font grid.
82 #define IsSelected(code, map) (map[(code) >> 5] & (1 << ((code) & 31)))
83 #define Select(code, map) (map[(code) >> 5] |= (1 << ((code) & 31)))
84 #define Unselect(code, map) (map[(code) >> 5] &= ~(1 << ((code) & 31)))
86 /**************************************************************************
90 **************************************************************************/
93 * Enums that represent the signals these objects send out.
104 static GtkWidgetClass *parent_class = 0;
105 static guint fontgrid_signals[TURN_TO_PAGE + 1];
107 static bdf_glyph_t empty_glyph;
109 /**************************************************************************
111 * Digits for displaying the cell encoding.
113 **************************************************************************/
116 * Lists of points that describe the encoding digits.
123 static GdkPoint digit00[] = {{2, 0}, {1, 1}, {3, 1}, {0, 2}, {4, 2}, {0, 3},
124 {4, 3}, {0, 4}, {4, 4}, {1, 5}, {3, 5}, {2, 6}};
126 static GdkPoint digit01[] = {{2, 0}, {1, 1}, {2, 1}, {0, 2}, {2, 2}, {2, 3},
127 {2, 4}, {2, 5}, {0, 6}, {1, 6}, {2, 6}, {3, 6},
130 static GdkPoint digit02[] = {{1, 0}, {2, 0}, {3, 0}, {0, 1}, {4, 1}, {4, 2},
131 {2, 3}, {3, 3}, {1, 4}, {0, 5}, {0, 6}, {1, 6},
132 {2, 6}, {3, 6}, {4, 6}};
134 static GdkPoint digit03[] = {{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}, {4, 1},
135 {3, 2}, {2, 3},{3, 3}, {4, 4}, {0, 5}, {4, 5},
136 {1, 6}, {2, 6}, {3, 6}};
138 static GdkPoint digit04[] = {{3, 0}, {2, 1}, {3, 1}, {1, 2}, {3, 2}, {0, 3},
139 {3, 3}, {0, 4}, {1, 4}, {2, 4}, {3, 4}, {4, 4},
142 static GdkPoint digit05[] = {{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}, {0, 1},
143 {0, 2}, {2, 2}, {3, 2}, {0, 3}, {1, 3}, {4, 3},
144 {4, 4}, {0, 5}, {4, 5}, {1, 6}, {2, 6}, {3, 6}};
146 static GdkPoint digit06[] = {{2, 0}, {3, 0}, {1, 1}, {0, 2}, {0, 3}, {2, 3},
147 {3, 3}, {0, 4}, {1, 4}, {4, 4}, {0, 5}, {4, 5},
148 {1, 6}, {2, 6}, {3, 6}};
150 static GdkPoint digit07[] = {{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}, {4, 1},
151 {3, 2}, {3, 3}, {2, 4}, {1, 5}, {1, 6}};
153 static GdkPoint digit08[] = {{1, 0}, {2, 0}, {3, 0}, {0, 1}, {4, 1}, {0, 2},
154 {4, 2}, {1, 3}, {2, 3}, {3, 3}, {0, 4}, {4, 4},
155 {0, 5}, {4, 5}, {1, 6}, {2, 6}, {3, 6}};
157 static GdkPoint digit09[] = {{1, 0}, {2, 0}, {3, 0}, {0, 1}, {4, 1}, {0, 2},
158 {3, 2}, {4, 2}, {1, 3}, {2, 3}, {4, 3}, {4, 4},
159 {3, 5}, {1, 6}, {2, 6}};
161 static GdkPoint digit10[] = {{2, 0}, {1, 1}, {3, 1}, {0, 2}, {4, 2}, {0, 3},
162 {4, 3}, {0, 4}, {1, 4}, {2, 4}, {3, 4}, {4, 4},
163 {0, 5}, {4, 5}, {0, 6}, {4, 6}};
165 static GdkPoint digit11[] = {{0, 0}, {1, 0}, {2, 0}, {3, 0}, {1, 1}, {4, 1},
166 {1, 2}, {4, 2}, {1, 3}, {2, 3}, {3, 3}, {1, 4},
167 {4, 4}, {1, 5}, {4, 5}, {0, 6}, {1, 6}, {2, 6},
170 static GdkPoint digit12[] = {{1, 0}, {2, 0}, {3, 0}, {0, 1}, {4, 1}, {0, 2},
171 {0, 3}, {0, 4},{0, 5}, {4, 5}, {1, 6}, {2, 6},
174 static GdkPoint digit13[] = {{0, 0}, {1, 0}, {2, 0}, {3, 0}, {1, 1}, {4, 1},
175 {1, 2}, {4, 2}, {1, 3}, {4, 3}, {1, 4}, {4, 4},
176 {1, 5}, {4, 5}, {0, 6}, {1, 6}, {2, 6}, {3, 6}};
178 static GdkPoint digit14[] = {{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}, {0, 1},
179 {0, 2}, {0, 3}, {1, 3}, {2, 3}, {3, 3}, {0, 4},
180 {0, 5}, {0, 6}, {1, 6}, {2, 6}, {3, 6}, {4, 6}};
182 static GdkPoint digit15[] = {{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}, {0, 1},
183 {0, 2}, {0, 3}, {1, 3}, {2, 3}, {3, 3}, {0, 4},
185 static GdkPoint minus[] = {{1, 3}, {2, 3}, {3, 3}, {4,3}};
187 static fontgrid_digit digits[] = {
188 {digit00, sizeof(digit00)/sizeof(GdkPoint)},
189 {digit01, sizeof(digit01)/sizeof(GdkPoint)},
190 {digit02, sizeof(digit02)/sizeof(GdkPoint)},
191 {digit03, sizeof(digit03)/sizeof(GdkPoint)},
192 {digit04, sizeof(digit04)/sizeof(GdkPoint)},
193 {digit05, sizeof(digit05)/sizeof(GdkPoint)},
194 {digit06, sizeof(digit06)/sizeof(GdkPoint)},
195 {digit07, sizeof(digit07)/sizeof(GdkPoint)},
196 {digit08, sizeof(digit08)/sizeof(GdkPoint)},
197 {digit09, sizeof(digit09)/sizeof(GdkPoint)},
198 {digit10, sizeof(digit10)/sizeof(GdkPoint)},
199 {digit11, sizeof(digit11)/sizeof(GdkPoint)},
200 {digit12, sizeof(digit12)/sizeof(GdkPoint)},
201 {digit13, sizeof(digit13)/sizeof(GdkPoint)},
202 {digit14, sizeof(digit14)/sizeof(GdkPoint)},
203 {digit15, sizeof(digit15)/sizeof(GdkPoint)},
204 {minus, sizeof(minus)/sizeof(GdkPoint)},
208 * This array is used to hold a set of digits that will be displayed. It
209 * provides for a max of 19 points per digit and a max of 6 digits.
211 static GdkPoint encoding_digits[19*6];
214 * Used to determine spacing between digits when displaying.
216 #define FONTGRID_DIGIT_WIDTH 6
217 #define FONTGRID_DIGIT_HEIGHT 10
220 * A macro for getting the current foreground GC.
222 #define WIDGET_FG_GC(w) ((w)->style->fg_gc[GTK_WIDGET_STATE(w)])
224 #define HMARGINS(fw) ((fw)->hmargin << 1)
225 #define VMARGINS(fw) ((fw)->vmargin << 1)
228 fontgrid_set_cell_geometry(Fontgrid *fw)
235 lw = FONTGRID_DIGIT_WIDTH * 7;
238 * The labels will always be numbers in base 8, 10, or 16, so we are only
239 * interested in the max ascent. Add a 2-pixel margin on top and bottom.
241 fw->label_height = FONTGRID_DIGIT_HEIGHT + 4;
244 * We want a minumum padding of 3 pixels on each side of the glyph bitmap
245 * in each cell. Thus the addition of 6 to each dimension.
248 fw->cell_width = font->bbx.width + 6;
249 fw->cell_height = font->bbx.height + 6;
252 * Hard-code a minimum size for NULL fonts. The initial height of
253 * an empty cell is 20 to give it a better visual appearance.
255 fw->cell_width = lw + 6;
256 fw->cell_height = FGRID_DEFAULT_CELL_HEIGHT + 6;
259 fw->cell_width = MAX(fw->cell_width, lw);
260 fw->cell_height = MAX(fw->cell_height, fw->label_height);
263 * Now add the label size into the picture.
265 fw->cell_height += fw->label_height - 1;
269 fontgrid_set_rows_cols(Fontgrid *fw, GtkAllocation *core)
272 guint16 dw, dh, wd, ht;
275 * Limit the window size to 7/8 of the actual screen dimensions.
277 dw = (gdk_screen_width() * 7) >> 3;
278 dh = (gdk_screen_height() * 7) >> 3;
282 * Adjust the rows and columns based on the preferred geometry.
284 wd = (fw->cell_width * fw->cell_cols) + HMARGINS(fw);
285 ht = (fw->cell_height * fw->cell_rows) + VMARGINS(fw);
288 fw->cell_cols = (dw - HMARGINS(fw)) / fw->cell_width;
291 fw->cell_rows = (dh - VMARGINS(fw)) / fw->cell_height;
294 * Adjust the rows and columns based on the current geometry.
296 fw->cell_cols = (core->width - HMARGINS(fw)) / fw->cell_width;
297 fw->cell_rows = (core->height - VMARGINS(fw)) / fw->cell_height;
301 * Adjust rows and columns to powers of two if necessary.
305 * Make sure the columns are a power of 2.
307 for (i = 15; i >= 0; i--) {
308 if (fw->cell_cols & (1 << i)) {
309 fw->cell_cols = 1 << i;
315 * Make sure the rows are a power of 2.
317 for (i = 15; i >= 0; i--) {
318 if (fw->cell_rows & (1 << i)) {
319 fw->cell_rows = 1 << i;
326 * Fall back to a minimum of two rows.
328 if (fw->cell_rows == 0)
332 * Fall back to a minimum of two columns.
334 if (fw->cell_cols == 0)
338 * Make sure the number of rows and cols are within the max limits.
340 if (fw->cell_cols > FGRID_MAX_COLS)
341 fw->cell_cols = FGRID_MAX_COLS;
343 if (fw->cell_rows > FGRID_MAX_ROWS)
344 fw->cell_rows = FGRID_MAX_ROWS;
347 * Set the new page size based on the calculated rows and columns.
349 fw->pagesize = fw->cell_rows * fw->cell_cols;
352 /**************************************************************************
354 * GObjectClass functions.
356 **************************************************************************/
359 fontgrid_set_property(GObject *obj, guint prop_id, const GValue *value,
365 widget = GTK_WIDGET(obj);
370 fw->base = g_value_get_uint(value);
372 * Force the encodings to be redisplayed here?
376 fw->power2 = g_value_get_boolean(value);
378 case PROP_ORIENTATION:
379 fontgrid_set_orientation(fw, g_value_get_enum(value));
383 * Need to set the rows and columns back to their defaults when
384 * a new font is passed in case it is NULL.
386 fw->font = (bdf_font_t *) g_value_get_pointer(value);
388 fontgrid_set_cell_geometry(fw);
389 fontgrid_set_rows_cols(fw, 0);
391 case PROP_POINT_SIZE:
392 fw->point_size = g_value_get_uint(value);
395 fw->spacing = g_value_get_int(value);
397 case PROP_SKIP_BLANKS:
398 fw->noblanks = g_value_get_boolean(value);
401 fw->overwrite = g_value_get_boolean(value);
404 fw->colors = (guint16 *) g_value_get_pointer(value);
406 case PROP_INITIAL_GLYPH:
407 fw->initial_glyph = g_value_get_int(value);
410 fw->bpp = g_value_get_int(value);
413 fw->hres = g_value_get_int(value);
416 fw->vres = g_value_get_int(value);
422 fontgrid_get_property(GObject *obj, guint prop_id, GValue *value,
431 g_value_set_uint(value, f->base);
434 g_value_set_boolean(value, f->power2);
436 case PROP_ORIENTATION:
437 g_value_set_enum(value, f->orientation);
440 g_value_set_pointer(value, f->font);
442 case PROP_POINT_SIZE:
443 g_value_set_uint(value, f->point_size);
446 g_value_set_int(value, f->spacing);
448 case PROP_SKIP_BLANKS:
449 g_value_set_boolean(value, f->noblanks);
452 g_value_set_pointer(value, f->colors);
454 case PROP_INITIAL_GLYPH:
455 g_value_set_int(value, f->initial_glyph);
458 g_value_set_int(value, f->bpp);
461 g_value_set_int(value, f->hres);
464 g_value_set_int(value, f->vres);
469 /**************************************************************************
471 * GtkObjectClass functions.
473 **************************************************************************/
476 fontgrid_destroy(GtkObject *obj)
483 * Do some checks to make sure the incoming object exists and is the right
486 g_return_if_fail(obj != 0);
487 g_return_if_fail(IS_FONTGRID(obj));
492 * Clean up this object instance.
495 bdf_free_font(f->font);
499 g_object_unref(G_OBJECT(f->xor_gc));
502 if (f->points_size > 0)
504 f->points_size = f->points_used = 0;
508 f->rgb_used = f->rgb_size = 0;
511 * Remove all ownership of selections.
513 gtk_selection_remove_all(GTK_WIDGET(obj));
516 * Free up the clipboard contents if there are any.
519 for (i = 0; i < gl->glyphs_used; i++) {
520 if (gl->glyphs[i].name)
521 free(gl->glyphs[i].name);
522 if (gl->glyphs[i].bytes > 0)
523 free((char *) gl->glyphs[i].bitmap);
525 if (gl->glyphs_size > 0)
526 free((char *) gl->glyphs);
527 gl->glyphs_size = gl->glyphs_used = 0;
530 * Follow the class chain back up to free up resources allocated in the
533 GTK_OBJECT_CLASS(parent_class)->destroy(obj);
537 fontgrid_finalize(GObject *obj)
540 * Do some checks to make sure the incoming object exists and is the right
543 g_return_if_fail(obj != 0);
544 g_return_if_fail(IS_FONTGRID(obj));
547 * Follow the class chain back up to free up resources allocated in the
550 G_OBJECT_CLASS(parent_class)->finalize(obj);
553 /**************************************************************************
555 * GtkWidgetClass functions.
557 **************************************************************************/
560 fontgrid_preferred_size(GtkWidget *widget, GtkRequisition *preferred)
564 fw = FONTGRID(widget);
565 preferred->width = (fw->cell_width * fw->cell_cols) + HMARGINS(fw);
566 preferred->height = (fw->cell_height * fw->cell_rows) + VMARGINS(fw);
570 fontgrid_actual_size(GtkWidget *widget, GtkAllocation *actual)
574 fw = FONTGRID(widget);
576 widget->allocation = *actual;
579 * Make sure the rows and columns are adjusted to fit the actual allocated
582 fontgrid_set_rows_cols(fw, actual);
584 if (GTK_WIDGET_REALIZED(widget))
585 gdk_window_move_resize(widget->window, actual->x, actual->y,
586 actual->width, actual->height);
590 fontgrid_realize(GtkWidget *widget)
593 GdkWindowAttr attributes;
595 gint attributes_mask;
597 g_return_if_fail(widget != NULL);
598 g_return_if_fail(IS_FONTGRID(widget));
600 fw = FONTGRID(widget);
601 GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED);
603 attributes.window_type = GDK_WINDOW_CHILD;
604 attributes.x = widget->allocation.x;
605 attributes.y = widget->allocation.y;
606 attributes.width = widget->allocation.width;
607 attributes.height = widget->allocation.height;
608 attributes.wclass = GDK_INPUT_OUTPUT;
609 attributes.visual = gtk_widget_get_visual(widget);
610 attributes.colormap = gtk_widget_get_colormap(widget);
611 attributes.event_mask = gtk_widget_get_events(widget);
612 attributes.event_mask |= (GDK_EXPOSURE_MASK|GDK_BUTTON_PRESS_MASK|
613 GDK_BUTTON_RELEASE_MASK|GDK_ENTER_NOTIFY_MASK|
614 GDK_POINTER_MOTION_MASK|
615 GDK_KEY_PRESS_MASK|GDK_KEY_RELEASE_MASK|
616 GDK_LEAVE_NOTIFY_MASK|GDK_FOCUS_CHANGE_MASK|
617 GDK_PROPERTY_CHANGE_MASK);
619 attributes_mask = GDK_WA_X|GDK_WA_Y|GDK_WA_VISUAL|GDK_WA_COLORMAP;
621 widget->window = gdk_window_new(gtk_widget_get_parent_window(widget),
622 &attributes, attributes_mask);
623 gdk_window_set_user_data(widget->window, widget);
625 widget->style = gtk_style_attach(widget->style, widget->window);
626 gtk_style_set_background(widget->style, widget->window, GTK_STATE_NORMAL);
629 g_object_unref(G_OBJECT(fw->xor_gc));
632 * Create the GC used to display selected cells.
634 values.foreground.pixel =
635 widget->style->fg[GTK_WIDGET_STATE(widget)].pixel ^
636 widget->style->bg[GTK_WIDGET_STATE(widget)].pixel;
637 (void) memset((char *) &values.background, 0, sizeof(GdkColor));
638 values.function = GDK_XOR;
639 fw->xor_gc = gdk_gc_new_with_values(widget->window, &values,
641 GDK_GC_BACKGROUND|GDK_GC_FUNCTION);
645 fontgrid_locate_glyph(bdf_glyph_t *glyphs, guint32 nglyphs, gint32 code,
646 gboolean exact_match)
650 if (code < 0 || glyphs == 0 || nglyphs == 0)
653 for (l = 0, r = (gint32) (nglyphs - 1); l <= r; ) {
655 if (glyphs[m].encoding < code)
657 else if (glyphs[m].encoding > code)
670 * Adjust to the beginning or end if nothing was found in the search.
672 while (m > 0 && glyphs[m].encoding > code)
674 while (m < (gint32) nglyphs && glyphs[m].encoding < code)
677 return (m < (gint32) nglyphs) ? glyphs + m : 0;
681 fontgrid_get_glyph_points(Fontgrid *fw, gint x, gint y, gint rx, gint by,
685 unsigned char *bmap, *masks = 0;
688 case 1: masks = bdf_onebpp; break;
689 case 2: masks = bdf_twobpp; break;
690 case 4: masks = bdf_fourbpp; break;
691 case 8: masks = bdf_eightbpp; break;
695 bmap = glyph->bitmap;
696 bpr = ((glyph->bbx.width * fw->bpp) + 7) >> 3;
698 for (i = 0; i + y - glyph->bbx.ascent < by && i < glyph->bbx.height; i++) {
699 for (col = j = 0; j + x < rx && j < glyph->bbx.width;
700 j++, col += fw->bpp) {
701 if (bmap[(i * bpr) + (col >> 3)] &
702 masks[(col & 7) / fw->bpp]) {
703 if (fw->points_used == fw->points_size) {
704 if (fw->points_size == 0)
706 (GdkPoint *) g_malloc(sizeof(GdkPoint) << 7);
709 (GdkPoint *) g_realloc(fw->points,
711 (fw->points_size + 128));
712 fw->points_size += 128;
715 fw->points[fw->points_used].x = j + x;
716 fw->points[fw->points_used].y = i + y - glyph->bbx.ascent;
725 fontgrid_get_glyph_points_color(Fontgrid *fw, gint x, gint y, gint rx, gint by,
726 gint color_index, bdf_glyph_t *glyph)
728 gint i, j, bpr, col, byte, di = 0, si, cidx = 0;
729 unsigned char *bmap, *masks = 0;
732 case 1: masks = bdf_onebpp; di = 7; break;
733 case 2: masks = bdf_twobpp; di = 3; break;
734 case 4: masks = bdf_fourbpp; di = 1; break;
735 case 8: masks = bdf_eightbpp; di = 0; break;
739 bmap = glyph->bitmap;
740 bpr = ((glyph->bbx.width * fw->bpp) + 7) >> 3;
742 for (i = 0; i + y - glyph->bbx.ascent < by && i < glyph->bbx.height; i++) {
743 for (col = j = 0; j + x < rx && j < glyph->bbx.width;
744 j++, col += fw->bpp) {
745 si = (col & 7) / fw->bpp;
746 byte = bmap[(i * bpr) + (col >> 3)] & masks[si];
749 * Check to see if the byte matches the color index being
753 byte >>= (di - si) * fw->bpp;
756 if (fw->points_used == fw->points_size) {
757 if (fw->points_size == 0)
758 fw->points = (GdkPoint *)
759 g_malloc(sizeof(GdkPoint) << 6);
761 fw->points = (GdkPoint *)
762 g_realloc(fw->points, sizeof(GdkPoint) *
763 (fw->points_size + 64));
764 fw->points_size += 64;
767 fw->points[fw->points_used].x = j + x;
768 fw->points[fw->points_used].y = i + y - glyph->bbx.ascent;
778 * This routine creates a 24 bits per pixel image of a glyph so it can be
779 * drawn using GtkRGB. This is less complicated than the old method of
780 * collecting and drawing individual pixels of each different color.
783 fontgrid_make_rgb_image(Fontgrid *fw, bdf_glyph_t *glyph)
785 GtkWidget *w = GTK_WIDGET(fw);
786 gint x, y, bpr, rgb_bpr, col, byte, di = 0, si;
787 guchar bg[4], pix[4], *bmap, *masks = 0;
790 * Figure out the background color.
792 bg[0] = (guchar) w->style->bg[GTK_WIDGET_STATE(w)].red;
793 bg[1] = (guchar) w->style->bg[GTK_WIDGET_STATE(w)].green;
794 bg[2] = (guchar) w->style->bg[GTK_WIDGET_STATE(w)].blue;
797 case 1: masks = bdf_onebpp; di = 7; break;
798 case 2: masks = bdf_twobpp; di = 3; break;
799 case 4: masks = bdf_fourbpp; di = 1; break;
800 case 8: masks = bdf_eightbpp; di = 0; break;
803 bmap = glyph->bitmap;
804 bpr = ((glyph->bbx.width * fw->bpp) + 7) >> 3;
806 rgb_bpr = glyph->bbx.width * 3;
807 fw->rgb_used = rgb_bpr * glyph->bbx.height;
809 if (fw->rgb_size < fw->rgb_used) {
810 if (fw->rgb_size == 0)
811 fw->rgb = g_malloc(fw->rgb_used);
813 fw->rgb = g_realloc(fw->rgb, fw->rgb_used);
814 fw->rgb_size = fw->rgb_used;
817 for (y = 0; y < glyph->bbx.height; y++) {
818 for (col = x = 0; x < glyph->bbx.width; x++, col += fw->bpp) {
819 si = (col & 7) / fw->bpp;
821 byte = bmap[(y * bpr) + (col >> 3)] & masks[si];
823 byte >>= (di - si) * fw->bpp;
829 case 1: memset(pix, 0, 3); break;
830 case 2: memset(pix, fw->colors[byte-1], 3); break;
831 case 4: memset(pix, fw->colors[byte-1+4], 3); break;
832 case 8: memset(pix, byte, 3); break;
836 * Set the pixel to the background color.
840 memcpy(&fw->rgb[(y * rgb_bpr) + (x * 3)], pix, 3);
846 fontgrid_draw_encoding(GtkWidget *w, GdkGC *gc, gint x, gint y, gchar *num,
852 if (!GTK_WIDGET_REALIZED(w))
855 dp = encoding_digits;
856 for (i = 0; i < numlen; i++) {
859 else if (num[i] <= '9')
862 d = (num[i] - 'A') + 10;
865 * Copy the next digit into the display array.
867 (void) memcpy((char *) dp, (char *) digits[d].points,
868 sizeof(GdkPoint) * digits[d].npoints);
870 * Position the points.
872 for (j = 0; j < digits[d].npoints; j++) {
876 dp += digits[d].npoints;
883 gdk_draw_points(w->window, gc, encoding_digits, dp - encoding_digits);
887 fontgrid_draw_cells(GtkWidget *widget, gint32 start, gint32 end,
888 gboolean labels, gboolean glyphs)
891 gint x, y, wd, as, ds, len, lx, ly;
896 bdf_glyph_t *glyph, *gp;
897 FontgridInternalPageInfo *pi;
902 if (!GTK_WIDGET_REALIZED(widget) || (labels == FALSE && glyphs == FALSE))
905 fw = FONTGRID(widget);
912 if (!fw->unencoded) {
915 glyph = font->glyphs;
916 nglyphs = font->glyphs_used;
920 * When viewing the unencoded glyph pages, all glyphs are labelled
921 * with an encoding of -1.
927 glyph = font->unencoded;
928 nglyphs = font->unencoded_used;
933 * The initial code to work from.
938 * Locate the glyph closest to the starting code.
940 if ((glyph = fontgrid_locate_glyph(glyph, nglyphs, start, FALSE)) == 0)
945 gc = widget->style->fg_gc[GTK_WIDGET_STATE(widget)];
947 for (ng = 0, i = start; i <= end; i++) {
949 * Only draw those cells that are on the current page.
951 if (i < pi->bcode || i >= pi->bcode + fw->pagesize)
954 if (fw->orientation == GTK_ORIENTATION_HORIZONTAL) {
955 r = (i - n) / fw->cell_cols;
956 c = (i - n) % fw->cell_cols;
958 c = (i - n) / fw->cell_rows;
959 r = (i - n) % fw->cell_rows;
962 x = fw->xoff + (c * fw->cell_width);
963 y = fw->yoff + (r * fw->cell_height);
966 if (!fw->unencoded) {
968 case 8: sprintf(nbuf, "%o", i); break;
969 case 10: sprintf(nbuf, "%d", i); break;
970 case 16: sprintf(nbuf, "%X", i); break;
975 rect.width = fw->cell_width - 2;
976 rect.height = fw->label_height - 2;
977 gdk_draw_rectangle(widget->window, gc, FALSE,
978 rect.x, rect.y, rect.width, rect.height);
985 lx = (x + ((fw->cell_width >> 1) - (wd >> 1))) + 1;
986 ly = (y + ((fw->label_height >> 1) - ((as + ds) >> 1))) + 1;
990 mod = (!fw->unencoded) ? bdf_glyph_modified(font, i, 0) :
991 bdf_glyph_modified(font, i, 1);
993 gdk_window_clear_area(widget->window, rect.x + 1, rect.y + 1,
994 rect.width - 1, rect.height - 1);
996 if (!fw->unencoded && mod) {
997 gdk_draw_rectangle(widget->window, gc, TRUE,
998 rect.x + 2, rect.y + 2,
999 rect.width - 3, rect.height - 3);
1000 fontgrid_draw_encoding(widget, fw->xor_gc, lx, ly, nbuf, len);
1001 if (gp && gp->encoding == i) {
1009 * If the glyph exists, then darken the rectangle to indicate
1012 if (gp && gp->encoding == i) {
1013 gdk_draw_rectangle(widget->window, gc, FALSE,
1014 rect.x + 1, rect.y + 1,
1015 rect.width - 2, rect.height - 2);
1021 fontgrid_draw_encoding(widget, gc, lx, ly, nbuf, len);
1027 rect.y = y + fw->label_height + 1;
1028 rect.width = fw->cell_width - 2;
1029 rect.height = (fw->cell_height - fw->label_height) - 2;
1031 if (i <= 0xffff && nglyphs > 0 && glyph->encoding == i) {
1037 * Set the right and left limits for generating points.
1039 lx = x + fw->cell_width - 2;
1040 ly = y + fw->cell_height - 2;
1043 * Adjust the X,Y coordinate pair so the bitmap points will
1044 * be generated to center the glyphs horizontally and align
1045 * them to the BDF font's baseline vertically.
1047 x += (fw->cell_width >> 1) -
1048 ((font->bbx.width + font->bbx.x_offset) >> 1) + 1;
1049 y += fw->label_height + font->bbx.ascent + 3;
1051 if (IsSelected(glyph->encoding, pi->selmap)) {
1052 gdk_draw_rectangle(widget->window, gc, TRUE,
1053 rect.x + 1, rect.y + 1,
1054 rect.width - 1, rect.height - 1);
1055 if (glyph->bytes > 0) {
1056 fontgrid_get_glyph_points(fw, x, y, lx, ly, glyph);
1057 if (fw->points_used > 0)
1058 gdk_draw_points(widget->window, fw->xor_gc,
1059 fw->points, fw->points_used);
1063 * The glyph is not selected, so draw it according to
1064 * the bytes-per-pixel of the font.
1066 gdk_window_clear_area(widget->window, rect.x, rect.y,
1067 rect.width, rect.height);
1068 if (glyph->bytes > 0) {
1069 fontgrid_make_rgb_image(fw, glyph);
1070 gdk_draw_rgb_image(widget->window, gc,
1071 x, y - glyph->bbx.ascent,
1074 GDK_RGB_DITHER_NONE,
1075 fw->rgb, glyph->bbx.width * 3);
1079 if (ng == nglyphs) {
1085 * Clear the empty cell.
1087 if (i <= 0xffff && IsSelected(i, pi->selmap))
1088 gdk_draw_rectangle(widget->window, gc, TRUE,
1089 rect.x + 1, rect.y + 1,
1090 rect.width - 1, rect.height - 1);
1092 gdk_window_clear_area(widget->window, rect.x, rect.y,
1093 rect.width, rect.height);
1095 gdk_draw_line(widget->window, gc, rect.x, rect.y,
1096 rect.x + rect.width,
1097 rect.y + rect.height);
1098 gdk_draw_line(widget->window, gc,
1099 rect.x + rect.width, rect.y,
1100 rect.x, rect.y + rect.height);
1109 fontgrid_draw(GtkWidget *widget, GdkRegion *region)
1113 guint16 wd, ht, gw, gh;
1117 g_return_if_fail(widget != NULL);
1118 g_return_if_fail(IS_FONTGRID(widget));
1120 fw = FONTGRID(widget);
1122 gc = widget->style->fg_gc[GTK_WIDGET_STATE(widget)];
1124 gw = fw->cell_width * fw->cell_cols;
1125 gh = fw->cell_height * fw->cell_rows;
1126 wd = widget->allocation.width;
1127 ht = widget->allocation.height;
1128 x = fw->xoff = ((wd >> 1) - (gw >> 1)) - 1;
1129 y = fw->yoff = ((ht >> 1) - (gh >> 1)) - 1;
1132 * Draw the horizontal lines.
1134 for (i = 0; i <= fw->cell_rows; i++) {
1135 gdk_draw_line(widget->window, gc, x, y, x + gw, y);
1138 * Only draw the second line if this is not the last line.
1140 if (i < fw->cell_rows)
1141 gdk_draw_line(widget->window, gc, x, y + fw->label_height,
1142 x + gw, y + fw->label_height);
1144 y += fw->cell_height;
1148 * Draw the vertical lines.
1153 for (i = 0; i <= fw->cell_cols; i++) {
1154 gdk_draw_line(widget->window, gc, x, y, x, y + gh);
1155 x += fw->cell_width;
1158 start = (!fw->unencoded) ? fw->npage.bcode : fw->upage.bcode;
1159 end = start + (gint32) (fw->pagesize - 1);
1161 fontgrid_draw_cells(widget, start, end, TRUE, TRUE);
1165 fontgrid_select_range(Fontgrid *fw, gint32 start, gint32 end)
1168 FontgridInternalPageInfo *pi;
1176 pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
1178 for (i = start; i <= end; i++)
1179 Select(i, pi->selmap);
1182 * Adjust the start and end values to the current page to determine which
1183 * cells need to be redrawn.
1185 tmp = pi->bcode + (fw->pagesize - 1);
1186 if (start >= tmp || end < pi->bcode)
1189 if (start < pi->bcode)
1193 fontgrid_draw_cells(GTK_WIDGET(fw), start, end, FALSE, TRUE);
1197 fontgrid_deselect_range(Fontgrid *fw, gint32 start, gint32 end)
1200 FontgridInternalPageInfo *pi;
1208 pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
1209 for (i = start; i <= end; i++) {
1210 if (IsSelected(i, pi->selmap)) {
1211 Unselect(i, pi->selmap);
1212 if (i >= pi->bcode && i <= pi->bcode + (fw->pagesize - 1))
1213 fontgrid_draw_cells(GTK_WIDGET(fw), i, i, FALSE, TRUE);
1219 fontgrid_deselect_all(Fontgrid *fw)
1221 FontgridInternalPageInfo *pi, *opi;
1223 if (!fw->unencoded) {
1231 if (pi->sel_start != -1 || pi->sel_end != -1)
1232 fontgrid_deselect_range(fw, pi->bcode, pi->bcode + fw->pagesize - 1);
1233 else if (opi->sel_start != -1 || opi->sel_end != -1)
1234 fontgrid_deselect_range(fw, opi->bcode, opi->bcode + fw->pagesize - 1);
1237 * Now clear the selected bitmaps.
1239 (void) memset((char *) pi->selmap, 0, sizeof(guint32) * 2048);
1240 (void) memset((char *) opi->selmap, 0, sizeof(guint32) * 2048);
1243 * Reset the selection start and end points.
1245 pi->sel_start = pi->sel_end = opi->sel_start = opi->sel_end = -1;
1249 fontgrid_draw_focus(GtkWidget *widget, GdkRectangle *area)
1252 gint x, y, wd, ht, fwidth, fpad;
1255 * Do something with this later to make sure the focus line width
1256 * is set in the GC's.
1258 gtk_widget_style_get(widget,
1259 "focus-line-width", &fwidth,
1260 "focus-padding", &fpad, NULL);
1262 gc = widget->style->bg_gc[GTK_WIDGET_STATE(widget)];
1264 x = (widget->style->xthickness + fwidth + fpad) - 1;
1265 y = (widget->style->ythickness + fwidth + fpad) - 1;
1266 wd = (widget->allocation.width - (x * 2));
1267 ht = (widget->allocation.height - (y * 2));
1269 if (GTK_WIDGET_HAS_FOCUS(widget))
1270 gtk_paint_focus(widget->style, widget->window, GTK_WIDGET_STATE(widget),
1271 area, widget, "fontgrid", x, y, wd, ht);
1273 gdk_gc_set_clip_rectangle(gc, area);
1274 gdk_draw_rectangle(widget->window, gc, FALSE, x, y, wd - 1, ht - 1);
1275 gdk_gc_set_clip_rectangle(gc, 0);
1280 fontgrid_expose(GtkWidget *widget, GdkEventExpose *event)
1283 * Paint the shadow first.
1285 if (GTK_WIDGET_DRAWABLE(widget))
1286 gtk_paint_shadow(widget->style, widget->window,
1287 GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
1288 &event->area, widget, "fontgrid",
1290 widget->allocation.width,
1291 widget->allocation.height);
1293 fontgrid_draw(widget, event->region);
1295 fontgrid_draw_focus(widget, &event->area);
1301 fontgrid_focus_in(GtkWidget *widget, GdkEventFocus *event)
1303 g_return_val_if_fail(widget != NULL, FALSE);
1304 g_return_val_if_fail(IS_FONTGRID(widget), FALSE);
1305 g_return_val_if_fail(event != NULL, FALSE);
1307 GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_FOCUS);
1308 fontgrid_draw_focus(widget, 0);
1314 fontgrid_focus_out(GtkWidget *widget, GdkEventFocus *event)
1316 g_return_val_if_fail(widget != NULL, FALSE);
1317 g_return_val_if_fail(IS_FONTGRID(widget), FALSE);
1318 g_return_val_if_fail(event != NULL, FALSE);
1320 GTK_WIDGET_UNSET_FLAGS(widget, GTK_HAS_FOCUS);
1321 fontgrid_draw_focus(widget, 0);
1327 fontgrid_lose_selection(GtkWidget *widget, GdkEventSelection *event)
1330 FontgridInternalPageInfo *pi;
1333 fw = FONTGRID(widget);
1335 pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
1337 if (pi->sel_start != pi->sel_end) {
1338 code = pi->sel_start;
1339 fontgrid_deselect_all(fw);
1340 pi->sel_end = pi->sel_start = code;
1341 Select(pi->sel_start, pi->selmap);
1342 fontgrid_draw_cells(widget, code, code, FALSE, TRUE);
1348 /**************************************************************************
1352 **************************************************************************/
1355 fontgrid_neighbor_pages(Fontgrid *fw, gint32 page, gint32 *prev, gint32 *next)
1357 gint32 bcode, l, r, m;
1359 bdf_glyph_t *glyphs;
1360 FontgridInternalPageInfo *pip;
1362 pip = (!fw->unencoded) ? &fw->npage : &fw->upage;
1364 if (fw->noblanks == FALSE ||
1365 (fw->unencoded == FALSE &&
1366 (fw->font == 0 || fw->font->glyphs_used == 0))) {
1368 *next = (page < pip->maxpage) ? page + 1 : -1;
1372 bcode = page * fw->pagesize;
1374 if (!fw->unencoded) {
1375 glyphs = fw->font->glyphs;
1376 nglyphs = fw->font->glyphs_used;
1378 glyphs = fw->font->unencoded;
1379 nglyphs = fw->font->unencoded_used;
1383 * Do a binary search to find the the preceding page number.
1385 for (l = m = 0, r = nglyphs - 1; l < r; ) {
1387 if (glyphs[m].encoding < bcode)
1389 else if (glyphs[m].encoding > bcode)
1401 * In case the search ends on a code in the specified page.
1403 while (r >= 0 && glyphs[r].encoding >= bcode)
1407 * Set the previous page code.
1409 *prev = (r >= 0) ? glyphs[r].encoding / fw->pagesize : -1;
1412 * Determine the following page code.
1416 while (r < nglyphs && glyphs[r].encoding < bcode + fw->pagesize)
1419 *next = (r < nglyphs) ? glyphs[r].encoding / fw->pagesize : -1;
1422 /**************************************************************************
1424 * Selection routines.
1426 **************************************************************************/
1429 start_selection(GtkWidget *widget, GdkEventButton *event)
1432 gint16 x, y, row, col;
1435 FontgridInternalPageInfo *pi, *opi;
1436 FontgridSelectionInfo sinfo;
1438 fw = FONTGRID(widget);
1441 * Deal with the focus issue first.
1443 if (!GTK_WIDGET_HAS_FOCUS(widget)) {
1444 GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_FOCUS);
1445 (void) fontgrid_draw_focus(widget, NULL);
1448 x = (gint16) event->x;
1449 y = (gint16) event->y;
1451 col = fw->xoff + (fw->cell_width * fw->cell_cols);
1452 row = fw->yoff + (fw->cell_height * fw->cell_rows);
1455 * If the button press is not in the font grid proper, just return.
1457 if (x < fw->xoff || x >= col || y < fw->yoff || y >= row)
1461 * Calculate the row and column that was clicked.
1463 row = (y - fw->yoff) / fw->cell_height;
1464 col = (x - fw->xoff) / fw->cell_width;
1466 if (!fw->unencoded) {
1474 if (fw->orientation == GTK_ORIENTATION_HORIZONTAL)
1475 code = pi->bcode + (row * fw->cell_cols) + col;
1477 code = pi->bcode + (col * fw->cell_rows) + row;
1480 * Any code greater than the maximum is ignored.
1488 gp = fontgrid_locate_glyph(fw->font->glyphs, fw->font->glyphs_used,
1491 gp = fontgrid_locate_glyph(fw->font->unencoded,
1492 fw->font->unencoded_used,
1497 empty_glyph.encoding = code;
1501 if (code != pi->sel_start || code != pi->sel_end) {
1503 * Clear any existing selection.
1505 if (pi->sel_start != -1 || pi->sel_end != -1 ||
1506 opi->sel_start != -1 || opi->sel_end != -1)
1507 fontgrid_deselect_all(fw);
1509 Select(code, pi->selmap);
1511 fontgrid_draw_cells(widget, code, code, FALSE, TRUE);
1513 pi->sel_start = pi->sel_end = code;
1516 * Clear the last click time to avoid situations where the second
1517 * click on a different cell will cause the select callback to be
1524 sinfo.num_glyphs = 1;
1525 sinfo.start = pi->sel_start;
1526 sinfo.end = pi->sel_end;
1527 sinfo.base = fw->base;
1528 sinfo.unencoded = fw->unencoded;
1529 if (event->type == GDK_BUTTON_PRESS &&
1530 event->time - fw->last_click >= fw->mclick_time) {
1531 sinfo.reason = FONTGRID_START_SELECTION;
1532 g_signal_emit(G_OBJECT(fw), fontgrid_signals[SELECTION_START], 0,
1534 } else if (event->type == GDK_2BUTTON_PRESS) {
1535 sinfo.reason = FONTGRID_ACTIVATE;
1536 g_signal_emit(G_OBJECT(fw), fontgrid_signals[ACTIVATE], 0,
1539 fw->last_click = event->time;
1543 extend_selection(GtkWidget *widget, gint16 x, gint16 y)
1549 gboolean call_extend;
1550 FontgridInternalPageInfo *pi;
1551 FontgridSelectionInfo sinfo;
1553 fw = FONTGRID(widget);
1556 * Deal with the focus issue first.
1558 if (!GTK_WIDGET_HAS_FOCUS(widget)) {
1559 GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_FOCUS);
1560 (void) fontgrid_draw_focus(widget, NULL);
1563 col = fw->xoff + (fw->cell_width * fw->cell_cols);
1564 row = fw->yoff + (fw->cell_height * fw->cell_rows);
1567 * If the button press is not in the font grid proper, just return.
1569 if (x < fw->xoff || x >= col || y < fw->yoff || y >= row)
1573 * Calculate the row and column that was clicked.
1575 row = (y - fw->yoff) / fw->cell_height;
1576 col = (x - fw->xoff) / fw->cell_width;
1578 pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
1580 if (fw->orientation == GTK_ORIENTATION_HORIZONTAL)
1581 code = pi->bcode + (row * fw->cell_cols) + col;
1583 code = pi->bcode + (col * fw->cell_rows) + row;
1586 * Any code greater than the maximum is ignored.
1594 gp = fontgrid_locate_glyph(fw->font->glyphs, fw->font->glyphs_used,
1597 gp = fontgrid_locate_glyph(fw->font->unencoded,
1598 fw->font->unencoded_used,
1601 empty_glyph.encoding = code;
1606 call_extend = FALSE;
1607 if (code > pi->sel_end) {
1609 if (code <= pi->sel_start)
1610 fontgrid_deselect_range(fw, pi->sel_end, code - 1);
1612 if (pi->sel_end < pi->sel_start) {
1613 fontgrid_deselect_range(fw, pi->sel_end, pi->sel_start - 1);
1614 fontgrid_select_range(fw, pi->sel_start + 1, code);
1616 fontgrid_select_range(fw, pi->sel_end, code);
1618 } else if (code < pi->sel_end) {
1620 if (code < pi->sel_start) {
1621 if (pi->sel_end > pi->sel_start) {
1622 fontgrid_deselect_range(fw, pi->sel_start + 1, pi->sel_end);
1623 fontgrid_select_range(fw, code, pi->sel_start);
1625 fontgrid_select_range(fw, code, pi->sel_end);
1627 fontgrid_deselect_range(fw, code + 1, pi->sel_end);
1632 if (call_extend == TRUE) {
1633 if (pi->sel_start == pi->sel_end) {
1635 sinfo.num_glyphs = 1;
1638 sinfo.num_glyphs = 0;
1640 sinfo.start = pi->sel_start;
1641 sinfo.end = pi->sel_end;
1642 sinfo.base = fw->base;
1643 sinfo.unencoded = fw->unencoded;
1644 sinfo.reason = FONTGRID_EXTEND_SELECTION;
1645 g_signal_emit(G_OBJECT(fw), fontgrid_signals[SELECTION_EXTEND], 0,
1651 end_selection(GtkWidget *widget, GdkEventButton *event)
1655 FontgridInternalPageInfo *pi;
1656 FontgridSelectionInfo sinfo;
1658 fw = FONTGRID(widget);
1660 pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
1662 if (pi->sel_start != pi->sel_end) {
1664 * Assert ownership of the clipboard if there is a selection of
1665 * more than one glyph.
1667 gdk_selection_owner_set(widget->window, FONTGRID_CLIPBOARD,
1668 GDK_CURRENT_TIME, FALSE);
1670 sinfo.num_glyphs = 0;
1675 gp = fontgrid_locate_glyph(fw->font->glyphs,
1676 fw->font->glyphs_used,
1677 pi->sel_start, TRUE);
1679 gp = fontgrid_locate_glyph(fw->font->unencoded,
1680 fw->font->unencoded_used,
1681 pi->sel_start, TRUE);
1683 empty_glyph.encoding = pi->sel_start;
1689 sinfo.num_glyphs = 1;
1691 sinfo.start = pi->sel_start;
1692 sinfo.end = pi->sel_end;
1693 sinfo.base = fw->base;
1694 sinfo.unencoded = fw->unencoded;
1695 sinfo.reason = FONTGRID_END_SELECTION;
1696 g_signal_emit(G_OBJECT(fw), fontgrid_signals[SELECTION_END], 0,
1701 paste_selection(GtkWidget *widget, GdkEventButton *event)
1703 start_selection(widget, event);
1705 if (event->state & GDK_SHIFT_MASK)
1706 fontgrid_paste_selection(FONTGRID(widget), FONTGRID_INSERT_PASTE);
1707 else if (event->state & GDK_CONTROL_MASK)
1708 fontgrid_paste_selection(FONTGRID(widget), FONTGRID_MERGE_PASTE);
1710 fontgrid_paste_selection(FONTGRID(widget), FONTGRID_NORMAL_PASTE);
1714 copy_selection(GtkWidget *widget, GdkEventButton *event)
1716 fontgrid_copy_selection(FONTGRID(widget));
1719 /**************************************************************************
1721 * Button, pointer motion, and keyboard handling routines.
1723 **************************************************************************/
1726 fontgrid_button_press(GtkWidget *widget, GdkEventButton *event)
1728 switch (event->button) {
1730 if (event->state & GDK_SHIFT_MASK)
1731 extend_selection(widget, (gint16) event->x, (gint16) event->y);
1733 start_selection(widget, event);
1735 case 2: paste_selection(widget, event); break;
1736 case 3: copy_selection(widget, event); break;
1743 fontgrid_button_release(GtkWidget *widget, GdkEventButton *event)
1745 switch (event->button) {
1746 case 1: end_selection(widget, event); break;
1754 fontgrid_motion_notify(GtkWidget *widget, GdkEventMotion *event)
1756 if (event->state & GDK_BUTTON1_MASK)
1757 extend_selection(widget, (gint16) event->x, (gint16) event->y);
1760 * Don't need these at the moment.
1762 if (event->state & GDK_BUTTON2_MASK) {
1764 if (event->state & GDK_BUTTON3_MASK) {
1771 fontgrid_shift_key_press(GtkWidget *widget, GdkEventKey *event)
1776 gint32 code, pageno;
1778 gboolean signal_extend, activate;
1779 FontgridInternalPageInfo *pi, *opi;
1780 FontgridSelectionInfo sinfo;
1782 g_return_val_if_fail(widget != NULL, FALSE);
1783 g_return_val_if_fail(IS_FONTGRID(widget), FALSE);
1784 g_return_val_if_fail(event != NULL, FALSE);
1786 fw = FONTGRID(widget);
1789 * For number keys, use them to add up a count that will effect the
1790 * behavior of the other keys.
1792 if (event->keyval >= GDK_0 && event->keyval <= GDK_9) {
1793 fw->count = (fw->count * 10) + (event->keyval - GDK_0);
1797 if (!fw->unencoded) {
1800 gp = (fw->font && fw->font->glyphs_used) ?
1801 (fw->font->glyphs + (fw->font->glyphs_used - 1)) : 0;
1805 gp = (fw->font && fw->font->unencoded_used) ?
1806 (fw->font->unencoded + (fw->font->unencoded_used - 1)) : 0;
1813 if ((count = fw->count) == 0)
1816 keyval = event->keyval;
1817 switch (event->keyval) {
1819 case GDK_KP_Page_Up:
1820 count *= fw->pagesize;
1824 case GDK_KP_Page_Down:
1825 count *= fw->pagesize;
1830 count = (pi->pageno - pi->minpage) * fw->pagesize;
1835 count = (pi->maxpage - pi->pageno) * fw->pagesize;
1848 if (fw->orientation == GTK_ORIENTATION_VERTICAL)
1849 code -= (fw->cell_rows * count);
1860 * Make sure that when on the unencoded pages, the final glyph is
1861 * the limit unlike the encoded pages where the max value is 0xffff.
1863 if ((fw->unencoded &&
1864 (gp == 0 || code == gp->encoding)) ||
1870 if (fw->orientation == GTK_ORIENTATION_VERTICAL)
1871 code += (fw->cell_rows * count);
1875 if (fw->unencoded && code > gp->encoding)
1876 code = gp->encoding;
1877 else if (code > 0xffff)
1888 if (fw->orientation == GTK_ORIENTATION_HORIZONTAL)
1889 code -= (fw->cell_cols * count);
1900 * Make sure that when on the unencoded pages, the final glyph is
1901 * the limit unlike the encoded pages where the max value is 0xffff.
1903 if ((fw->unencoded &&
1904 (gp == 0 || code == gp->encoding)) ||
1910 if (fw->orientation == GTK_ORIENTATION_HORIZONTAL)
1911 code += (fw->cell_cols * count);
1915 if (fw->unencoded && code > gp->encoding)
1916 code = gp->encoding;
1917 else if (code > 0xffff)
1923 pi->sel_end = pi->sel_start;
1930 signal_extend = FALSE;
1931 if (code > pi->sel_end) {
1932 signal_extend = TRUE;
1933 if (code <= pi->sel_start)
1934 fontgrid_deselect_range(fw, pi->sel_end, code - 1);
1936 if (pi->sel_end < pi->sel_start) {
1937 fontgrid_deselect_range(fw, pi->sel_end, pi->sel_start - 1);
1938 fontgrid_select_range(fw, pi->sel_start + 1, code);
1940 fontgrid_select_range(fw, pi->sel_end, code);
1942 } else if (code < pi->sel_end) {
1943 signal_extend = TRUE;
1944 if (code < pi->sel_start) {
1945 if (pi->sel_end > pi->sel_start) {
1946 fontgrid_deselect_range(fw, pi->sel_start + 1, pi->sel_end);
1947 fontgrid_select_range(fw, code, pi->sel_start);
1949 fontgrid_select_range(fw, code, pi->sel_end);
1951 fontgrid_deselect_range(fw, code + 1, pi->sel_end);
1957 * If the selection endpoint is on some page other than the current
1958 * page, make sure the page holding the end point is made visible.
1960 pageno = code / fw->pagesize;
1961 if (pageno != pi->pageno) {
1962 fw->no_sel_callback = TRUE;
1963 fontgrid_goto_page(fw, pageno);
1971 if (signal_extend) {
1972 if (pi->sel_start == pi->sel_end) {
1974 * Set up and emit the selection start signal.
1977 gp = fontgrid_locate_glyph(fw->font->glyphs,
1978 fw->font->glyphs_used,
1981 gp = fontgrid_locate_glyph(fw->font->unencoded,
1982 fw->font->unencoded_used,
1985 empty_glyph.encoding = code;
1989 sinfo.num_glyphs = 1;
1992 sinfo.num_glyphs = 0;
1994 sinfo.start = pi->sel_start;
1995 sinfo.end = pi->sel_end;
1996 sinfo.base = fw->base;
1997 sinfo.unencoded = fw->unencoded;
2000 sinfo.reason = FONTGRID_EXTEND_SELECTION;
2001 g_signal_emit(G_OBJECT(fw), fontgrid_signals[SELECTION_EXTEND],
2004 sinfo.reason = FONTGRID_ACTIVATE;
2005 g_signal_emit(G_OBJECT(fw), fontgrid_signals[ACTIVATE], 0,
2014 fontgrid_key_press(GtkWidget *widget, GdkEventKey *event)
2018 gint32 code, pageno;
2021 FontgridInternalPageInfo *pi, *opi;
2022 FontgridSelectionInfo sinfo;
2024 g_return_val_if_fail(widget != NULL, FALSE);
2025 g_return_val_if_fail(IS_FONTGRID(widget), FALSE);
2026 g_return_val_if_fail(event != NULL, FALSE);
2028 if (event->state & GDK_SHIFT_MASK)
2029 return fontgrid_shift_key_press(widget, event);
2031 fw = FONTGRID(widget);
2034 * For number keys, use them to add up a count that will effect the
2035 * behavior of the other keys.
2037 if (event->keyval >= GDK_0 && event->keyval <= GDK_9) {
2038 fw->count = (fw->count * 10) + (event->keyval - GDK_0);
2042 if (!fw->unencoded) {
2045 gp = (fw->font && fw->font->glyphs_used) ?
2046 (fw->font->glyphs + (fw->font->glyphs_used - 1)) : 0;
2050 gp = (fw->font && fw->font->unencoded_used) ?
2051 (fw->font->unencoded + (fw->font->unencoded_used - 1)) : 0;
2056 code = pi->sel_start;
2058 if ((count = fw->count) == 0)
2061 switch (event->keyval) {
2069 if (fw->orientation == GTK_ORIENTATION_VERTICAL)
2070 code -= (fw->cell_rows * count);
2081 * Make sure that when on the unencoded pages, the final glyph is
2082 * the limit unlike the encoded pages where the max value is 0xffff.
2084 if ((fw->unencoded &&
2085 (gp == 0 || code == gp->encoding)) ||
2091 if (fw->orientation == GTK_ORIENTATION_VERTICAL)
2092 code += (fw->cell_rows * count);
2096 if (fw->unencoded && code > gp->encoding)
2097 code = gp->encoding;
2098 else if (code > 0xffff)
2109 if (fw->orientation == GTK_ORIENTATION_HORIZONTAL)
2110 code -= (fw->cell_cols * count);
2121 * Make sure that when on the unencoded pages, the final glyph is
2122 * the limit unlike the encoded pages where the max value is 0xffff.
2124 if ((fw->unencoded &&
2125 (gp == 0 || code == gp->encoding)) ||
2131 if (fw->orientation == GTK_ORIENTATION_HORIZONTAL)
2132 code += (fw->cell_cols * count);
2136 if (fw->unencoded && code > gp->encoding)
2137 code = gp->encoding;
2138 else if (code > 0xffff)
2143 case GDK_KP_Page_Up:
2144 fw->from_keyboard = TRUE;
2145 fontgrid_goto_previous_page(fw);
2149 case GDK_KP_Page_Down:
2150 fw->from_keyboard = TRUE;
2151 fontgrid_goto_next_page(fw);
2156 fw->from_keyboard = TRUE;
2157 fontgrid_goto_first_page(fw);
2162 fw->from_keyboard = TRUE;
2163 fontgrid_goto_last_page(fw);
2168 pi->sel_end = pi->sel_start;
2174 fontgrid_cut_selection(fw);
2181 * This turns off the selection which means the cursor is effectively
2182 * turned off even for the fontgrid_goto_page() call. The reason is that
2183 * for keyboard navigation, the cursor should move up and down by rows and
2184 * not whole pages when a page change occurs.
2186 fontgrid_deselect_all(fw);
2188 pageno = code / fw->pagesize;
2189 if (pageno != pi->pageno) {
2190 fw->no_sel_callback = TRUE;
2191 fontgrid_goto_page(fw, pageno);
2194 pi->sel_start = pi->sel_end = code;
2195 Select(code, pi->selmap);
2196 fontgrid_draw_cells(widget, code, code, FALSE, TRUE);
2204 * Set up and emit the selection start signal.
2207 gp = fontgrid_locate_glyph(fw->font->glyphs, fw->font->glyphs_used,
2210 gp = fontgrid_locate_glyph(fw->font->unencoded, fw->font->unencoded_used,
2213 empty_glyph.encoding = code;
2217 sinfo.num_glyphs = 1;
2218 sinfo.start = pi->sel_start;
2219 sinfo.end = pi->sel_end;
2220 sinfo.base = fw->base;
2221 sinfo.unencoded = fw->unencoded;
2224 sinfo.reason = FONTGRID_START_SELECTION;
2225 g_signal_emit(G_OBJECT(fw), fontgrid_signals[SELECTION_START], 0,
2228 sinfo.reason = FONTGRID_ACTIVATE;
2229 g_signal_emit(G_OBJECT(fw), fontgrid_signals[ACTIVATE], 0, &sinfo);
2235 /**************************************************************************
2237 * Class and instance setup.
2239 **************************************************************************/
2242 fontgrid_class_init(gpointer g_class, gpointer class_data)
2244 GObjectClass *gocp = G_OBJECT_CLASS(g_class);
2245 GtkObjectClass *ocp = GTK_OBJECT_CLASS(g_class);
2246 GtkWidgetClass *wcp = GTK_WIDGET_CLASS(g_class);
2249 * Set the class global variables.
2251 parent_class = g_type_class_peek_parent(g_class);
2254 * GObject class functions.
2256 gocp->set_property = fontgrid_set_property;
2257 gocp->get_property = fontgrid_get_property;
2258 gocp->finalize = fontgrid_finalize;
2261 * GtkObjectClass functions.
2263 ocp->destroy = fontgrid_destroy;
2266 * Instance functions.
2268 wcp->size_request = fontgrid_preferred_size;
2269 wcp->size_allocate = fontgrid_actual_size;
2270 wcp->realize = fontgrid_realize;
2271 wcp->expose_event = fontgrid_expose;
2272 wcp->focus_in_event = fontgrid_focus_in;
2273 wcp->focus_out_event = fontgrid_focus_out;
2274 wcp->button_press_event = fontgrid_button_press;
2275 wcp->button_release_event = fontgrid_button_release;
2276 wcp->motion_notify_event = fontgrid_motion_notify;
2277 wcp->key_press_event = fontgrid_key_press;
2278 wcp->selection_clear_event = fontgrid_lose_selection;
2281 * Add parameters (a.k.a. resource) types.
2283 g_object_class_install_property(gocp, PROP_CODE_BASE,
2284 g_param_spec_uint("codeBase",
2286 _("Override for the code base (oct, dec, hex) for glyph codes."),
2290 G_PARAM_READWRITE));
2291 g_object_class_install_property(gocp, PROP_POWER2,
2292 g_param_spec_boolean("powersOfTwo",
2294 _("Indicate whether the grid display should be a power-of-two rows."),
2296 G_PARAM_READWRITE));
2298 g_object_class_install_property(gocp, PROP_ORIENTATION,
2299 g_param_spec_enum("orientation",
2301 _("Should the grid display vertically or horizontally."),
2302 GTK_TYPE_ORIENTATION,
2303 GTK_ORIENTATION_HORIZONTAL,
2304 G_PARAM_READWRITE));
2306 g_object_class_install_property(gocp, PROP_FONT,
2307 g_param_spec_pointer("font",
2309 _("Font to be displayed."),
2310 G_PARAM_READWRITE));
2312 g_object_class_install_property(gocp, PROP_POINT_SIZE,
2313 g_param_spec_uint("pointSize",
2315 _("Set the default point size for new fonts."),
2319 G_PARAM_READWRITE));
2321 g_object_class_install_property(gocp, PROP_SPACING,
2322 g_param_spec_int("spacing",
2324 _("Set the default glyph spacing."),
2328 G_PARAM_READWRITE));
2330 g_object_class_install_property(gocp, PROP_SKIP_BLANKS,
2331 g_param_spec_boolean("skipBlankPages",
2332 _("Skip blank pages"),
2333 _("Avoid displaying pages with no glyphs."),
2335 G_PARAM_READWRITE));
2337 g_object_class_install_property(gocp, PROP_OVERWRITE,
2338 g_param_spec_boolean("overwriteMode",
2339 _("Overwrite mode"),
2340 _("Pasting the selection overwrites."),
2342 G_PARAM_READWRITE));
2344 g_object_class_install_property(gocp, PROP_COLORS,
2345 g_param_spec_pointer("colorList",
2347 _("Colors to be used for glyphs having bits-per-pixel > 1."),
2348 G_PARAM_READWRITE));
2350 g_object_class_install_property(gocp, PROP_INITIAL_GLYPH,
2351 g_param_spec_int("initialGlyph",
2353 _("Code of the glyph to be displayed first."),
2357 G_PARAM_READWRITE));
2359 g_object_class_install_property(gocp, PROP_BPP,
2360 g_param_spec_int("bitsPerPixel",
2361 _("Bits per pixel"),
2362 _("Number of bits per pixel for grayscale glyphs."),
2366 G_PARAM_READWRITE));
2368 g_object_class_install_property(gocp, PROP_HRES,
2369 g_param_spec_int("horizontalResolution",
2370 _("Horizontal resolution"),
2371 _("Set the default horizontal resolution for new fonts."),
2375 G_PARAM_READWRITE));
2377 g_object_class_install_property(gocp, PROP_VRES,
2378 g_param_spec_int("verticalResolution",
2379 _("Vertical resolution"),
2380 _("Set the default vertical resolution for new fonts."),
2384 G_PARAM_READWRITE));
2387 * Add the signals these objects emit.
2389 fontgrid_signals[SELECTION_START] =
2390 g_signal_new("selection-start",
2391 G_TYPE_FROM_CLASS(gocp),
2393 G_STRUCT_OFFSET(FontgridClass, selection_start),
2395 g_cclosure_marshal_VOID__POINTER,
2399 fontgrid_signals[SELECTION_EXTEND] =
2400 g_signal_new("selection-extend",
2401 G_TYPE_FROM_CLASS(gocp),
2403 G_STRUCT_OFFSET(FontgridClass, selection_extend),
2405 g_cclosure_marshal_VOID__POINTER,
2409 fontgrid_signals[SELECTION_END] =
2410 g_signal_new("selection-end",
2411 G_TYPE_FROM_CLASS(gocp),
2413 G_STRUCT_OFFSET(FontgridClass, selection_end),
2415 g_cclosure_marshal_VOID__POINTER,
2419 fontgrid_signals[ACTIVATE] =
2420 g_signal_new("activate",
2421 G_TYPE_FROM_CLASS(gocp),
2423 G_STRUCT_OFFSET(FontgridClass, activate),
2425 g_cclosure_marshal_VOID__POINTER,
2429 fontgrid_signals[MODIFIED] =
2430 g_signal_new("modified",
2431 G_TYPE_FROM_CLASS(gocp),
2433 G_STRUCT_OFFSET(FontgridClass, modified),
2435 g_cclosure_marshal_VOID__POINTER,
2439 fontgrid_signals[TURN_TO_PAGE] =
2440 g_signal_new("turn_to_page",
2441 G_TYPE_FROM_CLASS(gocp),
2443 G_STRUCT_OFFSET(FontgridClass, page),
2445 g_cclosure_marshal_VOID__POINTER,
2452 fontgrid_init(GTypeInstance *obj, gpointer g_class)
2454 Fontgrid *fw = FONTGRID(obj);
2455 FontgridInternalPageInfo *pi;
2459 GTK_WIDGET_SET_FLAGS(fw, GTK_CAN_FOCUS);
2461 gtk_widget_style_get(GTK_WIDGET(fw),
2462 "focus-line-width", &fwidth,
2463 "focus-padding", &fpad,
2468 fw->overwrite = TRUE;
2469 fw->noblanks = TRUE;
2470 fw->orientation = GTK_ORIENTATION_HORIZONTAL;
2471 fw->point_size = 12;
2472 fw->spacing = BDF_CHARCELL;
2474 fw->initial_glyph = 0;
2478 gdk_drawable_get_screen(GDK_DRAWABLE(gdk_get_default_root_window()));
2479 fw->hres = (gint32) ((((double) gdk_screen_get_width(screen)) * 25.4) /
2480 ((double) gdk_screen_get_width_mm(screen)) + 0.5);
2481 fw->vres = (gint32) ((((double) gdk_screen_get_height(screen)) * 25.4) /
2482 ((double) gdk_screen_get_height_mm(screen)) + 0.5);
2484 fw->cell_rows = FGRID_DEFAULT_ROWS;
2485 fw->cell_cols = FGRID_DEFAULT_COLS;
2487 fw->hmargin = fw->widget.style->xthickness + fwidth + fpad + fw->border;
2488 fw->vmargin = fw->widget.style->ythickness + fwidth + fpad + fw->border;
2490 fontgrid_set_cell_geometry(fw);
2491 fontgrid_set_rows_cols(fw, 0);
2494 * Private variables.
2496 fw->unencoded = FALSE;
2499 fw->points_used = 0;
2500 fw->points_size = 0;
2505 fw->mclick_time = 0;
2508 memset((char *) &fw->clipboard, 0, sizeof(bdf_glyphlist_t));
2511 * Initialize the page information.
2515 pi->maxpage = 0xffff / fw->pagesize;
2516 pi->npage = pi->ppage = -1;
2517 pi->pageno = pi->bcode = 0;
2518 pi->sel_start = pi->sel_end = -1;
2519 (void) memset((char *) pi->selmap, 0, sizeof(guint32) * 2048);
2522 pi->maxpage = 0xffff / fw->pagesize;
2523 pi->npage = pi->ppage = -1;
2524 pi->pageno = pi->bcode = 0;
2525 pi->sel_start = pi->sel_end = -1;
2526 (void) memset((char *) pi->selmap, 0, sizeof(guint32) * 2048);
2529 /**************************************************************************
2533 **************************************************************************/
2536 * Type instantiation routines.
2539 fontgrid_get_type(void)
2541 static GType fontgrid_type = 0;
2543 if (!fontgrid_type) {
2544 static const GTypeInfo fontgrid_info = {
2545 sizeof (FontgridClass), /* class_size */
2547 0, /* base_finalize */
2548 fontgrid_class_init, /* class_init */
2549 0, /* class_finalize */
2551 sizeof(Fontgrid), /* instance_size */
2552 0, /* n_preallocs */
2553 fontgrid_init, /* instance_init */
2554 0, /* value_table */
2556 fontgrid_type = g_type_register_static(GTK_TYPE_WIDGET,
2557 "Fontgrid", &fontgrid_info, 0);
2560 return fontgrid_type;
2564 fontgrid_new(const gchar *prop1, ...)
2569 va_start(var_args, prop1);
2570 w = GTK_WIDGET(g_object_new_valist(fontgrid_get_type(), prop1, var_args));
2577 fontgrid_newv(bdf_font_t *font, guint32 pointSize, gint32 spacing,
2578 gboolean skipBlankPages, gboolean overwriteMode,
2579 gboolean powersOfTwo, guint16 *colorList, gint32 initialGlyph,
2580 guint codeBase, GtkOrientation orientation,
2581 gint32 bitsPerPixel, gint32 horizontalResolution,
2582 gint32 verticalResolution, FontgridPageInfo *initialPageInfo)
2584 Fontgrid *fw = FONTGRID(g_object_new(fontgrid_get_type(), NULL));
2586 FontgridInternalPageInfo *pi;
2589 fw->point_size = pointSize;
2590 fw->spacing = spacing;
2591 fw->colors = colorList;
2592 fw->noblanks = skipBlankPages;
2593 fw->overwrite = overwriteMode;
2594 fw->power2 = powersOfTwo;
2595 fw->initial_glyph = initialGlyph;
2596 fw->base = codeBase;
2597 fw->orientation = orientation;
2598 fw->bpp = (font) ? font->bpp : bitsPerPixel;
2599 fw->hres = horizontalResolution;
2600 fw->vres = verticalResolution;
2603 * If no font has been provided, make sure a default is created.
2604 * Too many other things depend on a font existing.
2607 fw->font = bdf_new_font(0, fw->point_size, fw->hres, fw->vres,
2608 fw->spacing, fw->bpp);
2609 if (fw->font->name == 0)
2610 fw->font->name = bdf_make_xlfd_name(fw->font, g_get_prgname(),
2614 fontgrid_set_cell_geometry(fw);
2615 fontgrid_set_rows_cols(fw, 0);
2618 * Initialize the page information.
2622 pi->maxpage = 0xffff / fw->pagesize;
2623 pi->npage = pi->ppage = -1;
2624 pi->pageno = pi->bcode = 0;
2625 pi->sel_start = pi->sel_end = -1;
2626 (void) memset((char *) pi->selmap, 0, sizeof(guint32) * 2048);
2629 pi->maxpage = 0xffff / fw->pagesize;
2630 pi->npage = pi->ppage = -1;
2631 pi->pageno = pi->bcode = 0;
2632 pi->sel_start = pi->sel_end = -1;
2633 (void) memset((char *) pi->selmap, 0, sizeof(guint32) * 2048);
2636 * Determine the page info from the initial glyph setting.
2639 if (fw->initial_glyph == -1)
2640 fw->initial_glyph = (font->glyphs_used > 0) ?
2641 font->glyphs->encoding : 0;
2644 pi->pageno = fw->initial_glyph / fw->pagesize;
2645 pi->bcode = pi->pageno * fw->pagesize;
2646 pi->sel_start = pi->sel_end = fw->initial_glyph;
2647 Select(fw->initial_glyph, pi->selmap);
2648 fontgrid_neighbor_pages(fw, pi->pageno, &pi->ppage, &pi->npage);
2651 * Set the min/max page numbers for the encoded glyphs.
2653 if (font->glyphs_used > 0) {
2655 pi->minpage = font->glyphs->encoding / fw->pagesize;
2657 font->glyphs[font->glyphs_used-1].encoding / fw->pagesize;
2660 pi->maxpage = 0xffff / fw->pagesize;
2665 * Set the min/max page numbers for the unencoded glyphs.
2667 if (font->unencoded_used > 0) {
2671 pi->pageno = pi->minpage =
2672 font->glyphs->encoding / fw->pagesize;
2674 font->unencoded[font->unencoded_used-1].encoding /
2676 pi->bcode = pi->pageno * fw->pagesize;
2680 * Lower boundary for the next page.
2682 boundary = pi->bcode + fw->pagesize;
2683 for (i = 0; i < font->unencoded_used &&
2684 font->unencoded[i].encoding < boundary; i++) ;
2685 pi->npage = (i == font->unencoded_used) ?
2686 -1 : font->unencoded[i].encoding / fw->pagesize;
2689 pi->pageno = pi->minpage = 0;
2690 pi->maxpage = 0xffff / fw->pagesize;
2692 pi->npage = pi->pageno + 1;
2698 * Provide the initial page info the calling application will need
2699 * to set up the page changing labels.
2701 initialPageInfo->unencoded_page = fw->unencoded;
2702 initialPageInfo->encoded_glyphs = (fw->font) ? fw->font->glyphs_used : 0;
2703 initialPageInfo->unencoded_glyphs =
2704 (fw->font) ? fw->font->unencoded_used : 0;
2706 if (!fw->unencoded) {
2707 initialPageInfo->previous_page = fw->npage.ppage;
2708 initialPageInfo->current_page = fw->npage.pageno;
2709 initialPageInfo->next_page = fw->npage.npage;
2711 initialPageInfo->previous_page = fw->upage.ppage;
2712 initialPageInfo->current_page = fw->upage.pageno;
2713 initialPageInfo->next_page = fw->upage.npage;
2716 return GTK_WIDGET(fw);
2720 fontgrid_has_selection(Fontgrid *fw, FontgridSelectionInfo *sinfo)
2722 FontgridInternalPageInfo *pi;
2724 g_return_val_if_fail(fw != 0, FALSE);
2726 pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
2729 * Set up the selection info to alert the application that the
2734 * Initialize the selection info structure.
2736 (void) memset((char *) sinfo, 0, sizeof(FontgridSelectionInfo));
2738 if (pi->sel_start == pi->sel_end) {
2742 fontgrid_locate_glyph(fw->font->glyphs,
2743 fw->font->glyphs_used,
2744 pi->sel_start, TRUE);
2747 fontgrid_locate_glyph(fw->font->unencoded,
2748 fw->font->unencoded_used,
2749 pi->sel_start, TRUE);
2750 if (sinfo->glyphs == 0) {
2751 empty_glyph.encoding = pi->sel_start;
2752 sinfo->glyphs = &empty_glyph;
2754 sinfo->num_glyphs = 1;
2758 sinfo->num_glyphs = 0;
2761 sinfo->start = pi->sel_start;
2762 sinfo->end = pi->sel_end;
2763 sinfo->base = fw->base;
2764 sinfo->unencoded = fw->unencoded;
2765 sinfo->reason = FONTGRID_START_SELECTION;
2768 return (pi->sel_start == -1) ? FALSE : TRUE;
2772 fontgrid_get_font(Fontgrid *fw)
2774 g_return_val_if_fail(fw != 0, 0);
2780 fontgrid_set_font(Fontgrid *fw, bdf_font_t *font, gint32 initial_glyph)
2784 FontgridInternalPageInfo *pi;
2785 FontgridPageInfo pageinfo;
2787 g_return_if_fail(fw != 0);
2789 if (font == fw->font)
2795 * Free up the existing font.
2798 bdf_free_font(fw->font);
2802 * Make sure the encoded pages are the default for newly loaded fonts.
2804 fw->unencoded = FALSE;
2807 * Set the bits-per-pixel from the font.
2809 fw->bpp = (font != 0) ? font->bpp : 1;
2812 * Set the initial glyph code.
2814 fw->initial_glyph = initial_glyph;
2817 * Calculate the cell geometry and the rows and columns.
2819 fontgrid_set_cell_geometry(fw);
2820 fontgrid_set_rows_cols(fw, 0);
2823 * Initialize the page information.
2827 pi->maxpage = 0xffff / fw->pagesize;
2828 pi->npage = pi->ppage = -1;
2829 pi->pageno = pi->bcode = 0;
2830 pi->sel_start = pi->sel_end = -1;
2831 (void) memset((char *) pi->selmap, 0, sizeof(guint32) * 2048);
2834 pi->maxpage = 0xffff / fw->pagesize;
2835 pi->npage = pi->ppage = -1;
2836 pi->pageno = pi->bcode = 0;
2837 pi->sel_start = pi->sel_end = -1;
2838 (void) memset((char *) pi->selmap, 0, sizeof(guint32) * 2048);
2841 * Determine the page info from the initial glyph setting.
2844 if (fw->initial_glyph == -1)
2845 fw->initial_glyph = (font->glyphs_used > 0) ?
2846 font->glyphs->encoding : 0;
2849 pi->pageno = fw->initial_glyph / fw->pagesize;
2850 pi->bcode = pi->pageno * fw->pagesize;
2851 pi->sel_start = pi->sel_end = fw->initial_glyph;
2852 Select(fw->initial_glyph, pi->selmap);
2853 fontgrid_neighbor_pages(fw, pi->pageno, &pi->ppage, &pi->npage);
2856 * Set the min/max page numbers for the encoded glyphs.
2858 if (font->glyphs_used > 0) {
2860 pi->minpage = font->glyphs->encoding / fw->pagesize;
2862 font->glyphs[font->glyphs_used-1].encoding / fw->pagesize;
2865 pi->maxpage = 0xffff / fw->pagesize;
2870 * Set the min/max page numbers for the unencoded glyphs.
2872 if (font->unencoded_used > 0) {
2876 pi->pageno = pi->minpage =
2877 font->glyphs->encoding / fw->pagesize;
2879 font->unencoded[font->unencoded_used-1].encoding /
2881 pi->bcode = pi->pageno * fw->pagesize;
2885 * Lower boundary for the next page.
2887 boundary = pi->bcode + fw->pagesize;
2888 for (i = 0; i < font->unencoded_used &&
2889 font->unencoded[i].encoding < boundary; i++) ;
2890 pi->npage = (i == font->unencoded_used) ?
2891 -1 : font->unencoded[i].encoding / fw->pagesize;
2894 pi->pageno = pi->minpage = 0;
2895 pi->maxpage = 0xffff / fw->pagesize;
2897 pi->npage = pi->pageno + 1;
2903 * Signal that a page change has taken place so the application can do
2904 * setup that it needs.
2906 pageinfo.unencoded_page = fw->unencoded;
2907 pageinfo.encoded_glyphs = (fw->font) ? fw->font->glyphs_used : 0;
2908 pageinfo.unencoded_glyphs = (fw->font) ? fw->font->unencoded_used : 0;
2910 if (!fw->unencoded) {
2911 pageinfo.previous_page = fw->npage.ppage;
2912 pageinfo.current_page = fw->npage.pageno;
2913 pageinfo.next_page = fw->npage.npage;
2915 pageinfo.previous_page = fw->upage.ppage;
2916 pageinfo.current_page = fw->upage.pageno;
2917 pageinfo.next_page = fw->upage.npage;
2920 g_signal_emit(G_OBJECT(fw), fontgrid_signals[TURN_TO_PAGE], 0, &pageinfo);
2923 * Queue up a resize so the grid will change size.
2925 gtk_widget_queue_resize(w);
2929 fontgrid_get_font_messages(Fontgrid *fw)
2931 g_return_val_if_fail(fw != 0, 0);
2933 return (fw->font) ? fw->font->acmsgs : 0;
2937 fontgrid_get_code_base(Fontgrid *fw)
2939 g_return_val_if_fail(fw != 0, 0);
2945 fontgrid_set_code_base(Fontgrid *fw, guint base)
2947 FontgridInternalPageInfo *pi;
2948 FontgridSelectionInfo sinfo;
2950 g_return_if_fail(fw != 0);
2953 case 8: case 10: case 16:
2954 if (fw->base != base) {
2956 if (!fw->unencoded) {
2958 fontgrid_draw_cells(GTK_WIDGET(fw), fw->npage.bcode,
2959 fw->npage.bcode + fw->pagesize,
2965 * Set up the selection info to alert the application that the
2968 if (pi->sel_start == pi->sel_end) {
2972 fontgrid_locate_glyph(fw->font->glyphs,
2973 fw->font->glyphs_used,
2974 pi->sel_start, TRUE);
2977 fontgrid_locate_glyph(fw->font->unencoded,
2978 fw->font->unencoded_used,
2979 pi->sel_start, TRUE);
2980 if (sinfo.glyphs == 0) {
2981 empty_glyph.encoding = pi->sel_start;
2982 sinfo.glyphs = &empty_glyph;
2984 sinfo.num_glyphs = 1;
2988 sinfo.num_glyphs = 0;
2991 sinfo.start = pi->sel_start;
2992 sinfo.end = pi->sel_end;
2993 sinfo.base = fw->base;
2994 sinfo.unencoded = fw->unencoded;
2995 sinfo.reason = FONTGRID_BASE_CHANGE;
2996 g_signal_emit(G_OBJECT(fw), fontgrid_signals[SELECTION_START], 0,
3004 fontgrid_get_orientation(Fontgrid *fw)
3006 g_return_val_if_fail(fw != 0, GTK_ORIENTATION_HORIZONTAL);
3008 return fw->orientation;
3012 fontgrid_set_orientation(Fontgrid *fw, GtkOrientation dir)
3016 g_return_if_fail(fw != 0);
3018 if (dir != fw->orientation) {
3019 fw->orientation = dir;
3022 * Need to swap rows and cols and attempt a resize if the object
3023 * has been constructed.
3025 tmp = fw->cell_rows;
3026 fw->cell_rows = fw->cell_cols;
3027 fw->cell_cols = tmp;
3029 gtk_widget_queue_resize(GTK_WIDGET(fw));
3034 fontgrid_get_page_info(Fontgrid *fw, FontgridPageInfo *pageinfo)
3036 g_return_if_fail(fw != 0);
3037 g_return_if_fail(pageinfo != 0);
3039 pageinfo->unencoded_page = fw->unencoded;
3040 pageinfo->encoded_glyphs = (fw->font) ? fw->font->glyphs_used : 0;
3041 pageinfo->unencoded_glyphs = (fw->font) ? fw->font->unencoded_used : 0;
3043 if (!fw->unencoded) {
3044 pageinfo->previous_page = fw->npage.ppage;
3045 pageinfo->current_page = fw->npage.pageno;
3046 pageinfo->next_page = fw->npage.npage;
3048 pageinfo->previous_page = fw->upage.ppage;
3049 pageinfo->current_page = fw->upage.pageno;
3050 pageinfo->next_page = fw->upage.npage;
3055 * This is the routine that does the majority of the work for updating
3059 fontgrid_page_change_update(Fontgrid *fw, FontgridInternalPageInfo *pi)
3062 FontgridPageInfo pageinfo;
3063 FontgridSelectionInfo selinfo;
3065 code = pi->sel_start - pi->bcode;
3066 pi->bcode = pi->pageno * fw->pagesize;
3068 if (fw->from_keyboard) {
3069 fontgrid_deselect_all(fw);
3071 pi->sel_start = pi->sel_end = code;
3072 Select(code, pi->selmap);
3073 fw->from_keyboard = FALSE;
3075 fontgrid_neighbor_pages(fw, pi->pageno, &pi->ppage, &pi->npage);
3077 fontgrid_draw_cells(GTK_WIDGET(fw), pi->bcode,
3078 pi->bcode + (fw->pagesize - 1), TRUE, TRUE);
3080 pageinfo.unencoded_page = fw->unencoded;
3081 pageinfo.encoded_glyphs = (fw->font) ? fw->font->glyphs_used : 0;
3082 pageinfo.unencoded_glyphs = (fw->font) ? fw->font->unencoded_used : 0;
3084 pageinfo.previous_page = pi->ppage;
3085 pageinfo.current_page = pi->pageno;
3086 pageinfo.next_page = pi->npage;
3088 g_signal_emit(G_OBJECT(fw), fontgrid_signals[TURN_TO_PAGE], 0, &pageinfo);
3091 * If this was called from the keyboard, then indicate the changed
3094 if (!fw->no_sel_callback && fw->from_keyboard) {
3096 selinfo.num_glyphs = 1;
3098 selinfo.glyphs = (!fw->unencoded) ?
3099 fontgrid_locate_glyph(fw->font->glyphs,
3100 fw->font->glyphs_used,
3102 fontgrid_locate_glyph(fw->font->unencoded,
3103 fw->font->unencoded_used,
3106 if (selinfo.glyphs == 0) {
3107 empty_glyph.encoding = code;
3108 selinfo.glyphs = &empty_glyph;
3111 selinfo.reason = FONTGRID_START_SELECTION;
3112 selinfo.start = pi->sel_start;
3113 selinfo.end = pi->sel_end;
3114 selinfo.base = fw->base;
3115 selinfo.unencoded = fw->unencoded;
3116 g_signal_emit(G_OBJECT(fw), fontgrid_signals[SELECTION_START], 0,
3122 fontgrid_goto_page(Fontgrid *fw, gint32 pageno)
3125 FontgridInternalPageInfo *pi;
3127 g_return_if_fail(fw != 0);
3129 pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
3131 mpage = 0xffff / fw->pagesize;
3138 if (pageno != pi->pageno) {
3139 pi->pageno = pageno;
3140 fontgrid_page_change_update(fw, pi);
3145 fontgrid_goto_code(Fontgrid *fw, gint32 code)
3148 FontgridInternalPageInfo *pi;
3149 FontgridSelectionInfo selinfo;
3151 g_return_if_fail(fw != 0);
3153 pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
3160 pageno = code / fw->pagesize;
3162 if (pageno != pi->pageno) {
3163 fw->no_sel_callback = TRUE;
3164 pi->pageno = pageno;
3165 fontgrid_page_change_update(fw, pi);
3168 fontgrid_deselect_all(fw);
3169 Select(code, pi->selmap);
3170 pi->sel_start = pi->sel_end = code;
3171 fontgrid_draw_cells(GTK_WIDGET(fw), code, code, FALSE, TRUE);
3174 selinfo.num_glyphs = 1;
3176 selinfo.glyphs = (!fw->unencoded) ?
3177 fontgrid_locate_glyph(fw->font->glyphs,
3178 fw->font->glyphs_used,
3180 fontgrid_locate_glyph(fw->font->unencoded,
3181 fw->font->unencoded_used,
3184 if (selinfo.glyphs == 0) {
3185 empty_glyph.encoding = code;
3186 selinfo.glyphs = &empty_glyph;
3189 selinfo.reason = FONTGRID_START_SELECTION;
3190 selinfo.start = pi->sel_start;
3191 selinfo.end = pi->sel_end;
3192 selinfo.base = fw->base;
3193 selinfo.unencoded = fw->unencoded;
3194 g_signal_emit(G_OBJECT(fw), fontgrid_signals[SELECTION_START], 0,
3199 fontgrid_goto_first_page(Fontgrid *fw)
3201 FontgridInternalPageInfo *pi;
3203 g_return_if_fail(fw != 0);
3205 pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
3207 if (pi->pageno == pi->minpage)
3210 pi->pageno = pi->minpage;
3211 fontgrid_page_change_update(fw, pi);
3215 fontgrid_goto_last_page(Fontgrid *fw)
3217 FontgridInternalPageInfo *pi;
3219 g_return_if_fail(fw != 0);
3221 pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
3223 if (pi->pageno == pi->maxpage)
3226 pi->pageno = pi->maxpage;
3227 fontgrid_page_change_update(fw, pi);
3231 fontgrid_goto_next_page(Fontgrid *fw)
3233 FontgridInternalPageInfo *pi;
3235 g_return_if_fail(fw != 0);
3237 pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
3239 if (pi->pageno == pi->maxpage)
3242 pi->pageno = pi->npage;
3243 fontgrid_page_change_update(fw, pi);
3247 fontgrid_goto_previous_page(Fontgrid *fw)
3249 FontgridInternalPageInfo *pi;
3251 g_return_if_fail(fw != 0);
3253 pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
3255 if (pi->pageno == pi->minpage)
3258 pi->pageno = pi->ppage;
3259 fontgrid_page_change_update(fw, pi);
3263 fontgrid_viewing_unencoded(Fontgrid *fw)
3265 g_return_val_if_fail(fw != 0, FALSE);
3267 return fw->unencoded;
3271 fontgrid_switch_encoding_view(Fontgrid *fw)
3273 FontgridInternalPageInfo *pi;
3275 g_return_if_fail(fw != 0);
3277 fw->unencoded = !fw->unencoded;
3278 pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
3279 fontgrid_draw_cells(GTK_WIDGET(fw), pi->bcode, pi->bcode + fw->pagesize,
3284 fontgrid_get_font_name(Fontgrid *fw)
3286 g_return_val_if_fail(fw != 0, 0);
3288 return (fw->font) ? fw->font->name : "";
3292 fontgrid_set_font_name(Fontgrid *fw, gchar *name)
3294 FontgridModificationInfo minfo;
3296 g_return_if_fail(fw != 0);
3297 g_return_if_fail(fw->font != 0);
3299 if (fw->font->name != 0)
3300 free(fw->font->name);
3302 if (name == 0 || *name == 0)
3303 fw->font->name = bdf_make_xlfd_name(fw->font, g_get_prgname(),
3306 fw->font->name = g_strdup(name);
3308 bdf_set_modified(fw->font, 1);
3310 minfo.reason = FONTGRID_MODIFIED;
3311 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3315 fontgrid_get_font_modified(Fontgrid *fw)
3317 g_return_val_if_fail(fw != 0, FALSE);
3319 return (fw->font) ? ((fw->font->modified) ? TRUE : FALSE) : FALSE;
3323 fontgrid_set_font_modified(Fontgrid *fw, gboolean mod)
3325 FontgridInternalPageInfo *pi;
3327 g_return_if_fail(fw != 0);
3329 if (fw->font && fw->font->modified != mod) {
3330 bdf_set_modified(fw->font, mod);
3334 * Redraw all the labels to clear those that were showing as
3337 pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
3338 fontgrid_draw_cells(GTK_WIDGET(fw), pi->bcode,
3339 (pi->bcode + fw->pagesize) - 1, TRUE, FALSE);
3342 * If the font is being marked as modified, then signal the
3343 * application of this state.
3345 fprintf(stderr, "MOD\n");
3351 fontgrid_set_unicode_glyph_names(Fontgrid *fw, FILE *in)
3353 FontgridModificationInfo minfo;
3355 g_return_if_fail(fw != 0);
3356 g_return_if_fail(in != 0);
3358 if (bdf_set_unicode_glyph_names(in, fw->font, 0)) {
3360 * Redraw the labels.
3362 fontgrid_draw_cells(GTK_WIDGET(fw), fw->npage.bcode,
3363 fw->npage.bcode + fw->pagesize, TRUE, FALSE);
3364 minfo.reason = FONTGRID_GLYPH_NAMES_MODIFIED;
3365 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3370 fontgrid_set_adobe_glyph_names(Fontgrid *fw, FILE *in)
3372 FontgridModificationInfo minfo;
3374 g_return_if_fail(fw != 0);
3375 g_return_if_fail(in != 0);
3377 if (bdf_set_adobe_glyph_names(in, fw->font, 0)) {
3379 * Redraw the labels.
3381 fontgrid_draw_cells(GTK_WIDGET(fw), fw->npage.bcode,
3382 fw->npage.bcode + fw->pagesize, TRUE, FALSE);
3383 minfo.reason = FONTGRID_GLYPH_NAMES_MODIFIED;
3384 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3389 fontgrid_set_code_glyph_names(Fontgrid *fw, gint ch)
3391 FontgridModificationInfo minfo;
3393 g_return_if_fail(fw != 0);
3395 if (bdf_set_glyph_code_names(ch, fw->font, 0)) {
3397 * Redraw the labels.
3399 fontgrid_draw_cells(GTK_WIDGET(fw), fw->npage.bcode,
3400 fw->npage.bcode + fw->pagesize, TRUE, FALSE);
3401 minfo.reason = FONTGRID_GLYPH_NAMES_MODIFIED;
3402 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3407 fontgrid_make_xlfd_font_name(Fontgrid *fw)
3409 FontgridModificationInfo minfo;
3411 g_return_if_fail(fw != 0);
3413 if ((minfo.name = bdf_make_xlfd_name(fw->font, "Foundry",
3414 "FaceName")) != 0) {
3415 minfo.reason = FONTGRID_NAME_MODIFIED;
3416 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3421 fontgrid_update_font_name_from_properties(Fontgrid *fw)
3423 FontgridModificationInfo minfo;
3425 g_return_if_fail(fw != 0);
3427 if (bdf_has_xlfd_name(fw->font)) {
3428 bdf_update_name_from_properties(fw->font);
3430 minfo.reason = FONTGRID_NAME_MODIFIED;
3431 minfo.name = fw->font->name;
3432 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3437 fontgrid_update_properties_from_font_name(Fontgrid *fw)
3439 FontgridModificationInfo minfo;
3441 g_return_if_fail(fw != 0);
3443 if (bdf_update_properties_from_name(fw->font)) {
3444 minfo.reason = FONTGRID_PROPERTIES_MODIFIED;
3445 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3450 fontgrid_set_font_property(Fontgrid *fw, bdf_property_t *prop)
3452 FontgridModificationInfo minfo;
3456 g_return_if_fail(fw != 0);
3457 g_return_if_fail(prop != 0);
3461 if ((p = bdf_get_font_property(fw->font, prop->name)) == 0)
3463 else if (p->format == prop->format) {
3464 switch (p->format) {
3467 * If the atoms are different or one is NULL and the other isn't,
3468 * then the property will be changed.
3470 if ((p->value.atom && prop->value.atom &&
3471 strcmp(p->value.atom, prop->value.atom) != 0) ||
3472 p->value.atom != prop->value.atom)
3476 if (p->value.int32 != prop->value.int32)
3480 if (p->value.card32 != prop->value.card32)
3487 * If this causes no change, just return.
3489 if (changed == FALSE)
3492 bdf_add_font_property(fw->font, prop);
3493 minfo.reason = FONTGRID_PROPERTIES_MODIFIED;
3494 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3498 fontgrid_delete_font_property(Fontgrid *fw, gchar *prop_name)
3500 FontgridModificationInfo minfo;
3503 g_return_if_fail(fw != 0);
3504 g_return_if_fail(prop_name != 0);
3507 * If the property doesn't exist, then just return.
3509 if ((p = bdf_get_font_property(fw->font, prop_name)) == 0)
3512 bdf_delete_font_property(fw->font, prop_name);
3513 minfo.reason = FONTGRID_PROPERTIES_MODIFIED;
3514 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3518 fontgrid_get_font_comments(Fontgrid *fw, gchar **comments)
3520 g_return_val_if_fail(fw != 0, 0);
3523 *comments = fw->font->comments;
3525 return fw->font->comments_len;
3529 fontgrid_set_font_comments(Fontgrid *fw, gchar *comments)
3531 FontgridModificationInfo minfo;
3534 g_return_if_fail(fw != 0);
3536 len = (comments) ? (unsigned int) strlen(comments) : 0;
3537 if (bdf_replace_comments(fw->font, comments, len)) {
3538 minfo.reason = FONTGRID_COMMENTS_MODIFIED;
3539 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3544 fontgrid_get_font_spacing(Fontgrid *fw)
3546 g_return_val_if_fail(fw != 0, -1);
3548 return fw->font->spacing;
3552 fontgrid_set_font_spacing(Fontgrid *fw, gint spacing)
3554 FontgridModificationInfo minfo;
3557 g_return_if_fail(fw != 0);
3559 if (spacing < BDF_PROPORTIONAL || spacing > BDF_CHARCELL ||
3560 fw->font->spacing == spacing)
3564 p.format = BDF_ATOM;
3566 case BDF_PROPORTIONAL: p.value.atom = "P"; break;
3567 case BDF_MONOWIDTH: p.value.atom = "M"; break;
3568 case BDF_CHARCELL: p.value.atom = "C"; break;
3571 bdf_add_font_property(fw->font, &p);
3572 minfo.reason = FONTGRID_PROPERTIES_MODIFIED;
3573 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3577 fontgrid_get_font_device_width(Fontgrid *fw)
3579 g_return_val_if_fail(fw != 0, 0);
3581 return fw->font->monowidth;
3585 fontgrid_set_font_device_width(Fontgrid *fw, guint16 dwidth)
3587 FontgridModificationInfo minfo;
3589 g_return_if_fail(fw != 0);
3592 * Only set the global device width if this is not a proportional font or
3593 * if there the device width changed.
3595 if (fw->font->spacing == BDF_PROPORTIONAL ||
3596 fw->font->monowidth == dwidth)
3599 fw->font->monowidth = dwidth;
3600 fw->font->modified = 1;
3602 minfo.reason = FONTGRID_DEVICE_WIDTH_MODIFIED;
3603 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3607 fontgrid_get_font_info(Fontgrid *fw, FontgridFontInfo *info)
3609 g_return_if_fail(fw != 0);
3610 g_return_if_fail(fw->font != 0);
3611 g_return_if_fail(info != 0);
3613 info->name = fw->font->name;
3614 info->comments = fw->font->comments;
3615 info->messages = fw->font->acmsgs;
3616 info->default_char = fw->font->default_glyph;
3617 info->monowidth = fw->font->monowidth;
3618 info->spacing = (guint16) fw->font->spacing;
3619 info->font_ascent = fw->font->font_ascent;
3620 info->font_descent = fw->font->font_descent;
3621 info->font_descent = fw->font->font_descent;
3622 info->resolution_x = fw->font->resolution_x;
3623 info->resolution_y = fw->font->resolution_y;
3624 info->bits_per_pixel = fw->font->bpp;
3625 memcpy((char *) &info->bbx, (char *) &fw->font->bbx, sizeof(bdf_bbx_t));
3629 fontgrid_set_font_info(Fontgrid *fw, FontgridFontInfo *info)
3633 bdf_property_t prop;
3634 FontgridModificationInfo minfo;
3636 g_return_if_fail(fw != 0);
3637 g_return_if_fail(fw->font != 0);
3638 g_return_if_fail(info != 0);
3642 minfo.reason = FONTGRID_MODIFIED;
3645 * Do some special stuff with the modified field so we know whether to
3646 * call the modified callback or not.
3652 * Handle the default character field. If it happens to be -1, then
3653 * delete the font property. Otherwise add it.
3655 if (info->default_char < 0)
3656 bdf_delete_font_property(f, "DEFAULT_CHAR");
3658 prop.name = "DEFAULT_CHAR";
3659 prop.format = BDF_CARDINAL;
3660 prop.value.card32 = info->default_char;
3661 bdf_add_font_property(f, &prop);
3664 prop.name = "FONT_ASCENT";
3665 prop.format = BDF_INTEGER;
3666 prop.value.int32 = info->font_ascent;
3667 bdf_add_font_property(f, &prop);
3669 prop.name = "FONT_DESCENT";
3670 prop.format = BDF_INTEGER;
3671 prop.value.int32 = info->font_descent;
3672 bdf_add_font_property(f, &prop);
3674 prop.name = "RESOLUTION_X";
3675 prop.format = BDF_CARDINAL;
3676 prop.value.int32 = info->resolution_x;
3677 bdf_add_font_property(f, &prop);
3679 prop.name = "RESOLUTION_Y";
3680 prop.format = BDF_CARDINAL;
3681 prop.value.int32 = info->resolution_y;
3682 bdf_add_font_property(f, &prop);
3684 prop.name = "SPACING";
3685 prop.format = BDF_ATOM;
3686 prop.value.atom = 0;
3687 switch (info->spacing) {
3688 case BDF_PROPORTIONAL: prop.value.atom = "P"; break;
3689 case BDF_MONOWIDTH: prop.value.atom = "M"; break;
3690 case BDF_CHARCELL: prop.value.atom = "C"; break;
3692 if (prop.value.atom != 0)
3693 bdf_add_font_property(f, &prop);
3696 * If the font was modified, and has an XLFD name, make sure the XLFD name
3697 * gets updated from the properties and the appropriate callback is
3700 if (f->modified && bdf_has_xlfd_name(f))
3701 fontgrid_update_font_name_from_properties(fw);
3704 * Now determine if the monowidth field will have a resize affect on
3707 if (f->spacing != BDF_PROPORTIONAL) {
3708 if (f->monowidth == 0) {
3710 * Handle the special case of a proportional font being changed to
3711 * some other spacing.
3713 f->monowidth = f->bbx.width;
3716 if (info->monowidth != f->monowidth) {
3718 * Go ahead and queue up a resize in case the monowidth
3719 * really does change the size.
3721 gtk_widget_queue_resize(GTK_WIDGET(fw));
3722 f->monowidth = f->bbx.width = info->monowidth;
3727 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3732 fontgrid_translate_glyphs(Fontgrid *fw, gint16 dx, gint16 dy,
3733 gboolean all_glyphs)
3735 GtkWidget *w = (GtkWidget *) fw;
3737 FontgridInternalPageInfo *pi;
3738 FontgridModificationInfo minfo;
3740 g_return_if_fail(fw != 0);
3742 pi = (!fw->unencoded) ? &fw->npage: &fw->upage;
3745 start = pi->minpage * fw->pagesize;
3746 end = (pi->maxpage * fw->pagesize) + fw->pagesize;
3748 start = pi->sel_start;
3752 if (bdf_translate_glyphs(fw->font, dx, dy, start, end, 0, 0,
3754 gtk_widget_queue_resize(w);
3755 if (GTK_WIDGET_REALIZED(w))
3756 gdk_window_clear(w->window);
3758 gtk_widget_queue_resize(w);
3759 if (GTK_WIDGET_REALIZED(w))
3760 gdk_window_clear(w->window);
3762 minfo.reason = FONTGRID_GLYPHS_MODIFIED;
3763 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3768 fontgrid_rotate_glyphs(Fontgrid *fw, gint16 degrees, gboolean all_glyphs)
3770 GtkWidget *w = (GtkWidget *) fw;
3772 FontgridInternalPageInfo *pi;
3773 FontgridModificationInfo minfo;
3775 g_return_if_fail(fw != 0);
3777 pi = (!fw->unencoded) ? &fw->npage: &fw->upage;
3780 start = pi->minpage * fw->pagesize;
3781 end = (pi->maxpage * fw->pagesize) + fw->pagesize;
3783 start = pi->sel_start;
3787 if (bdf_rotate_glyphs(fw->font, degrees, start, end, 0, 0,
3789 gtk_widget_queue_resize(w);
3790 if (GTK_WIDGET_REALIZED(w))
3791 gdk_window_clear(w->window);
3793 minfo.reason = FONTGRID_GLYPHS_MODIFIED;
3794 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3799 fontgrid_shear_glyphs(Fontgrid *fw, gint16 degrees, gboolean all_glyphs)
3801 GtkWidget *w = (GtkWidget *) fw;
3803 FontgridInternalPageInfo *pi;
3804 FontgridModificationInfo minfo;
3806 g_return_if_fail(fw != 0);
3808 pi = (!fw->unencoded) ? &fw->npage: &fw->upage;
3811 start = pi->minpage * fw->pagesize;
3812 end = (pi->maxpage * fw->pagesize) + fw->pagesize;
3814 start = pi->sel_start;
3818 if (bdf_shear_glyphs(fw->font, degrees, start, end, 0, 0,
3820 gtk_widget_queue_resize(w);
3821 if (GTK_WIDGET_REALIZED(w))
3822 gdk_window_clear(w->window);
3824 minfo.reason = FONTGRID_GLYPHS_MODIFIED;
3825 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3830 fontgrid_embolden_glyphs(Fontgrid *fw, gboolean all_glyphs)
3832 GtkWidget *w = (GtkWidget *) fw;
3835 FontgridInternalPageInfo *pi;
3836 FontgridModificationInfo minfo;
3838 g_return_if_fail(fw != 0);
3840 pi = (!fw->unencoded) ? &fw->npage: &fw->upage;
3843 start = pi->minpage * fw->pagesize;
3844 end = (pi->maxpage * fw->pagesize) + fw->pagesize;
3846 start = pi->sel_start;
3851 if (bdf_embolden_glyphs(fw->font, start, end, 0, 0,
3852 fw->unencoded, &resize)) {
3854 gtk_widget_queue_resize(w);
3855 if (GTK_WIDGET_REALIZED(w))
3856 gdk_window_clear(w->window);
3859 * Just redisplay the selection.
3861 fontgrid_draw_cells(w, start, end, TRUE, TRUE);
3863 minfo.reason = FONTGRID_GLYPHS_MODIFIED;
3864 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3869 fontgrid_clipboard_empty(Fontgrid *fw)
3872 gboolean empty = TRUE;
3874 gint aformat, nitems;
3877 g_return_val_if_fail(fw != 0, empty);
3879 if ((owner = gdk_selection_owner_get(FONTGRID_CLIPBOARD)) == 0)
3883 * Check to see if the clipboard contents are empty or not.
3885 * This is handled specially to allow determination of this without
3886 * using up what might be a lot of memory to get the whole contents. It
3887 * will have to be changed for Windows.
3889 if (gdk_property_get(owner, FONTGRID_CLIPBOARD, FONTGRID_GLYPHLIST,
3890 0, 4, FALSE, &atype, &aformat, &nitems, &data)) {
3893 free((char *) data);
3900 static unsigned char *
3901 fontgrid_encode_selection(Fontgrid *fw, guint32 *bytes)
3903 FontgridInternalPageInfo *pi;
3905 bdf_glyphlist_t *gl;
3907 guint32 i, nlen, bcount;
3912 gl = &fw->clipboard;
3913 pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
3914 bdf_copy_glyphs(fw->font, pi->sel_start, pi->sel_end, gl, fw->unencoded);
3917 * Calculate the number of bytes that will be needed for everything except
3918 * the name strings and the bitmap data.
3920 bcount = (sizeof(unsigned int) << 1) + (6 * sizeof(unsigned short)) +
3921 (((6 * sizeof(unsigned short)) + sizeof(unsigned int)) *
3925 * Figure out how much extra will be needed for the names, bitmaps, and
3926 * PSF Unicode mappings.
3928 for (i = 0, gp = gl->glyphs; i < gl->glyphs_used; i++, gp++) {
3929 nlen = (gp->name) ? (guint32) (strlen(gp->name) + 1) : 0;
3931 * The extra 2 bytes is for encoding the number of bytes used for the
3932 * Unicode mappings, even if it is 0. This could be a problem later
3933 * if a set of mappings legitimately exceeds 2^16 in length.
3935 bcount += nlen + gp->bytes + 2 + gp->unicode.map_used;
3939 * Allocate the storage space needed for the encoded form.
3941 sel = sp = g_malloc(bcount);
3944 * Set the returned byte count.
3949 * Encode the 20-byte header.
3951 a = (guint16) gl->bpp;
3952 *sp++ = (a >> 8) & 0xff;
3955 nlen = (guint32) gl->start;
3956 *sp++ = (nlen >> 24) & 0xff;
3957 *sp++ = (nlen >> 16) & 0xff;
3958 *sp++ = (nlen >> 8) & 0xff;
3959 *sp++ = nlen & 0xff;
3961 nlen = (guint32) gl->end;
3962 *sp++ = (nlen >> 24) & 0xff;
3963 *sp++ = (nlen >> 16) & 0xff;
3964 *sp++ = (nlen >> 8) & 0xff;
3965 *sp++ = nlen & 0xff;
3967 a = (guint16) gl->glyphs_used;
3968 *sp++ = (a >> 8) & 0xff;
3971 a = (guint16) gl->bbx.width;
3972 *sp++ = (a >> 8) & 0xff;
3975 a = (guint16) gl->bbx.x_offset;
3976 *sp++ = (a >> 8) & 0xff;
3979 a = (guint16) gl->bbx.ascent;
3980 *sp++ = (a >> 8) & 0xff;
3983 a = (guint16) gl->bbx.descent;
3984 *sp++ = (a >> 8) & 0xff;
3988 * Go through each glyph entry and encode the data.
3990 for (i = 0, gp = gl->glyphs; i < gl->glyphs_used; i++, gp++) {
3992 * Encode the glyph encoding.
3994 nlen = (guint32) gp->encoding;
3995 *sp++ = (nlen >> 24) & 0xff;
3996 *sp++ = (nlen >> 16) & 0xff;
3997 *sp++ = (nlen >> 8) & 0xff;
3998 *sp++ = nlen & 0xff;
4001 * Encode the glyph device width.
4003 a = (guint16) gp->dwidth;
4004 *sp++ = (a >> 8) & 0xff;
4008 * Encode the glyph name length.
4010 nlen = (gp->name) ? (guint32) (strlen(gp->name) + 1) : 0;
4012 *sp++ = (a >> 8) & 0xff;
4016 * Encode the four bounding box values needed.
4018 a = (guint16) gp->bbx.width;
4019 *sp++ = (a >> 8) & 0xff;
4022 a = (guint16) gp->bbx.x_offset;
4023 *sp++ = (a >> 8) & 0xff;
4026 a = (guint16) gp->bbx.ascent;
4027 *sp++ = (a >> 8) & 0xff;
4030 a = (guint16) gp->bbx.descent;
4031 *sp++ = (a >> 8) & 0xff;
4035 * Encode the name if it exists.
4038 (void) memcpy((char *) sp, gp->name, nlen);
4043 * Encode the bitmap.
4045 if (gp->bytes > 0) {
4046 (void) memcpy((char *) sp, (char *) gp->bitmap, gp->bytes);
4051 * Encode the PSF Unicode mappings. Even if there aren't any, add
4054 *sp++ = (gp->unicode.map_used >> 8) & 0xff;
4055 *sp++ = gp->unicode.map_used & 0xff;
4056 if (gp->unicode.map_used > 0) {
4057 (void) memcpy((char *) sp, (char *) gp->unicode.map,
4058 sizeof(unsigned char) * gp->unicode.map_used);
4059 sp += gp->unicode.map_used;
4064 * Return the selection encoded as a byte stream.
4069 #define GETSHORT(s) ((s[0] << 8) | s[1])
4070 #define GETLONG(s) ((s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3])
4073 fontgrid_decode_selection(Fontgrid *fw, guchar *sel)
4075 guint32 i, range, nlen;
4077 bdf_glyphlist_t *gl;
4082 gl = &fw->clipboard;
4085 * Clear out the bitmaps and names from the existing glyphs.
4087 for (gp = gl->glyphs, i = 0; i < gl->glyphs_size; i++, gp++) {
4091 free((char *) gp->bitmap);
4095 * Extract the glyph list bits per pixel.
4097 gl->bpp = GETSHORT(sel);
4101 * Extract the glyph list starting and ending encodings.
4103 gl->start = (int) GETLONG(sel);
4106 gl->end = (int) GETLONG(sel);
4110 * Extract the number of encoded glyphs.
4112 range = (guint32) GETSHORT(sel);
4116 * Resize the internal glyph list clipboard if necessary.
4118 if (range > gl->glyphs_size) {
4119 if (gl->glyphs_size == 0)
4120 gl->glyphs = (bdf_glyph_t *) malloc(sizeof(bdf_glyph_t) * range);
4122 gl->glyphs = (bdf_glyph_t *) realloc((char *) gl->glyphs,
4123 sizeof(bdf_glyph_t) * range);
4124 gl->glyphs_size = range;
4128 * Initialize the glyph list.
4130 (void) memset((char *) &gl->bbx, 0, sizeof(bdf_bbx_t));
4131 (void) memset((char *) gl->glyphs, 0,
4132 sizeof(bdf_glyph_t) * gl->glyphs_size);
4134 gl->glyphs_used = range;
4137 * Decode the overall metrics of the glyph list.
4139 gl->bbx.width = GETSHORT(sel);
4141 gl->bbx.x_offset = GETSHORT(sel);
4143 gl->bbx.ascent = GETSHORT(sel);
4145 gl->bbx.descent = GETSHORT(sel);
4147 gl->bbx.height = gl->bbx.ascent + gl->bbx.descent;
4148 gl->bbx.y_offset = -gl->bbx.descent;
4151 * Decode the glyphs.
4153 for (i = 0, gp = gl->glyphs; i < range; i++, gp++) {
4155 * Get the glyph encoding.
4157 gp->encoding = (int) GETLONG(sel);
4161 * Get the device width.
4163 gp->dwidth = GETSHORT(sel);
4167 * Get the name length.
4169 nlen = GETSHORT(sel);
4173 * Get the bounding box.
4175 gp->bbx.width = GETSHORT(sel);
4177 gp->bbx.x_offset = GETSHORT(sel);
4179 gp->bbx.ascent = GETSHORT(sel);
4181 gp->bbx.descent = GETSHORT(sel);
4183 gp->bbx.height = gp->bbx.ascent + gp->bbx.descent;
4184 gp->bbx.y_offset = -gp->bbx.descent;
4190 gp->name = (char *) malloc(nlen);
4191 (void) memcpy(gp->name, (char *) sel, nlen);
4201 gp->bytes = ((gp->bbx.width + 7) >> 3) * gp->bbx.height;
4204 gp->bytes = (((gp->bbx.width << 1) + 7) >> 3) * gp->bbx.height;
4207 gp->bytes = (((gp->bbx.width << 2) + 7) >> 3) * gp->bbx.height;
4210 gp->bytes = gp->bbx.width * gp->bbx.height;
4214 if (gp->bytes > 0) {
4215 gp->bitmap = (unsigned char *) malloc(gp->bytes);
4216 (void) memcpy((char *) gp->bitmap, (char *) sel, gp->bytes);
4221 * Get the Unicode mappings.
4223 gp->unicode.map_used = GETSHORT(sel);
4225 if (gp->unicode.map_used > 0) {
4226 gp->unicode.map_size = ((gp->unicode.map_used >> 2) +
4227 ((gp->unicode.map_used & 3) ? 1 : 0)) << 2;
4228 gp->unicode.map = (unsigned char *) malloc(gp->unicode.map_size);
4229 (void) memcpy((char *) gp->unicode.map, (char *) sel,
4230 gp->unicode.map_used);
4231 sel += gp->unicode.map_used;
4237 * This function assumes the fontgrid is realized so a GdkWindow exists.
4240 fontgrid_copy_selection(Fontgrid *fw)
4247 g_return_if_fail(fw != 0);
4252 * Make sure the widget owns the clipboard property.
4254 if ((win = gdk_selection_owner_get(FONTGRID_CLIPBOARD)) == 0 ||
4256 gdk_selection_owner_set(w->window, FONTGRID_CLIPBOARD, GDK_CURRENT_TIME,
4260 * Encode the selection as a byte stream for the clipboard.
4262 if ((sel = fontgrid_encode_selection(fw, &bytes)) == 0)
4265 gdk_property_change(w->window, FONTGRID_CLIPBOARD, FONTGRID_GLYPHLIST,
4266 8, GDK_PROP_MODE_REPLACE, sel, (gint) bytes);
4269 * Free the data because the property now has control over it.
4275 fontgrid_cut_selection(Fontgrid *fw)
4277 gint32 code, start, end;
4279 FontgridInternalPageInfo *pi;
4280 FontgridModificationInfo minfo;
4281 FontgridSelectionInfo sinfo;
4283 g_return_if_fail(fw != 0);
4285 fontgrid_copy_selection(fw);
4287 pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
4288 code = pi->sel_start;
4290 if (bdf_delete_glyphs(fw->font, pi->sel_start, pi->sel_end,
4292 start = pi->sel_start;
4295 fontgrid_deselect_all(fw);
4296 Select(code, pi->selmap);
4297 pi->sel_start = pi->sel_end = code;
4298 fontgrid_draw_cells(GTK_WIDGET(fw), start, end, TRUE, TRUE);
4301 * Set up and emit the modified signal.
4303 minfo.reason = FONTGRID_GLYPHS_DELETED;
4304 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
4307 * Set up and call the selection start signal.
4309 gp = (!fw->unencoded) ?
4310 fontgrid_locate_glyph(fw->font->glyphs, fw->font->glyphs_used,
4312 fontgrid_locate_glyph(fw->font->unencoded,
4313 fw->font->unencoded_used, code, TRUE);
4315 empty_glyph.encoding = code;
4320 sinfo.num_glyphs = 1;
4321 sinfo.start = sinfo.end = code;
4322 sinfo.base = fw->base;
4323 sinfo.unencoded = fw->unencoded;
4324 sinfo.reason = FONTGRID_START_SELECTION;
4325 g_signal_emit(G_OBJECT(fw), fontgrid_signals[SELECTION_START], 0,
4331 fontgrid_paste_selection(Fontgrid *fw, FontgridPasteType paste_type)
4333 GtkWidget *w = GTK_WIDGET(fw);
4336 gint afmt, nitems, unenc, doresize;
4342 bdf_glyphlist_t *gl;
4343 FontgridInternalPageInfo *pi;
4344 bdf_glyphlist_t overflow;
4345 FontgridModificationInfo minfo;
4346 FontgridSelectionInfo sinfo;
4348 g_return_if_fail(fw != 0);
4349 g_return_if_fail(GTK_WIDGET_REALIZED(w));
4351 if ((win = gdk_selection_owner_get(FONTGRID_CLIPBOARD)) == 0) {
4352 gdk_selection_owner_set(w->window, FONTGRID_CLIPBOARD,
4353 GDK_CURRENT_TIME, FALSE);
4355 * Return here because there was no owner of the selection.
4361 unenc = fw->unencoded;
4363 pi = (!unenc) ? &fw->npage : &fw->upage;
4366 (void) gdk_property_get(win, FONTGRID_CLIPBOARD, FONTGRID_GLYPHLIST,
4367 0, 102400, FALSE, &atype, &afmt, &nitems, &data);
4370 * Attempt to own the clipboard after getting the value if this widget
4373 if (win != w->window)
4374 gdk_selection_owner_set(w->window, FONTGRID_CLIPBOARD, GDK_CURRENT_TIME,
4379 gl = &fw->clipboard;
4382 * Convert the encoded selection into a glyph list in the internal
4383 * glyph list clipboard.
4385 fontgrid_decode_selection(fw, data);
4388 * If the paste is occuring in the unencoded section, make sure the
4389 * paste is appended as opposed to being inserted. Also turn off
4390 * the selected cell before doing the paste.
4393 fontgrid_deselect_all(fw);
4394 pi->sel_start = font->unencoded_used;
4396 gl->end = gl->glyphs_used - 1;
4400 * Set the end point of the selection.
4402 pi->sel_end = pi->sel_start + (gl->end - gl->start);
4405 * First, check to see if pasting the glyphs will exceed the maximum
4406 * encoding value of 0xffff. If some of them do, then transfer the
4407 * extra glyphs to the unencoded area before doing anything else.
4408 * This means that a new glyph list needs to be constructed to do the
4409 * insert into the unencoded area.
4411 if (!unenc && pi->sel_end > 0xffff) {
4413 * Determine if any of the glyphs would actually get encoded after
4414 * 0xffff or if those are all empty glyphs.
4416 for (ng = 0, gp = gl->glyphs; ng < gl->glyphs_used; ng++, gp++) {
4417 if (pi->sel_start + (gp->encoding - gl->start) > 0xffff)
4419 * The glyph list does contain glyphs that will overflow.
4424 if (ng < gl->glyphs_used) {
4426 * Construct a new glyph list containing only the glyphs that
4427 * overflow the 0xffff boundary. There is no need to
4428 * recalculate the bounding box for the new glyph list. Any
4429 * resize will be handled correctly anyway.
4431 (void) memcpy((char *) &overflow.bbx, (char *) &gl->bbx,
4433 overflow.bpp = font->bpp;
4434 overflow.glyphs_used = gl->glyphs_used - ng;
4435 overflow.glyphs = gp;
4437 overflow.end = overflow.glyphs_used - 1;
4440 * Add the glyphs to the unencoded area.
4442 doresize = bdf_replace_glyphs(font, font->unencoded_used,
4447 * Adjust the glyph list and selection to fit within the 0xffff
4448 * limit before pasting the glyphs into the font.
4450 gl->glyphs_used = ng;
4451 gl->end -= pi->sel_end - 0xffff;
4452 pi->sel_end = 0xffff;
4456 * If the grid is in insert mode, then determine if moving glyphs
4457 * forward from the insert location would cause an overflow.
4460 (!fw->overwrite || paste_type == FONTGRID_INSERT_PASTE)) {
4461 doresize += bdf_insert_glyphs(font, pi->sel_start, gl);
4463 * Force a page recalculation to be done so the application can
4466 fontgrid_goto_page(fw, fw->npage.pageno);
4467 } else if (paste_type == FONTGRID_MERGE_PASTE)
4468 doresize += bdf_merge_glyphs(font, pi->sel_start, gl, unenc);
4470 doresize += bdf_replace_glyphs(font, pi->sel_start, gl, unenc);
4473 * If the paste has more than one glyph, make sure the whole
4474 * range is selected.
4476 for (i = pi->sel_start; i <= pi->sel_end; i++)
4477 Select(i, pi->selmap);
4480 * If the incoming glyphs changed the font bounding box, then
4481 * determine the new geometry and attempt a resize.
4484 fontgrid_set_cell_geometry(fw);
4485 fontgrid_set_rows_cols(fw, 0);
4486 gtk_widget_queue_resize(w);
4488 fontgrid_draw_cells(w, pi->sel_start, pi->sel_end, TRUE, TRUE);
4491 * Update the number of pages used.
4495 if (font->unencoded_used == 0)
4498 gp = font->unencoded + (font->unencoded_used - 1);
4499 pi->maxpage = gp->encoding / fw->pagesize;
4504 if (font->glyphs_used == 0)
4507 gp = font->glyphs + (font->glyphs_used - 1);
4508 pi->maxpage = gp->encoding / fw->pagesize;
4514 * Set up and call the modified callback.
4517 * Set up and emit the modified signal.
4519 minfo.reason = FONTGRID_GLYPHS_PASTED;
4520 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
4522 if (pi->sel_start == pi->sel_end) {
4524 * Set up and call the selection start signal.
4526 gp = (!fw->unencoded) ?
4527 fontgrid_locate_glyph(fw->font->glyphs, fw->font->glyphs_used,
4528 pi->sel_start, TRUE) :
4529 fontgrid_locate_glyph(fw->font->unencoded,
4530 fw->font->unencoded_used, pi->sel_start,
4533 empty_glyph.encoding = pi->sel_start;
4538 sinfo.num_glyphs = 1;
4541 sinfo.num_glyphs = 0;
4543 sinfo.start = pi->sel_start;
4544 sinfo.end = pi->sel_end;
4545 sinfo.base = fw->base;
4546 sinfo.unencoded = fw->unencoded;
4547 sinfo.reason = FONTGRID_START_SELECTION;
4548 g_signal_emit(G_OBJECT(fw), fontgrid_signals[SELECTION_START], 0,
4552 * And last, since the change of the selection owner caused the
4553 * clipboard to lose its data, add the data to it again so
4554 * it can be pasted in some other font editor.
4556 gdk_property_change(w->window, FONTGRID_CLIPBOARD,
4557 FONTGRID_GLYPHLIST, 8, GDK_PROP_MODE_REPLACE,
4558 data, (gint) nitems);
4560 g_free((char *) data);
4565 fontgrid_update_metrics(Fontgrid *fw, bdf_metrics_t *metrics)
4567 FontgridModificationInfo mi;
4569 g_return_if_fail(fw != 0);
4570 g_return_if_fail(fw->font != 0);
4572 if (bdf_set_font_bbx(fw->font, metrics)) {
4578 * Calculate the cell geometry and the rows and columns.
4580 fontgrid_set_cell_geometry(fw);
4581 fontgrid_set_rows_cols(fw, 0);
4583 gtk_widget_queue_resize(GTK_WIDGET(fw));
4585 mi.reason = FONTGRID_FONT_METRICS_MODIFIED;
4587 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &mi);
4592 fontgrid_update_glyph(Fontgrid *fw, bdf_glyph_t *glyph, gboolean unencoded)
4594 FontgridInternalPageInfo *pi;
4597 FontgridModificationInfo mi;
4599 g_return_if_fail(fw != 0);
4600 g_return_if_fail(fw->font != 0);
4602 gl.bpp = fw->font->bpp;
4603 gl.start = gl.end = glyph->encoding;
4606 memcpy((char *) &gl.bbx, (char *) &glyph->bbx, sizeof(bdf_bbx_t));
4608 if (bdf_replace_glyphs(fw->font, glyph->encoding, &gl, unencoded)) {
4610 * The font geometry was changed by the glyph being pasted.
4611 * A resize will be needed.
4615 * Calculate the cell geometry and the rows and columns.
4617 fontgrid_set_cell_geometry(fw);
4618 fontgrid_set_rows_cols(fw, 0);
4620 gtk_widget_queue_resize(GTK_WIDGET(fw));
4622 mi.reason = FONTGRID_FONT_METRICS_MODIFIED;
4624 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &mi);
4627 * Simply redraw the cells that were modified.
4629 fontgrid_draw_cells(GTK_WIDGET(fw), glyph->encoding, glyph->encoding,
4632 pi = (fw->unencoded) ? &fw->upage : &fw->npage;
4635 if (fw->font->unencoded_used == 0)
4638 gp = fw->font->unencoded + (fw->font->unencoded_used - 1);
4639 pi->maxpage = gp->encoding / fw->pagesize;
4644 if (fw->font->glyphs_used == 0)
4647 gp = fw->font->glyphs + (fw->font->glyphs_used - 1);
4648 pi->maxpage = gp->encoding / fw->pagesize;
4653 mi.reason = FONTGRID_GLYPHS_MODIFIED;
4655 mi.start = mi.end = glyph->encoding;
4656 mi.unencoded = fw->unencoded;
4657 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &mi);
4661 fontgrid_update_psf_mappings(Fontgrid *fw, gint32 encoding,
4662 bdf_psf_unimap_t *mappings)
4664 FontgridModificationInfo mi;
4666 g_return_if_fail(fw != 0);
4667 g_return_if_fail(fw->font != 0);
4669 if (bdf_replace_mappings(fw->font, encoding, mappings, fw->unencoded)) {
4670 mi.reason = FONTGRID_PSF_MAPPINGS_MODIFIED;
4672 mi.start = mi.end = encoding;
4673 mi.unencoded = fw->unencoded;
4674 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &mi);
4679 fontgrid_select_next_glyph(Fontgrid *fw, gint32 code)
4684 FontgridInternalPageInfo *pi;
4685 FontgridSelectionInfo sinfo;
4687 g_return_val_if_fail(fw != NULL, FALSE);
4688 g_return_val_if_fail(IS_FONTGRID(fw), FALSE);
4690 if (!fw->unencoded) {
4692 gp = (fw->font && fw->font->glyphs_used) ?
4693 (fw->font->glyphs + (fw->font->glyphs_used - 1)) : 0;
4696 gp = (fw->font && fw->font->unencoded_used) ?
4697 (fw->font->unencoded + (fw->font->unencoded_used - 1)) : 0;
4700 if ((count = fw->count) == 0)
4704 * Make sure that when on the unencoded pages, the final glyph is
4705 * the limit unlike the encoded pages where the max value is 0xffff.
4707 if ((fw->unencoded &&
4708 (gp == 0 || code == gp->encoding)) ||
4714 if (fw->orientation == GTK_ORIENTATION_VERTICAL)
4715 code += (fw->cell_rows * count);
4719 if (fw->unencoded && code > gp->encoding)
4720 code = gp->encoding;
4721 else if (code > 0xffff)
4724 fontgrid_deselect_all(fw);
4726 pageno = code / fw->pagesize;
4727 if (pageno != pi->pageno) {
4728 fw->no_sel_callback = TRUE;
4729 fontgrid_goto_page(fw, pageno);
4732 pi->sel_start = pi->sel_end = code;
4733 Select(code, pi->selmap);
4734 fontgrid_draw_cells(GTK_WIDGET(fw), code, code, FALSE, TRUE);
4742 * Set up and emit the selection start signal.
4745 gp = fontgrid_locate_glyph(fw->font->glyphs, fw->font->glyphs_used,
4748 gp = fontgrid_locate_glyph(fw->font->unencoded, fw->font->unencoded_used,
4751 empty_glyph.encoding = code;
4755 sinfo.num_glyphs = 1;
4756 sinfo.start = pi->sel_start;
4757 sinfo.end = pi->sel_end;
4758 sinfo.base = fw->base;
4759 sinfo.unencoded = fw->unencoded;
4761 sinfo.reason = FONTGRID_START_SELECTION;
4762 g_signal_emit(G_OBJECT(fw), fontgrid_signals[SELECTION_START], 0,
4768 fontgrid_select_previous_glyph(Fontgrid *fw, gint32 code)
4773 FontgridInternalPageInfo *pi;
4774 FontgridSelectionInfo sinfo;
4776 g_return_val_if_fail(fw != NULL, FALSE);
4777 g_return_val_if_fail(IS_FONTGRID(fw), FALSE);
4779 if (!fw->unencoded) {
4781 gp = (fw->font && fw->font->glyphs_used) ?
4782 (fw->font->glyphs + (fw->font->glyphs_used - 1)) : 0;
4785 gp = (fw->font && fw->font->unencoded_used) ?
4786 (fw->font->unencoded + (fw->font->unencoded_used - 1)) : 0;
4789 if ((count = fw->count) == 0)
4797 if (fw->orientation == GTK_ORIENTATION_VERTICAL)
4798 code -= (fw->cell_rows * count);
4805 fontgrid_deselect_all(fw);
4807 pageno = code / fw->pagesize;
4808 if (pageno != pi->pageno) {
4809 fw->no_sel_callback = TRUE;
4810 fontgrid_goto_page(fw, pageno);
4813 pi->sel_start = pi->sel_end = code;
4814 Select(code, pi->selmap);
4815 fontgrid_draw_cells(GTK_WIDGET(fw), code, code, FALSE, TRUE);
4823 * Set up and emit the selection start signal.
4826 gp = fontgrid_locate_glyph(fw->font->glyphs, fw->font->glyphs_used,
4829 gp = fontgrid_locate_glyph(fw->font->unencoded, fw->font->unencoded_used,
4832 empty_glyph.encoding = code;
4836 sinfo.num_glyphs = 1;
4837 sinfo.start = pi->sel_start;
4838 sinfo.end = pi->sel_end;
4839 sinfo.base = fw->base;
4840 sinfo.unencoded = fw->unencoded;
4842 sinfo.reason = FONTGRID_START_SELECTION;
4843 g_signal_emit(G_OBJECT(fw), fontgrid_signals[SELECTION_START], 0,