1 /*
2 * Copyright 2008 Department of Mathematical Sciences, New Mexico State University
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * DEPARTMENT OF MATHEMATICAL SCIENCES OR NEW MEXICO STATE UNIVERSITY BE
18 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
19 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 */
22
23 #include "fontgrid.h"
24 #include <gdk/gdkkeysyms.h>
25 #include <gtk/gtkselection.h>
26
27 #ifdef HAVE_XLIB
28 #include <gdk/gdkx.h>
29 #endif
30
31 #ifdef ENABLE_NLS
32 #include <libintl.h>
33 #define _(s) dgettext(GETTEXT_PACKAGE,s)
34 #else
35 #define _(s) (s)
36 #endif
37
38 /*
39 * Macros that represent the properties used by this type of object.
40 */
41 #define FONTGRID_CLIPBOARD gdk_atom_intern("FONTGRID_CLIPBOARD", FALSE)
42 #define FONTGRID_GLYPHLIST gdk_atom_intern("FONTGRID_GLYPHLIST", FALSE)
43
44 /*
45 * Set several defaults.
46 */
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
52
53 /*
54 * Enums used for identifying properties.
55 */
56 enum {
57 PROP_0 = 0,
58 PROP_CODE_BASE,
59 PROP_POWER2,
60 PROP_ORIENTATION,
61 PROP_FONT,
62 PROP_POINT_SIZE,
63 PROP_SPACING,
64 PROP_SKIP_BLANKS,
65 PROP_OVERWRITE,
66 PROP_COLORS,
67 PROP_INITIAL_GLYPH,
68 PROP_BPP,
69 PROP_HRES,
70 PROP_VRES
71 };
72
73 /**************************************************************************
74 *
75 * Selection macros for toggling & testing glyph selected state.
76 *
77 **************************************************************************/
78
79 /*
80 * Macros for dealing with the selected state of glyphs in the font grid.
81 */
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)))
85
86 /**************************************************************************
87 *
88 * Signals.
89 *
90 **************************************************************************/
91
92 /*
93 * Enums that represent the signals these objects send out.
94 */
95 enum {
96 SELECTION_START = 0,
97 SELECTION_EXTEND,
98 SELECTION_END,
99 ACTIVATE,
100 MODIFIED,
101 TURN_TO_PAGE
102 };
103
104 static GtkWidgetClass *parent_class = 0;
105 static guint fontgrid_signals[TURN_TO_PAGE + 1];
106
107 static bdf_glyph_t empty_glyph;
108
109 /**************************************************************************
110 *
111 * Digits for displaying the cell encoding.
112 *
113 **************************************************************************/
114
115 /*
116 * Lists of points that describe the encoding digits.
117 */
118 typedef struct {
119 GdkPoint *points;
120 guint npoints;
121 } fontgrid_digit;
122
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}};
125
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},
128 {4, 6}};
129
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}};
133
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}};
137
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},
140 {3, 5}, {3, 6}};
141
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}};
145
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}};
149
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}};
152
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}};
156
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}};
160
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}};
164
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},
168 {3, 6}};
169
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},
172 {3, 6}};
173
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}};
177
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}};
181
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},
184 {0, 5}, {0, 6}};
185 static GdkPoint minus[] = {{1, 3}, {2, 3}, {3, 3}, {4,3}};
186
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)},
205 };
206
207 /*
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.
210 */
211 static GdkPoint encoding_digits[19*6];
212
213 /*
214 * Used to determine spacing between digits when displaying.
215 */
216 #define FONTGRID_DIGIT_WIDTH 6
217 #define FONTGRID_DIGIT_HEIGHT 10
218
219 /*
220 * A macro for getting the current foreground GC.
221 */
222 #define WIDGET_FG_GC(w) ((w)->style->fg_gc[GTK_WIDGET_STATE(w)])
223
224 #define HMARGINS(fw) ((fw)->hmargin << 1)
225 #define VMARGINS(fw) ((fw)->vmargin << 1)
226
227 static void
fontgrid_set_cell_geometry(Fontgrid * fw)228 fontgrid_set_cell_geometry(Fontgrid *fw)
229 {
230 bdf_font_t *font;
231 gint lw;
232
233 font = fw->font;
234
235 lw = FONTGRID_DIGIT_WIDTH * 7;
236
237 /*
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.
240 */
241 fw->label_height = FONTGRID_DIGIT_HEIGHT + 4;
242
243 /*
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.
246 */
247 if (font != 0) {
248 fw->cell_width = font->bbx.width + 6;
249 fw->cell_height = font->bbx.height + 6;
250 } else {
251 /*
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.
254 */
255 fw->cell_width = lw + 6;
256 fw->cell_height = FGRID_DEFAULT_CELL_HEIGHT + 6;
257 }
258
259 fw->cell_width = MAX(fw->cell_width, lw);
260 fw->cell_height = MAX(fw->cell_height, fw->label_height);
261
262 /*
263 * Now add the label size into the picture.
264 */
265 fw->cell_height += fw->label_height - 1;
266 }
267
268 static void
fontgrid_set_rows_cols(Fontgrid * fw,GtkAllocation * core)269 fontgrid_set_rows_cols(Fontgrid *fw, GtkAllocation *core)
270 {
271 gint i;
272 guint16 dw, dh, wd, ht;
273
274 /*
275 * Limit the window size to 7/8 of the actual screen dimensions.
276 */
277 dw = (gdk_screen_width() * 7) >> 3;
278 dh = (gdk_screen_height() * 7) >> 3;
279
280 if (!core) {
281 /*
282 * Adjust the rows and columns based on the preferred geometry.
283 */
284 wd = (fw->cell_width * fw->cell_cols) + HMARGINS(fw);
285 ht = (fw->cell_height * fw->cell_rows) + VMARGINS(fw);
286
287 if (wd > dw)
288 fw->cell_cols = (dw - HMARGINS(fw)) / fw->cell_width;
289
290 if (ht > dh)
291 fw->cell_rows = (dh - VMARGINS(fw)) / fw->cell_height;
292 } else {
293 /*
294 * Adjust the rows and columns based on the current geometry.
295 */
296 fw->cell_cols = (core->width - HMARGINS(fw)) / fw->cell_width;
297 fw->cell_rows = (core->height - VMARGINS(fw)) / fw->cell_height;
298 }
299
300 /*
301 * Adjust rows and columns to powers of two if necessary.
302 */
303 if (fw->power2) {
304 /*
305 * Make sure the columns are a power of 2.
306 */
307 for (i = 15; i >= 0; i--) {
308 if (fw->cell_cols & (1 << i)) {
309 fw->cell_cols = 1 << i;
310 break;
311 }
312 }
313
314 /*
315 * Make sure the rows are a power of 2.
316 */
317 for (i = 15; i >= 0; i--) {
318 if (fw->cell_rows & (1 << i)) {
319 fw->cell_rows = 1 << i;
320 break;
321 }
322 }
323 }
324
325 /*
326 * Fall back to a minimum of two rows.
327 */
328 if (fw->cell_rows == 0)
329 fw->cell_rows = 2;
330
331 /*
332 * Fall back to a minimum of two columns.
333 */
334 if (fw->cell_cols == 0)
335 fw->cell_cols = 2;
336
337 /*
338 * Make sure the number of rows and cols are within the max limits.
339 */
340 if (fw->cell_cols > FGRID_MAX_COLS)
341 fw->cell_cols = FGRID_MAX_COLS;
342
343 if (fw->cell_rows > FGRID_MAX_ROWS)
344 fw->cell_rows = FGRID_MAX_ROWS;
345
346 /*
347 * Set the new page size based on the calculated rows and columns.
348 */
349 fw->pagesize = fw->cell_rows * fw->cell_cols;
350 }
351
352 /**************************************************************************
353 *
354 * GObjectClass functions.
355 *
356 **************************************************************************/
357
358 static void
fontgrid_set_property(GObject * obj,guint prop_id,const GValue * value,GParamSpec * pspec)359 fontgrid_set_property(GObject *obj, guint prop_id, const GValue *value,
360 GParamSpec *pspec)
361 {
362 GtkWidget *widget;
363 Fontgrid *fw;
364
365 widget = GTK_WIDGET(obj);
366 fw = FONTGRID(obj);
367
368 switch (prop_id) {
369 case PROP_CODE_BASE:
370 fw->base = g_value_get_uint(value);
371 /*
372 * Force the encodings to be redisplayed here?
373 */
374 break;
375 case PROP_POWER2:
376 fw->power2 = g_value_get_boolean(value);
377 break;
378 case PROP_ORIENTATION:
379 fontgrid_set_orientation(fw, g_value_get_enum(value));
380 break;
381 case PROP_FONT:
382 /*
383 * Need to set the rows and columns back to their defaults when
384 * a new font is passed in case it is NULL.
385 */
386 fw->font = (bdf_font_t *) g_value_get_pointer(value);
387
388 fontgrid_set_cell_geometry(fw);
389 fontgrid_set_rows_cols(fw, 0);
390 break;
391 case PROP_POINT_SIZE:
392 fw->point_size = g_value_get_uint(value);
393 break;
394 case PROP_SPACING:
395 fw->spacing = g_value_get_int(value);
396 break;
397 case PROP_SKIP_BLANKS:
398 fw->noblanks = g_value_get_boolean(value);
399 break;
400 case PROP_OVERWRITE:
401 fw->overwrite = g_value_get_boolean(value);
402 break;
403 case PROP_COLORS:
404 fw->colors = (guint16 *) g_value_get_pointer(value);
405 break;
406 case PROP_INITIAL_GLYPH:
407 fw->initial_glyph = g_value_get_int(value);
408 break;
409 case PROP_BPP:
410 fw->bpp = g_value_get_int(value);
411 break;
412 case PROP_HRES:
413 fw->hres = g_value_get_int(value);
414 break;
415 case PROP_VRES:
416 fw->vres = g_value_get_int(value);
417 break;
418 }
419 }
420
421 static void
fontgrid_get_property(GObject * obj,guint prop_id,GValue * value,GParamSpec * pspec)422 fontgrid_get_property(GObject *obj, guint prop_id, GValue *value,
423 GParamSpec *pspec)
424 {
425 Fontgrid *f;
426
427 f = FONTGRID(obj);
428
429 switch (prop_id) {
430 case PROP_CODE_BASE:
431 g_value_set_uint(value, f->base);
432 break;
433 case PROP_POWER2:
434 g_value_set_boolean(value, f->power2);
435 break;
436 case PROP_ORIENTATION:
437 g_value_set_enum(value, f->orientation);
438 break;
439 case PROP_FONT:
440 g_value_set_pointer(value, f->font);
441 break;
442 case PROP_POINT_SIZE:
443 g_value_set_uint(value, f->point_size);
444 break;
445 case PROP_SPACING:
446 g_value_set_int(value, f->spacing);
447 break;
448 case PROP_SKIP_BLANKS:
449 g_value_set_boolean(value, f->noblanks);
450 break;
451 case PROP_COLORS:
452 g_value_set_pointer(value, f->colors);
453 break;
454 case PROP_INITIAL_GLYPH:
455 g_value_set_int(value, f->initial_glyph);
456 break;
457 case PROP_BPP:
458 g_value_set_int(value, f->bpp);
459 break;
460 case PROP_HRES:
461 g_value_set_int(value, f->hres);
462 break;
463 case PROP_VRES:
464 g_value_set_int(value, f->vres);
465 break;
466 }
467 }
468
469 /**************************************************************************
470 *
471 * GtkObjectClass functions.
472 *
473 **************************************************************************/
474
475 static void
fontgrid_destroy(GtkObject * obj)476 fontgrid_destroy(GtkObject *obj)
477 {
478 Fontgrid *f;
479 guint32 i;
480 bdf_glyphlist_t *gl;
481
482 /*
483 * Do some checks to make sure the incoming object exists and is the right
484 * kind.
485 */
486 g_return_if_fail(obj != 0);
487 g_return_if_fail(IS_FONTGRID(obj));
488
489 f = FONTGRID(obj);
490
491 /*
492 * Clean up this object instance.
493 */
494 if (f->font)
495 bdf_free_font(f->font);
496 f->font = 0;
497
498 if (f->xor_gc != 0)
499 g_object_unref(G_OBJECT(f->xor_gc));
500 f->xor_gc = 0;
501
502 if (f->points_size > 0)
503 g_free(f->points);
504 f->points_size = f->points_used = 0;
505
506 if (f->rgb_size > 0)
507 g_free(f->rgb);
508 f->rgb_used = f->rgb_size = 0;
509
510 /*
511 * Remove all ownership of selections.
512 */
513 gtk_selection_remove_all(GTK_WIDGET(obj));
514
515 /*
516 * Free up the clipboard contents if there are any.
517 */
518 gl = &f->clipboard;
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);
524 }
525 if (gl->glyphs_size > 0)
526 free((char *) gl->glyphs);
527 gl->glyphs_size = gl->glyphs_used = 0;
528
529 /*
530 * Follow the class chain back up to free up resources allocated in the
531 * parent classes.
532 */
533 GTK_OBJECT_CLASS(parent_class)->destroy(obj);
534 }
535
536 static void
fontgrid_finalize(GObject * obj)537 fontgrid_finalize(GObject *obj)
538 {
539 /*
540 * Do some checks to make sure the incoming object exists and is the right
541 * kind.
542 */
543 g_return_if_fail(obj != 0);
544 g_return_if_fail(IS_FONTGRID(obj));
545
546 /*
547 * Follow the class chain back up to free up resources allocated in the
548 * parent classes.
549 */
550 G_OBJECT_CLASS(parent_class)->finalize(obj);
551 }
552
553 /**************************************************************************
554 *
555 * GtkWidgetClass functions.
556 *
557 **************************************************************************/
558
559 static void
fontgrid_preferred_size(GtkWidget * widget,GtkRequisition * preferred)560 fontgrid_preferred_size(GtkWidget *widget, GtkRequisition *preferred)
561 {
562 Fontgrid *fw;
563
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);
567 }
568
569 static void
fontgrid_actual_size(GtkWidget * widget,GtkAllocation * actual)570 fontgrid_actual_size(GtkWidget *widget, GtkAllocation *actual)
571 {
572 Fontgrid *fw;
573
574 fw = FONTGRID(widget);
575
576 widget->allocation = *actual;
577
578 /*
579 * Make sure the rows and columns are adjusted to fit the actual allocated
580 * size.
581 */
582 fontgrid_set_rows_cols(fw, actual);
583
584 if (GTK_WIDGET_REALIZED(widget))
585 gdk_window_move_resize(widget->window, actual->x, actual->y,
586 actual->width, actual->height);
587 }
588
589 static void
fontgrid_realize(GtkWidget * widget)590 fontgrid_realize(GtkWidget *widget)
591 {
592 Fontgrid *fw;
593 GdkWindowAttr attributes;
594 GdkGCValues values;
595 gint attributes_mask;
596
597 g_return_if_fail(widget != NULL);
598 g_return_if_fail(IS_FONTGRID(widget));
599
600 fw = FONTGRID(widget);
601 GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED);
602
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);
618
619 attributes_mask = GDK_WA_X|GDK_WA_Y|GDK_WA_VISUAL|GDK_WA_COLORMAP;
620
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);
624
625 widget->style = gtk_style_attach(widget->style, widget->window);
626 gtk_style_set_background(widget->style, widget->window, GTK_STATE_NORMAL);
627
628 if (fw->xor_gc != 0)
629 g_object_unref(G_OBJECT(fw->xor_gc));
630
631 /*
632 * Create the GC used to display selected cells.
633 */
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,
640 GDK_GC_FOREGROUND|
641 GDK_GC_BACKGROUND|GDK_GC_FUNCTION);
642 }
643
644 static bdf_glyph_t *
fontgrid_locate_glyph(bdf_glyph_t * glyphs,guint32 nglyphs,gint32 code,gboolean exact_match)645 fontgrid_locate_glyph(bdf_glyph_t *glyphs, guint32 nglyphs, gint32 code,
646 gboolean exact_match)
647 {
648 gint32 l, r, m = 0;
649
650 if (code < 0 || glyphs == 0 || nglyphs == 0)
651 return 0;
652
653 for (l = 0, r = (gint32) (nglyphs - 1); l <= r; ) {
654 m = (l + r) >> 1;
655 if (glyphs[m].encoding < code)
656 l = m + 1;
657 else if (glyphs[m].encoding > code)
658 r = m - 1;
659 else {
660 if (exact_match)
661 return glyphs + m;
662 break;
663 }
664 }
665
666 if (exact_match)
667 return 0;
668
669 /*
670 * Adjust to the beginning or end if nothing was found in the search.
671 */
672 while (m > 0 && glyphs[m].encoding > code)
673 m--;
674 while (m < (gint32) nglyphs && glyphs[m].encoding < code)
675 m++;
676
677 return (m < (gint32) nglyphs) ? glyphs + m : 0;
678 }
679
680 static void
fontgrid_get_glyph_points(Fontgrid * fw,gint x,gint y,gint rx,gint by,bdf_glyph_t * glyph)681 fontgrid_get_glyph_points(Fontgrid *fw, gint x, gint y, gint rx, gint by,
682 bdf_glyph_t *glyph)
683 {
684 gint i, j, bpr, col;
685 unsigned char *bmap, *masks = 0;
686
687 switch (fw->bpp) {
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;
692 }
693
694 fw->points_used = 0;
695 bmap = glyph->bitmap;
696 bpr = ((glyph->bbx.width * fw->bpp) + 7) >> 3;
697
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)
705 fw->points =
706 (GdkPoint *) g_malloc(sizeof(GdkPoint) << 7);
707 else
708 fw->points =
709 (GdkPoint *) g_realloc(fw->points,
710 sizeof(GdkPoint) *
711 (fw->points_size + 128));
712 fw->points_size += 128;
713 }
714
715 fw->points[fw->points_used].x = j + x;
716 fw->points[fw->points_used].y = i + y - glyph->bbx.ascent;
717 fw->points_used++;
718 }
719 }
720 }
721 }
722
723 #if 0
724 static void
725 fontgrid_get_glyph_points_color(Fontgrid *fw, gint x, gint y, gint rx, gint by,
726 gint color_index, bdf_glyph_t *glyph)
727 {
728 gint i, j, bpr, col, byte, di = 0, si, cidx = 0;
729 unsigned char *bmap, *masks = 0;
730
731 switch (fw->bpp) {
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;
736 }
737
738 fw->points_used = 0;
739 bmap = glyph->bitmap;
740 bpr = ((glyph->bbx.width * fw->bpp) + 7) >> 3;
741
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];
747 if (byte) {
748 /*
749 * Check to see if the byte matches the color index being
750 * collected.
751 */
752 if (di > si)
753 byte >>= (di - si) * fw->bpp;
754
755 if (byte == cidx) {
756 if (fw->points_used == fw->points_size) {
757 if (fw->points_size == 0)
758 fw->points = (GdkPoint *)
759 g_malloc(sizeof(GdkPoint) << 6);
760 else
761 fw->points = (GdkPoint *)
762 g_realloc(fw->points, sizeof(GdkPoint) *
763 (fw->points_size + 64));
764 fw->points_size += 64;
765 }
766
767 fw->points[fw->points_used].x = j + x;
768 fw->points[fw->points_used].y = i + y - glyph->bbx.ascent;
769 fw->points_used++;
770 }
771 }
772 }
773 }
774 }
775 #endif
776
777 /*
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.
781 */
782 static void
fontgrid_make_rgb_image(Fontgrid * fw,bdf_glyph_t * glyph)783 fontgrid_make_rgb_image(Fontgrid *fw, bdf_glyph_t *glyph)
784 {
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;
788
789 /*
790 * Figure out the background color.
791 */
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;
795
796 switch (fw->bpp) {
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;
801 }
802
803 bmap = glyph->bitmap;
804 bpr = ((glyph->bbx.width * fw->bpp) + 7) >> 3;
805
806 rgb_bpr = glyph->bbx.width * 3;
807 fw->rgb_used = rgb_bpr * glyph->bbx.height;
808
809 if (fw->rgb_size < fw->rgb_used) {
810 if (fw->rgb_size == 0)
811 fw->rgb = g_malloc(fw->rgb_used);
812 else
813 fw->rgb = g_realloc(fw->rgb, fw->rgb_used);
814 fw->rgb_size = fw->rgb_used;
815 }
816
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;
820
821 byte = bmap[(y * bpr) + (col >> 3)] & masks[si];
822 if (di > si)
823 byte >>= (di - si) * fw->bpp;
824 if (byte) {
825 /*
826 * Look up the color.
827 */
828 switch (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;
833 }
834 } else
835 /*
836 * Set the pixel to the background color.
837 */
838 memcpy(pix, bg, 3);
839
840 memcpy(&fw->rgb[(y * rgb_bpr) + (x * 3)], pix, 3);
841 }
842 }
843 }
844
845 static void
fontgrid_draw_encoding(GtkWidget * w,GdkGC * gc,gint x,gint y,gchar * num,gint numlen)846 fontgrid_draw_encoding(GtkWidget *w, GdkGC *gc, gint x, gint y, gchar *num,
847 gint numlen)
848 {
849 gint i, j, d;
850 GdkPoint *dp;
851
852 if (!GTK_WIDGET_REALIZED(w))
853 return;
854
855 dp = encoding_digits;
856 for (i = 0; i < numlen; i++) {
857 if (num[i] == '-')
858 d = 16;
859 else if (num[i] <= '9')
860 d = num[i] - '0';
861 else
862 d = (num[i] - 'A') + 10;
863
864 /*
865 * Copy the next digit into the display array.
866 */
867 (void) memcpy((char *) dp, (char *) digits[d].points,
868 sizeof(GdkPoint) * digits[d].npoints);
869 /*
870 * Position the points.
871 */
872 for (j = 0; j < digits[d].npoints; j++) {
873 dp[j].x += x;
874 dp[j].y += y;
875 }
876 dp += digits[d].npoints;
877 x += 6;
878 }
879
880 /*
881 * Draw the points.
882 */
883 gdk_draw_points(w->window, gc, encoding_digits, dp - encoding_digits);
884 }
885
886 static void
fontgrid_draw_cells(GtkWidget * widget,gint32 start,gint32 end,gboolean labels,gboolean glyphs)887 fontgrid_draw_cells(GtkWidget *widget, gint32 start, gint32 end,
888 gboolean labels, gboolean glyphs)
889 {
890 Fontgrid *fw;
891 gint x, y, wd, as, ds, len, lx, ly;
892 gint32 i, n, r, c;
893 guint32 nglyphs, ng;
894 gboolean mod;
895 bdf_font_t *font;
896 bdf_glyph_t *glyph, *gp;
897 FontgridInternalPageInfo *pi;
898 GdkGC *gc;
899 GdkRectangle rect;
900 gchar nbuf[16];
901
902 if (!GTK_WIDGET_REALIZED(widget) || (labels == FALSE && glyphs == FALSE))
903 return;
904
905 fw = FONTGRID(widget);
906
907 font = fw->font;
908
909 glyph = 0;
910 nglyphs = 0;
911
912 if (!fw->unencoded) {
913 pi = &fw->npage;
914 if (font) {
915 glyph = font->glyphs;
916 nglyphs = font->glyphs_used;
917 }
918 } else {
919 /*
920 * When viewing the unencoded glyph pages, all glyphs are labelled
921 * with an encoding of -1.
922 */
923 strcpy(nbuf, "-1");
924
925 pi = &fw->upage;
926 if (font) {
927 glyph = font->unencoded;
928 nglyphs = font->unencoded_used;
929 }
930 }
931
932 /*
933 * The initial code to work from.
934 */
935 n = pi->bcode;
936
937 /*
938 * Locate the glyph closest to the starting code.
939 */
940 if ((glyph = fontgrid_locate_glyph(glyph, nglyphs, start, FALSE)) == 0)
941 nglyphs = 0;
942
943 gp = glyph;
944
945 gc = widget->style->fg_gc[GTK_WIDGET_STATE(widget)];
946
947 for (ng = 0, i = start; i <= end; i++) {
948 /*
949 * Only draw those cells that are on the current page.
950 */
951 if (i < pi->bcode || i >= pi->bcode + fw->pagesize)
952 continue;
953
954 if (fw->orientation == GTK_ORIENTATION_HORIZONTAL) {
955 r = (i - n) / fw->cell_cols;
956 c = (i - n) % fw->cell_cols;
957 } else {
958 c = (i - n) / fw->cell_rows;
959 r = (i - n) % fw->cell_rows;
960 }
961
962 x = fw->xoff + (c * fw->cell_width);
963 y = fw->yoff + (r * fw->cell_height);
964
965 if (labels) {
966 if (!fw->unencoded) {
967 switch (fw->base) {
968 case 8: sprintf(nbuf, "%o", i); break;
969 case 10: sprintf(nbuf, "%d", i); break;
970 case 16: sprintf(nbuf, "%X", i); break;
971 }
972 }
973 rect.x = x + 1;
974 rect.y = y + 1;
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);
979
980 len = strlen(nbuf);
981 wd = len * 6;
982 as = 8;
983 ds = 0;
984
985 lx = (x + ((fw->cell_width >> 1) - (wd >> 1))) + 1;
986 ly = (y + ((fw->label_height >> 1) - ((as + ds) >> 1))) + 1;
987
988 mod = FALSE;
989 if (i <= 0xffff)
990 mod = (!fw->unencoded) ? bdf_glyph_modified(font, i, 0) :
991 bdf_glyph_modified(font, i, 1);
992
993 gdk_window_clear_area(widget->window, rect.x + 1, rect.y + 1,
994 rect.width - 1, rect.height - 1);
995
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) {
1002 ng++;
1003 gp++;
1004 if (ng == nglyphs)
1005 gp = 0;
1006 }
1007 } else {
1008 /*
1009 * If the glyph exists, then darken the rectangle to indicate
1010 * this.
1011 */
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);
1016 ng++;
1017 gp++;
1018 if (ng == nglyphs)
1019 gp = 0;
1020 }
1021 fontgrid_draw_encoding(widget, gc, lx, ly, nbuf, len);
1022 }
1023 }
1024
1025 if (glyphs) {
1026 rect.x = x + 1;
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;
1030
1031 if (i <= 0xffff && nglyphs > 0 && glyph->encoding == i) {
1032 /*
1033 * Draw the glyph.
1034 */
1035
1036 /*
1037 * Set the right and left limits for generating points.
1038 */
1039 lx = x + fw->cell_width - 2;
1040 ly = y + fw->cell_height - 2;
1041
1042 /*
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.
1046 */
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;
1050
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);
1060 }
1061 } else {
1062 /*
1063 * The glyph is not selected, so draw it according to
1064 * the bytes-per-pixel of the font.
1065 */
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,
1072 glyph->bbx.width,
1073 glyph->bbx.height,
1074 GDK_RGB_DITHER_NONE,
1075 fw->rgb, glyph->bbx.width * 3);
1076 }
1077 }
1078 glyph++;
1079 if (ng == nglyphs) {
1080 nglyphs = 0;
1081 glyph = 0;
1082 }
1083 } else {
1084 /*
1085 * Clear the empty cell.
1086 */
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);
1091 else {
1092 gdk_window_clear_area(widget->window, rect.x, rect.y,
1093 rect.width, rect.height);
1094 if (i > 0xffff) {
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);
1101 }
1102 }
1103 }
1104 }
1105 }
1106 }
1107
1108 static void
fontgrid_draw(GtkWidget * widget,GdkRegion * region)1109 fontgrid_draw(GtkWidget *widget, GdkRegion *region)
1110 {
1111 Fontgrid *fw;
1112 gint x, y, i;
1113 guint16 wd, ht, gw, gh;
1114 gint32 start, end;
1115 GdkGC *gc;
1116
1117 g_return_if_fail(widget != NULL);
1118 g_return_if_fail(IS_FONTGRID(widget));
1119
1120 fw = FONTGRID(widget);
1121
1122 gc = widget->style->fg_gc[GTK_WIDGET_STATE(widget)];
1123
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;
1130
1131 /*
1132 * Draw the horizontal lines.
1133 */
1134 for (i = 0; i <= fw->cell_rows; i++) {
1135 gdk_draw_line(widget->window, gc, x, y, x + gw, y);
1136
1137 /*
1138 * Only draw the second line if this is not the last line.
1139 */
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);
1143
1144 y += fw->cell_height;
1145 }
1146
1147 /*
1148 * Draw the vertical lines.
1149 */
1150 x = fw->xoff;
1151 y = fw->yoff;
1152
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;
1156 }
1157
1158 start = (!fw->unencoded) ? fw->npage.bcode : fw->upage.bcode;
1159 end = start + (gint32) (fw->pagesize - 1);
1160
1161 fontgrid_draw_cells(widget, start, end, TRUE, TRUE);
1162 }
1163
1164 static void
fontgrid_select_range(Fontgrid * fw,gint32 start,gint32 end)1165 fontgrid_select_range(Fontgrid *fw, gint32 start, gint32 end)
1166 {
1167 gint32 i, tmp;
1168 FontgridInternalPageInfo *pi;
1169
1170 if (start > end) {
1171 tmp = start;
1172 start = end;
1173 end = tmp;
1174 }
1175
1176 pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
1177
1178 for (i = start; i <= end; i++)
1179 Select(i, pi->selmap);
1180
1181 /*
1182 * Adjust the start and end values to the current page to determine which
1183 * cells need to be redrawn.
1184 */
1185 tmp = pi->bcode + (fw->pagesize - 1);
1186 if (start >= tmp || end < pi->bcode)
1187 return;
1188
1189 if (start < pi->bcode)
1190 start = pi->bcode;
1191 if (end > tmp)
1192 end = tmp;
1193 fontgrid_draw_cells(GTK_WIDGET(fw), start, end, FALSE, TRUE);
1194 }
1195
1196 static void
fontgrid_deselect_range(Fontgrid * fw,gint32 start,gint32 end)1197 fontgrid_deselect_range(Fontgrid *fw, gint32 start, gint32 end)
1198 {
1199 gint32 i, tmp;
1200 FontgridInternalPageInfo *pi;
1201
1202 if (start > end) {
1203 tmp = start;
1204 start = end;
1205 end = tmp;
1206 }
1207
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);
1214 }
1215 }
1216 }
1217
1218 static void
fontgrid_deselect_all(Fontgrid * fw)1219 fontgrid_deselect_all(Fontgrid *fw)
1220 {
1221 FontgridInternalPageInfo *pi, *opi;
1222
1223 if (!fw->unencoded) {
1224 pi = &fw->npage;
1225 opi = &fw->upage;
1226 } else {
1227 pi = &fw->upage;
1228 opi = &fw->npage;
1229 }
1230
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);
1235
1236 /*
1237 * Now clear the selected bitmaps.
1238 */
1239 (void) memset((char *) pi->selmap, 0, sizeof(guint32) * 2048);
1240 (void) memset((char *) opi->selmap, 0, sizeof(guint32) * 2048);
1241
1242 /*
1243 * Reset the selection start and end points.
1244 */
1245 pi->sel_start = pi->sel_end = opi->sel_start = opi->sel_end = -1;
1246 }
1247
1248 static void
fontgrid_draw_focus(GtkWidget * widget,GdkRectangle * area)1249 fontgrid_draw_focus(GtkWidget *widget, GdkRectangle *area)
1250 {
1251 GdkGC *gc;
1252 gint x, y, wd, ht, fwidth, fpad;
1253
1254 /*
1255 * Do something with this later to make sure the focus line width
1256 * is set in the GC's.
1257 */
1258 gtk_widget_style_get(widget,
1259 "focus-line-width", &fwidth,
1260 "focus-padding", &fpad, NULL);
1261
1262 gc = widget->style->bg_gc[GTK_WIDGET_STATE(widget)];
1263
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));
1268
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);
1272 else {
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);
1276 }
1277 }
1278
1279 static gint
fontgrid_expose(GtkWidget * widget,GdkEventExpose * event)1280 fontgrid_expose(GtkWidget *widget, GdkEventExpose *event)
1281 {
1282 /*
1283 * Paint the shadow first.
1284 */
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",
1289 0, 0,
1290 widget->allocation.width,
1291 widget->allocation.height);
1292
1293 fontgrid_draw(widget, event->region);
1294
1295 fontgrid_draw_focus(widget, &event->area);
1296
1297 return FALSE;
1298 }
1299
1300 static gint
fontgrid_focus_in(GtkWidget * widget,GdkEventFocus * event)1301 fontgrid_focus_in(GtkWidget *widget, GdkEventFocus *event)
1302 {
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);
1306
1307 GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_FOCUS);
1308 fontgrid_draw_focus(widget, 0);
1309
1310 return FALSE;
1311 }
1312
1313 static gint
fontgrid_focus_out(GtkWidget * widget,GdkEventFocus * event)1314 fontgrid_focus_out(GtkWidget *widget, GdkEventFocus *event)
1315 {
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);
1319
1320 GTK_WIDGET_UNSET_FLAGS(widget, GTK_HAS_FOCUS);
1321 fontgrid_draw_focus(widget, 0);
1322
1323 return FALSE;
1324 }
1325
1326 static gint
fontgrid_lose_selection(GtkWidget * widget,GdkEventSelection * event)1327 fontgrid_lose_selection(GtkWidget *widget, GdkEventSelection *event)
1328 {
1329 Fontgrid *fw;
1330 FontgridInternalPageInfo *pi;
1331 gint32 code;
1332
1333 fw = FONTGRID(widget);
1334
1335 pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
1336
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);
1343 }
1344
1345 return TRUE;
1346 }
1347
1348 /**************************************************************************
1349 *
1350 * Paging routines.
1351 *
1352 **************************************************************************/
1353
1354 static void
fontgrid_neighbor_pages(Fontgrid * fw,gint32 page,gint32 * prev,gint32 * next)1355 fontgrid_neighbor_pages(Fontgrid *fw, gint32 page, gint32 *prev, gint32 *next)
1356 {
1357 gint32 bcode, l, r, m;
1358 guint32 nglyphs;
1359 bdf_glyph_t *glyphs;
1360 FontgridInternalPageInfo *pip;
1361
1362 pip = (!fw->unencoded) ? &fw->npage : &fw->upage;
1363
1364 if (fw->noblanks == FALSE ||
1365 (fw->unencoded == FALSE &&
1366 (fw->font == 0 || fw->font->glyphs_used == 0))) {
1367 *prev = page - 1;
1368 *next = (page < pip->maxpage) ? page + 1 : -1;
1369 return;
1370 }
1371
1372 bcode = page * fw->pagesize;
1373
1374 if (!fw->unencoded) {
1375 glyphs = fw->font->glyphs;
1376 nglyphs = fw->font->glyphs_used;
1377 } else {
1378 glyphs = fw->font->unencoded;
1379 nglyphs = fw->font->unencoded_used;
1380 }
1381
1382 /*
1383 * Do a binary search to find the the preceding page number.
1384 */
1385 for (l = m = 0, r = nglyphs - 1; l < r; ) {
1386 m = (l + r) >> 1;
1387 if (glyphs[m].encoding < bcode)
1388 l = m + 1;
1389 else if (glyphs[m].encoding > bcode)
1390 r = m - 1;
1391 else {
1392 /*
1393 * Exact match.
1394 */
1395 l = r = m - 1;
1396 break;
1397 }
1398 }
1399
1400 /*
1401 * In case the search ends on a code in the specified page.
1402 */
1403 while (r >= 0 && glyphs[r].encoding >= bcode)
1404 r--;
1405
1406 /*
1407 * Set the previous page code.
1408 */
1409 *prev = (r >= 0) ? glyphs[r].encoding / fw->pagesize : -1;
1410
1411 /*
1412 * Determine the following page code.
1413 */
1414 if (r < 0)
1415 r = 0;
1416 while (r < nglyphs && glyphs[r].encoding < bcode + fw->pagesize)
1417 r++;
1418
1419 *next = (r < nglyphs) ? glyphs[r].encoding / fw->pagesize : -1;
1420 }
1421
1422 /**************************************************************************
1423 *
1424 * Selection routines.
1425 *
1426 **************************************************************************/
1427
1428 static void
start_selection(GtkWidget * widget,GdkEventButton * event)1429 start_selection(GtkWidget *widget, GdkEventButton *event)
1430 {
1431 Fontgrid *fw;
1432 gint16 x, y, row, col;
1433 gint32 code;
1434 bdf_glyph_t *gp;
1435 FontgridInternalPageInfo *pi, *opi;
1436 FontgridSelectionInfo sinfo;
1437
1438 fw = FONTGRID(widget);
1439
1440 /*
1441 * Deal with the focus issue first.
1442 */
1443 if (!GTK_WIDGET_HAS_FOCUS(widget)) {
1444 GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_FOCUS);
1445 (void) fontgrid_draw_focus(widget, NULL);
1446 }
1447
1448 x = (gint16) event->x;
1449 y = (gint16) event->y;
1450
1451 col = fw->xoff + (fw->cell_width * fw->cell_cols);
1452 row = fw->yoff + (fw->cell_height * fw->cell_rows);
1453
1454 /*
1455 * If the button press is not in the font grid proper, just return.
1456 */
1457 if (x < fw->xoff || x >= col || y < fw->yoff || y >= row)
1458 return;
1459
1460 /*
1461 * Calculate the row and column that was clicked.
1462 */
1463 row = (y - fw->yoff) / fw->cell_height;
1464 col = (x - fw->xoff) / fw->cell_width;
1465
1466 if (!fw->unencoded) {
1467 pi = &fw->npage;
1468 opi = &fw->upage;
1469 } else {
1470 pi = &fw->upage;
1471 opi = &fw->npage;
1472 }
1473
1474 if (fw->orientation == GTK_ORIENTATION_HORIZONTAL)
1475 code = pi->bcode + (row * fw->cell_cols) + col;
1476 else
1477 code = pi->bcode + (col * fw->cell_rows) + row;
1478
1479 /*
1480 * Any code greater than the maximum is ignored.
1481 */
1482 if (code > 0xffff)
1483 return;
1484
1485 gp = 0;
1486 if (fw->font) {
1487 if (!fw->unencoded)
1488 gp = fontgrid_locate_glyph(fw->font->glyphs, fw->font->glyphs_used,
1489 code, TRUE);
1490 else
1491 gp = fontgrid_locate_glyph(fw->font->unencoded,
1492 fw->font->unencoded_used,
1493 code, TRUE);
1494 }
1495
1496 if (gp == 0) {
1497 empty_glyph.encoding = code;
1498 gp = &empty_glyph;
1499 }
1500
1501 if (code != pi->sel_start || code != pi->sel_end) {
1502 /*
1503 * Clear any existing selection.
1504 */
1505 if (pi->sel_start != -1 || pi->sel_end != -1 ||
1506 opi->sel_start != -1 || opi->sel_end != -1)
1507 fontgrid_deselect_all(fw);
1508
1509 Select(code, pi->selmap);
1510
1511 fontgrid_draw_cells(widget, code, code, FALSE, TRUE);
1512
1513 pi->sel_start = pi->sel_end = code;
1514
1515 /*
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
1518 * called.
1519 */
1520 fw->last_click = 0;
1521 }
1522
1523 sinfo.glyphs = gp;
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,
1533 &sinfo);
1534 } else if (event->type == GDK_2BUTTON_PRESS) {
1535 sinfo.reason = FONTGRID_ACTIVATE;
1536 g_signal_emit(G_OBJECT(fw), fontgrid_signals[ACTIVATE], 0,
1537 &sinfo);
1538 }
1539 fw->last_click = event->time;
1540 }
1541
1542 static void
extend_selection(GtkWidget * widget,gint16 x,gint16 y)1543 extend_selection(GtkWidget *widget, gint16 x, gint16 y)
1544 {
1545 Fontgrid *fw;
1546 gint16 row, col;
1547 gint32 code;
1548 bdf_glyph_t *gp;
1549 gboolean call_extend;
1550 FontgridInternalPageInfo *pi;
1551 FontgridSelectionInfo sinfo;
1552
1553 fw = FONTGRID(widget);
1554
1555 /*
1556 * Deal with the focus issue first.
1557 */
1558 if (!GTK_WIDGET_HAS_FOCUS(widget)) {
1559 GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_FOCUS);
1560 (void) fontgrid_draw_focus(widget, NULL);
1561 }
1562
1563 col = fw->xoff + (fw->cell_width * fw->cell_cols);
1564 row = fw->yoff + (fw->cell_height * fw->cell_rows);
1565
1566 /*
1567 * If the button press is not in the font grid proper, just return.
1568 */
1569 if (x < fw->xoff || x >= col || y < fw->yoff || y >= row)
1570 return;
1571
1572 /*
1573 * Calculate the row and column that was clicked.
1574 */
1575 row = (y - fw->yoff) / fw->cell_height;
1576 col = (x - fw->xoff) / fw->cell_width;
1577
1578 pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
1579
1580 if (fw->orientation == GTK_ORIENTATION_HORIZONTAL)
1581 code = pi->bcode + (row * fw->cell_cols) + col;
1582 else
1583 code = pi->bcode + (col * fw->cell_rows) + row;
1584
1585 /*
1586 * Any code greater than the maximum is ignored.
1587 */
1588 if (code > 0xffff)
1589 return;
1590
1591 gp = 0;
1592 if (fw->font) {
1593 if (!fw->unencoded)
1594 gp = fontgrid_locate_glyph(fw->font->glyphs, fw->font->glyphs_used,
1595 code, TRUE);
1596 else
1597 gp = fontgrid_locate_glyph(fw->font->unencoded,
1598 fw->font->unencoded_used,
1599 code, TRUE);
1600 if (gp == 0) {
1601 empty_glyph.encoding = code;
1602 gp = &empty_glyph;
1603 }
1604 }
1605
1606 call_extend = FALSE;
1607 if (code > pi->sel_end) {
1608 call_extend = TRUE;
1609 if (code <= pi->sel_start)
1610 fontgrid_deselect_range(fw, pi->sel_end, code - 1);
1611 else {
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);
1615 } else
1616 fontgrid_select_range(fw, pi->sel_end, code);
1617 }
1618 } else if (code < pi->sel_end) {
1619 call_extend = TRUE;
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);
1624 } else
1625 fontgrid_select_range(fw, code, pi->sel_end);
1626 } else
1627 fontgrid_deselect_range(fw, code + 1, pi->sel_end);
1628 }
1629
1630 pi->sel_end = code;
1631
1632 if (call_extend == TRUE) {
1633 if (pi->sel_start == pi->sel_end) {
1634 sinfo.glyphs = gp;
1635 sinfo.num_glyphs = 1;
1636 } else {
1637 sinfo.glyphs = 0;
1638 sinfo.num_glyphs = 0;
1639 }
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,
1646 &sinfo);
1647 }
1648 }
1649
1650 static void
end_selection(GtkWidget * widget,GdkEventButton * event)1651 end_selection(GtkWidget *widget, GdkEventButton *event)
1652 {
1653 Fontgrid *fw;
1654 bdf_glyph_t *gp;
1655 FontgridInternalPageInfo *pi;
1656 FontgridSelectionInfo sinfo;
1657
1658 fw = FONTGRID(widget);
1659
1660 pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
1661
1662 if (pi->sel_start != pi->sel_end) {
1663 /*
1664 * Assert ownership of the clipboard if there is a selection of
1665 * more than one glyph.
1666 */
1667 gdk_selection_owner_set(widget->window, FONTGRID_CLIPBOARD,
1668 GDK_CURRENT_TIME, FALSE);
1669 sinfo.glyphs = 0;
1670 sinfo.num_glyphs = 0;
1671 } else {
1672 gp = 0;
1673 if (fw->font) {
1674 if (!fw->unencoded)
1675 gp = fontgrid_locate_glyph(fw->font->glyphs,
1676 fw->font->glyphs_used,
1677 pi->sel_start, TRUE);
1678 else
1679 gp = fontgrid_locate_glyph(fw->font->unencoded,
1680 fw->font->unencoded_used,
1681 pi->sel_start, TRUE);
1682 if (gp == 0) {
1683 empty_glyph.encoding = pi->sel_start;
1684 gp = &empty_glyph;
1685 }
1686 }
1687
1688 sinfo.glyphs = gp;
1689 sinfo.num_glyphs = 1;
1690 }
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,
1697 &sinfo);
1698 }
1699
1700 static void
paste_selection(GtkWidget * widget,GdkEventButton * event)1701 paste_selection(GtkWidget *widget, GdkEventButton *event)
1702 {
1703 start_selection(widget, event);
1704
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);
1709 else
1710 fontgrid_paste_selection(FONTGRID(widget), FONTGRID_NORMAL_PASTE);
1711 }
1712
1713 static void
copy_selection(GtkWidget * widget,GdkEventButton * event)1714 copy_selection(GtkWidget *widget, GdkEventButton *event)
1715 {
1716 fontgrid_copy_selection(FONTGRID(widget));
1717 }
1718
1719 /**************************************************************************
1720 *
1721 * Button, pointer motion, and keyboard handling routines.
1722 *
1723 **************************************************************************/
1724
1725 static gint
fontgrid_button_press(GtkWidget * widget,GdkEventButton * event)1726 fontgrid_button_press(GtkWidget *widget, GdkEventButton *event)
1727 {
1728 switch (event->button) {
1729 case 1:
1730 if (event->state & GDK_SHIFT_MASK)
1731 extend_selection(widget, (gint16) event->x, (gint16) event->y);
1732 else
1733 start_selection(widget, event);
1734 break;
1735 case 2: paste_selection(widget, event); break;
1736 case 3: copy_selection(widget, event); break;
1737 }
1738
1739 return FALSE;
1740 }
1741
1742 static gint
fontgrid_button_release(GtkWidget * widget,GdkEventButton * event)1743 fontgrid_button_release(GtkWidget *widget, GdkEventButton *event)
1744 {
1745 switch (event->button) {
1746 case 1: end_selection(widget, event); break;
1747 case 2: break;
1748 case 3: break;
1749 }
1750 return FALSE;
1751 }
1752
1753 static gint
fontgrid_motion_notify(GtkWidget * widget,GdkEventMotion * event)1754 fontgrid_motion_notify(GtkWidget *widget, GdkEventMotion *event)
1755 {
1756 if (event->state & GDK_BUTTON1_MASK)
1757 extend_selection(widget, (gint16) event->x, (gint16) event->y);
1758 #if 0
1759 /*
1760 * Don't need these at the moment.
1761 */
1762 if (event->state & GDK_BUTTON2_MASK) {
1763 }
1764 if (event->state & GDK_BUTTON3_MASK) {
1765 }
1766 #endif
1767 return FALSE;
1768 }
1769
1770 static gint
fontgrid_shift_key_press(GtkWidget * widget,GdkEventKey * event)1771 fontgrid_shift_key_press(GtkWidget *widget, GdkEventKey *event)
1772 {
1773 Fontgrid *fw;
1774 bdf_glyph_t *gp;
1775 guint keyval;
1776 gint32 code, pageno;
1777 guint32 count;
1778 gboolean signal_extend, activate;
1779 FontgridInternalPageInfo *pi, *opi;
1780 FontgridSelectionInfo sinfo;
1781
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);
1785
1786 fw = FONTGRID(widget);
1787
1788 /*
1789 * For number keys, use them to add up a count that will effect the
1790 * behavior of the other keys.
1791 */
1792 if (event->keyval >= GDK_0 && event->keyval <= GDK_9) {
1793 fw->count = (fw->count * 10) + (event->keyval - GDK_0);
1794 return FALSE;
1795 }
1796
1797 if (!fw->unencoded) {
1798 pi = &fw->npage;
1799 opi = &fw->upage;
1800 gp = (fw->font && fw->font->glyphs_used) ?
1801 (fw->font->glyphs + (fw->font->glyphs_used - 1)) : 0;
1802 } else {
1803 pi = &fw->upage;
1804 opi = &fw->npage;
1805 gp = (fw->font && fw->font->unencoded_used) ?
1806 (fw->font->unencoded + (fw->font->unencoded_used - 1)) : 0;
1807 }
1808
1809 activate = FALSE;
1810
1811 code = pi->sel_end;
1812
1813 if ((count = fw->count) == 0)
1814 count = 1;
1815
1816 keyval = event->keyval;
1817 switch (event->keyval) {
1818 case GDK_Page_Up:
1819 case GDK_KP_Page_Up:
1820 count *= fw->pagesize;
1821 keyval = GDK_Left;
1822 break;
1823 case GDK_Page_Down:
1824 case GDK_KP_Page_Down:
1825 count *= fw->pagesize;
1826 keyval = GDK_Right;
1827 break;
1828 case GDK_Home:
1829 case GDK_KP_Home:
1830 count = (pi->pageno - pi->minpage) * fw->pagesize;
1831 keyval = GDK_Left;
1832 break;
1833 case GDK_End:
1834 case GDK_KP_End:
1835 count = (pi->maxpage - pi->pageno) * fw->pagesize;
1836 keyval = GDK_Right;
1837 break;
1838 }
1839
1840 switch (keyval) {
1841 case GDK_Left:
1842 case GDK_KP_Left:
1843 if (code == 0) {
1844 gdk_beep();
1845 return TRUE;
1846 }
1847
1848 if (fw->orientation == GTK_ORIENTATION_VERTICAL)
1849 code -= (fw->cell_rows * count);
1850 else
1851 code -= count;
1852
1853 if (code < 0)
1854 code = 0;
1855
1856 break;
1857 case GDK_Right:
1858 case GDK_KP_Right:
1859 /*
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.
1862 */
1863 if ((fw->unencoded &&
1864 (gp == 0 || code == gp->encoding)) ||
1865 code == 0xffff) {
1866 gdk_beep();
1867 return TRUE;
1868 }
1869
1870 if (fw->orientation == GTK_ORIENTATION_VERTICAL)
1871 code += (fw->cell_rows * count);
1872 else
1873 code += count;
1874
1875 if (fw->unencoded && code > gp->encoding)
1876 code = gp->encoding;
1877 else if (code > 0xffff)
1878 code = 0xffff;
1879
1880 break;
1881 case GDK_Up:
1882 case GDK_KP_Up:
1883 if (code == 0) {
1884 gdk_beep();
1885 return TRUE;
1886 }
1887
1888 if (fw->orientation == GTK_ORIENTATION_HORIZONTAL)
1889 code -= (fw->cell_cols * count);
1890 else
1891 code -= count;
1892
1893 if (code < 0)
1894 code = 0;
1895
1896 break;
1897 case GDK_Down:
1898 case GDK_KP_Down:
1899 /*
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.
1902 */
1903 if ((fw->unencoded &&
1904 (gp == 0 || code == gp->encoding)) ||
1905 code == 0xffff) {
1906 gdk_beep();
1907 return TRUE;
1908 }
1909
1910 if (fw->orientation == GTK_ORIENTATION_HORIZONTAL)
1911 code += (fw->cell_cols * count);
1912 else
1913 code += count;
1914
1915 if (fw->unencoded && code > gp->encoding)
1916 code = gp->encoding;
1917 else if (code > 0xffff)
1918 code = 0xffff;
1919
1920 break;
1921 case GDK_Return:
1922 case GDK_KP_Enter:
1923 pi->sel_end = pi->sel_start;
1924 activate = TRUE;
1925 break;
1926 default:
1927 return FALSE;
1928 }
1929
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);
1935 else {
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);
1939 } else
1940 fontgrid_select_range(fw, pi->sel_end, code);
1941 }
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);
1948 } else
1949 fontgrid_select_range(fw, code, pi->sel_end);
1950 } else
1951 fontgrid_deselect_range(fw, code + 1, pi->sel_end);
1952 }
1953
1954 pi->sel_end = code;
1955
1956 /*
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.
1959 */
1960 pageno = code / fw->pagesize;
1961 if (pageno != pi->pageno) {
1962 fw->no_sel_callback = TRUE;
1963 fontgrid_goto_page(fw, pageno);
1964 }
1965
1966 /*
1967 * Reset the count.
1968 */
1969 fw->count = 0;
1970
1971 if (signal_extend) {
1972 if (pi->sel_start == pi->sel_end) {
1973 /*
1974 * Set up and emit the selection start signal.
1975 */
1976 if (!fw->unencoded)
1977 gp = fontgrid_locate_glyph(fw->font->glyphs,
1978 fw->font->glyphs_used,
1979 code, TRUE);
1980 else
1981 gp = fontgrid_locate_glyph(fw->font->unencoded,
1982 fw->font->unencoded_used,
1983 code, TRUE);
1984 if (gp == 0) {
1985 empty_glyph.encoding = code;
1986 gp = &empty_glyph;
1987 }
1988 sinfo.glyphs = gp;
1989 sinfo.num_glyphs = 1;
1990 } else {
1991 sinfo.glyphs = 0;
1992 sinfo.num_glyphs = 0;
1993 }
1994 sinfo.start = pi->sel_start;
1995 sinfo.end = pi->sel_end;
1996 sinfo.base = fw->base;
1997 sinfo.unencoded = fw->unencoded;
1998
1999 if (!activate) {
2000 sinfo.reason = FONTGRID_EXTEND_SELECTION;
2001 g_signal_emit(G_OBJECT(fw), fontgrid_signals[SELECTION_EXTEND],
2002 0, &sinfo);
2003 } else {
2004 sinfo.reason = FONTGRID_ACTIVATE;
2005 g_signal_emit(G_OBJECT(fw), fontgrid_signals[ACTIVATE], 0,
2006 &sinfo);
2007 }
2008 }
2009
2010 return TRUE;
2011 }
2012
2013 static gint
fontgrid_key_press(GtkWidget * widget,GdkEventKey * event)2014 fontgrid_key_press(GtkWidget *widget, GdkEventKey *event)
2015 {
2016 Fontgrid *fw;
2017 bdf_glyph_t *gp;
2018 gint32 code, pageno;
2019 guint32 count;
2020 gboolean activate;
2021 FontgridInternalPageInfo *pi, *opi;
2022 FontgridSelectionInfo sinfo;
2023
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);
2027
2028 if (event->state & GDK_SHIFT_MASK)
2029 return fontgrid_shift_key_press(widget, event);
2030
2031 fw = FONTGRID(widget);
2032
2033 /*
2034 * For number keys, use them to add up a count that will effect the
2035 * behavior of the other keys.
2036 */
2037 if (event->keyval >= GDK_0 && event->keyval <= GDK_9) {
2038 fw->count = (fw->count * 10) + (event->keyval - GDK_0);
2039 return FALSE;
2040 }
2041
2042 if (!fw->unencoded) {
2043 pi = &fw->npage;
2044 opi = &fw->upage;
2045 gp = (fw->font && fw->font->glyphs_used) ?
2046 (fw->font->glyphs + (fw->font->glyphs_used - 1)) : 0;
2047 } else {
2048 pi = &fw->upage;
2049 opi = &fw->npage;
2050 gp = (fw->font && fw->font->unencoded_used) ?
2051 (fw->font->unencoded + (fw->font->unencoded_used - 1)) : 0;
2052 }
2053
2054 activate = FALSE;
2055
2056 code = pi->sel_start;
2057
2058 if ((count = fw->count) == 0)
2059 count = 1;
2060
2061 switch (event->keyval) {
2062 case GDK_Left:
2063 case GDK_KP_Left:
2064 if (code == 0) {
2065 gdk_beep();
2066 return TRUE;
2067 }
2068
2069 if (fw->orientation == GTK_ORIENTATION_VERTICAL)
2070 code -= (fw->cell_rows * count);
2071 else
2072 code -= count;
2073
2074 if (code < 0)
2075 code = 0;
2076
2077 break;
2078 case GDK_Right:
2079 case GDK_KP_Right:
2080 /*
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.
2083 */
2084 if ((fw->unencoded &&
2085 (gp == 0 || code == gp->encoding)) ||
2086 code == 0xffff) {
2087 gdk_beep();
2088 return TRUE;
2089 }
2090
2091 if (fw->orientation == GTK_ORIENTATION_VERTICAL)
2092 code += (fw->cell_rows * count);
2093 else
2094 code += count;
2095
2096 if (fw->unencoded && code > gp->encoding)
2097 code = gp->encoding;
2098 else if (code > 0xffff)
2099 code = 0xffff;
2100
2101 break;
2102 case GDK_Up:
2103 case GDK_KP_Up:
2104 if (code == 0) {
2105 gdk_beep();
2106 return TRUE;
2107 }
2108
2109 if (fw->orientation == GTK_ORIENTATION_HORIZONTAL)
2110 code -= (fw->cell_cols * count);
2111 else
2112 code -= count;
2113
2114 if (code < 0)
2115 code = 0;
2116
2117 break;
2118 case GDK_Down:
2119 case GDK_KP_Down:
2120 /*
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.
2123 */
2124 if ((fw->unencoded &&
2125 (gp == 0 || code == gp->encoding)) ||
2126 code == 0xffff) {
2127 gdk_beep();
2128 return TRUE;
2129 }
2130
2131 if (fw->orientation == GTK_ORIENTATION_HORIZONTAL)
2132 code += (fw->cell_cols * count);
2133 else
2134 code += count;
2135
2136 if (fw->unencoded && code > gp->encoding)
2137 code = gp->encoding;
2138 else if (code > 0xffff)
2139 code = 0xffff;
2140
2141 break;
2142 case GDK_Page_Up:
2143 case GDK_KP_Page_Up:
2144 fw->from_keyboard = TRUE;
2145 fontgrid_goto_previous_page(fw);
2146 return TRUE;
2147 break;
2148 case GDK_Page_Down:
2149 case GDK_KP_Page_Down:
2150 fw->from_keyboard = TRUE;
2151 fontgrid_goto_next_page(fw);
2152 return TRUE;
2153 break;
2154 case GDK_Home:
2155 case GDK_KP_Home:
2156 fw->from_keyboard = TRUE;
2157 fontgrid_goto_first_page(fw);
2158 return TRUE;
2159 break;
2160 case GDK_End:
2161 case GDK_KP_End:
2162 fw->from_keyboard = TRUE;
2163 fontgrid_goto_last_page(fw);
2164 return TRUE;
2165 break;
2166 case GDK_Return:
2167 case GDK_KP_Enter:
2168 pi->sel_end = pi->sel_start;
2169 activate = TRUE;
2170 break;
2171 case GDK_BackSpace:
2172 case GDK_Delete:
2173 case GDK_KP_Delete:
2174 fontgrid_cut_selection(fw);
2175 return TRUE;
2176 default:
2177 return FALSE;
2178 }
2179
2180 /*
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.
2185 */
2186 fontgrid_deselect_all(fw);
2187
2188 pageno = code / fw->pagesize;
2189 if (pageno != pi->pageno) {
2190 fw->no_sel_callback = TRUE;
2191 fontgrid_goto_page(fw, pageno);
2192 }
2193
2194 pi->sel_start = pi->sel_end = code;
2195 Select(code, pi->selmap);
2196 fontgrid_draw_cells(widget, code, code, FALSE, TRUE);
2197
2198 /*
2199 * Reset the count.
2200 */
2201 fw->count = 0;
2202
2203 /*
2204 * Set up and emit the selection start signal.
2205 */
2206 if (!fw->unencoded)
2207 gp = fontgrid_locate_glyph(fw->font->glyphs, fw->font->glyphs_used,
2208 code, TRUE);
2209 else
2210 gp = fontgrid_locate_glyph(fw->font->unencoded, fw->font->unencoded_used,
2211 code, TRUE);
2212 if (gp == 0) {
2213 empty_glyph.encoding = code;
2214 gp = &empty_glyph;
2215 }
2216 sinfo.glyphs = gp;
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;
2222
2223 if (!activate) {
2224 sinfo.reason = FONTGRID_START_SELECTION;
2225 g_signal_emit(G_OBJECT(fw), fontgrid_signals[SELECTION_START], 0,
2226 &sinfo);
2227 } else {
2228 sinfo.reason = FONTGRID_ACTIVATE;
2229 g_signal_emit(G_OBJECT(fw), fontgrid_signals[ACTIVATE], 0, &sinfo);
2230 }
2231
2232 return TRUE;
2233 }
2234
2235 /**************************************************************************
2236 *
2237 * Class and instance setup.
2238 *
2239 **************************************************************************/
2240
2241 static void
fontgrid_class_init(gpointer g_class,gpointer class_data)2242 fontgrid_class_init(gpointer g_class, gpointer class_data)
2243 {
2244 GObjectClass *gocp = G_OBJECT_CLASS(g_class);
2245 GtkObjectClass *ocp = GTK_OBJECT_CLASS(g_class);
2246 GtkWidgetClass *wcp = GTK_WIDGET_CLASS(g_class);
2247
2248 /*
2249 * Set the class global variables.
2250 */
2251 parent_class = g_type_class_peek_parent(g_class);
2252
2253 /*
2254 * GObject class functions.
2255 */
2256 gocp->set_property = fontgrid_set_property;
2257 gocp->get_property = fontgrid_get_property;
2258 gocp->finalize = fontgrid_finalize;
2259
2260 /*
2261 * GtkObjectClass functions.
2262 */
2263 ocp->destroy = fontgrid_destroy;
2264
2265 /*
2266 * Instance functions.
2267 */
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;
2279
2280 /*
2281 * Add parameters (a.k.a. resource) types.
2282 */
2283 g_object_class_install_property(gocp, PROP_CODE_BASE,
2284 g_param_spec_uint("codeBase",
2285 _("Code base"),
2286 _("Override for the code base (oct, dec, hex) for glyph codes."),
2287 8,
2288 16,
2289 16,
2290 G_PARAM_READWRITE));
2291 g_object_class_install_property(gocp, PROP_POWER2,
2292 g_param_spec_boolean("powersOfTwo",
2293 _("Powers of two"),
2294 _("Indicate whether the grid display should be a power-of-two rows."),
2295 TRUE,
2296 G_PARAM_READWRITE));
2297
2298 g_object_class_install_property(gocp, PROP_ORIENTATION,
2299 g_param_spec_enum("orientation",
2300 _("Orientation"),
2301 _("Should the grid display vertically or horizontally."),
2302 GTK_TYPE_ORIENTATION,
2303 GTK_ORIENTATION_HORIZONTAL,
2304 G_PARAM_READWRITE));
2305
2306 g_object_class_install_property(gocp, PROP_FONT,
2307 g_param_spec_pointer("font",
2308 _("Font"),
2309 _("Font to be displayed."),
2310 G_PARAM_READWRITE));
2311
2312 g_object_class_install_property(gocp, PROP_POINT_SIZE,
2313 g_param_spec_uint("pointSize",
2314 _("Point size"),
2315 _("Set the default point size for new fonts."),
2316 2,
2317 256,
2318 12,
2319 G_PARAM_READWRITE));
2320
2321 g_object_class_install_property(gocp, PROP_SPACING,
2322 g_param_spec_int("spacing",
2323 _("Spacing"),
2324 _("Set the default glyph spacing."),
2325 BDF_PROPORTIONAL,
2326 BDF_CHARCELL,
2327 BDF_PROPORTIONAL,
2328 G_PARAM_READWRITE));
2329
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."),
2334 TRUE,
2335 G_PARAM_READWRITE));
2336
2337 g_object_class_install_property(gocp, PROP_OVERWRITE,
2338 g_param_spec_boolean("overwriteMode",
2339 _("Overwrite mode"),
2340 _("Pasting the selection overwrites."),
2341 TRUE,
2342 G_PARAM_READWRITE));
2343
2344 g_object_class_install_property(gocp, PROP_COLORS,
2345 g_param_spec_pointer("colorList",
2346 _("Color list"),
2347 _("Colors to be used for glyphs having bits-per-pixel > 1."),
2348 G_PARAM_READWRITE));
2349
2350 g_object_class_install_property(gocp, PROP_INITIAL_GLYPH,
2351 g_param_spec_int("initialGlyph",
2352 _("Initial glyph"),
2353 _("Code of the glyph to be displayed first."),
2354 -1,
2355 0xffff,
2356 -1,
2357 G_PARAM_READWRITE));
2358
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."),
2363 1,
2364 4,
2365 1,
2366 G_PARAM_READWRITE));
2367
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."),
2372 1,
2373 2400,
2374 100,
2375 G_PARAM_READWRITE));
2376
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."),
2381 1,
2382 2400,
2383 100,
2384 G_PARAM_READWRITE));
2385
2386 /*
2387 * Add the signals these objects emit.
2388 */
2389 fontgrid_signals[SELECTION_START] =
2390 g_signal_new("selection-start",
2391 G_TYPE_FROM_CLASS(gocp),
2392 G_SIGNAL_RUN_FIRST,
2393 G_STRUCT_OFFSET(FontgridClass, selection_start),
2394 NULL, NULL,
2395 g_cclosure_marshal_VOID__POINTER,
2396 G_TYPE_NONE,
2397 1,
2398 G_TYPE_POINTER);
2399 fontgrid_signals[SELECTION_EXTEND] =
2400 g_signal_new("selection-extend",
2401 G_TYPE_FROM_CLASS(gocp),
2402 G_SIGNAL_RUN_FIRST,
2403 G_STRUCT_OFFSET(FontgridClass, selection_extend),
2404 NULL, NULL,
2405 g_cclosure_marshal_VOID__POINTER,
2406 G_TYPE_NONE,
2407 1,
2408 G_TYPE_POINTER);
2409 fontgrid_signals[SELECTION_END] =
2410 g_signal_new("selection-end",
2411 G_TYPE_FROM_CLASS(gocp),
2412 G_SIGNAL_RUN_FIRST,
2413 G_STRUCT_OFFSET(FontgridClass, selection_end),
2414 NULL, NULL,
2415 g_cclosure_marshal_VOID__POINTER,
2416 G_TYPE_NONE,
2417 1,
2418 G_TYPE_POINTER);
2419 fontgrid_signals[ACTIVATE] =
2420 g_signal_new("activate",
2421 G_TYPE_FROM_CLASS(gocp),
2422 G_SIGNAL_RUN_FIRST,
2423 G_STRUCT_OFFSET(FontgridClass, activate),
2424 NULL, NULL,
2425 g_cclosure_marshal_VOID__POINTER,
2426 G_TYPE_NONE,
2427 1,
2428 G_TYPE_POINTER);
2429 fontgrid_signals[MODIFIED] =
2430 g_signal_new("modified",
2431 G_TYPE_FROM_CLASS(gocp),
2432 G_SIGNAL_RUN_FIRST,
2433 G_STRUCT_OFFSET(FontgridClass, modified),
2434 NULL, NULL,
2435 g_cclosure_marshal_VOID__POINTER,
2436 G_TYPE_NONE,
2437 1,
2438 G_TYPE_POINTER);
2439 fontgrid_signals[TURN_TO_PAGE] =
2440 g_signal_new("turn_to_page",
2441 G_TYPE_FROM_CLASS(gocp),
2442 G_SIGNAL_RUN_FIRST,
2443 G_STRUCT_OFFSET(FontgridClass, page),
2444 NULL, NULL,
2445 g_cclosure_marshal_VOID__POINTER,
2446 G_TYPE_NONE,
2447 1,
2448 G_TYPE_POINTER);
2449 }
2450
2451 static void
fontgrid_init(GTypeInstance * obj,gpointer g_class)2452 fontgrid_init(GTypeInstance *obj, gpointer g_class)
2453 {
2454 Fontgrid *fw = FONTGRID(obj);
2455 FontgridInternalPageInfo *pi;
2456 GdkScreen *screen;
2457 gint fwidth, fpad;
2458
2459 GTK_WIDGET_SET_FLAGS(fw, GTK_CAN_FOCUS);
2460
2461 gtk_widget_style_get(GTK_WIDGET(fw),
2462 "focus-line-width", &fwidth,
2463 "focus-padding", &fpad,
2464 NULL);
2465
2466 fw->base = 16;
2467 fw->power2 = TRUE;
2468 fw->overwrite = TRUE;
2469 fw->noblanks = TRUE;
2470 fw->orientation = GTK_ORIENTATION_HORIZONTAL;
2471 fw->point_size = 12;
2472 fw->spacing = BDF_CHARCELL;
2473 fw->colors = 0;
2474 fw->initial_glyph = 0;
2475 fw->bpp = 1;
2476
2477 screen =
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);
2483
2484 fw->cell_rows = FGRID_DEFAULT_ROWS;
2485 fw->cell_cols = FGRID_DEFAULT_COLS;
2486 fw->border = 4;
2487 fw->hmargin = fw->widget.style->xthickness + fwidth + fpad + fw->border;
2488 fw->vmargin = fw->widget.style->ythickness + fwidth + fpad + fw->border;
2489
2490 fontgrid_set_cell_geometry(fw);
2491 fontgrid_set_rows_cols(fw, 0);
2492
2493 /*
2494 * Private variables.
2495 */
2496 fw->unencoded = FALSE;
2497 fw->debug = FALSE;
2498 fw->xor_gc = 0;
2499 fw->points_used = 0;
2500 fw->points_size = 0;
2501 fw->rgb_used = 0;
2502 fw->rgb_size = 0;
2503
2504 fw->last_click = 0;
2505 fw->mclick_time = 0;
2506
2507 fw->count = 0;
2508 memset((char *) &fw->clipboard, 0, sizeof(bdf_glyphlist_t));
2509
2510 /*
2511 * Initialize the page information.
2512 */
2513 pi = &fw->upage;
2514 pi->minpage = 0;
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);
2520 pi = &fw->npage;
2521 pi->minpage = 0;
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);
2527 }
2528
2529 /**************************************************************************
2530 *
2531 * API.
2532 *
2533 **************************************************************************/
2534
2535 /*
2536 * Type instantiation routines.
2537 */
2538 GType
fontgrid_get_type(void)2539 fontgrid_get_type(void)
2540 {
2541 static GType fontgrid_type = 0;
2542
2543 if (!fontgrid_type) {
2544 static const GTypeInfo fontgrid_info = {
2545 sizeof (FontgridClass), /* class_size */
2546 0, /* base_init */
2547 0, /* base_finalize */
2548 fontgrid_class_init, /* class_init */
2549 0, /* class_finalize */
2550 0, /* class_data */
2551 sizeof(Fontgrid), /* instance_size */
2552 0, /* n_preallocs */
2553 fontgrid_init, /* instance_init */
2554 0, /* value_table */
2555 };
2556 fontgrid_type = g_type_register_static(GTK_TYPE_WIDGET,
2557 "Fontgrid", &fontgrid_info, 0);
2558 }
2559
2560 return fontgrid_type;
2561 }
2562
2563 GtkWidget *
fontgrid_new(const gchar * prop1,...)2564 fontgrid_new(const gchar *prop1, ...)
2565 {
2566 GtkWidget *w;
2567 va_list var_args;
2568
2569 va_start(var_args, prop1);
2570 w = GTK_WIDGET(g_object_new_valist(fontgrid_get_type(), prop1, var_args));
2571 va_end(var_args);
2572
2573 return w;
2574 }
2575
2576 GtkWidget *
fontgrid_newv(bdf_font_t * font,guint32 pointSize,gint32 spacing,gboolean skipBlankPages,gboolean overwriteMode,gboolean powersOfTwo,guint16 * colorList,gint32 initialGlyph,guint codeBase,GtkOrientation orientation,gint32 bitsPerPixel,gint32 horizontalResolution,gint32 verticalResolution,FontgridPageInfo * initialPageInfo)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)
2583 {
2584 Fontgrid *fw = FONTGRID(g_object_new(fontgrid_get_type(), NULL));
2585 gint32 i, boundary;
2586 FontgridInternalPageInfo *pi;
2587
2588 fw->font = font;
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;
2601
2602 /*
2603 * If no font has been provided, make sure a default is created.
2604 * Too many other things depend on a font existing.
2605 */
2606 if (font == 0) {
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(),
2611 "Unknown");
2612 }
2613
2614 fontgrid_set_cell_geometry(fw);
2615 fontgrid_set_rows_cols(fw, 0);
2616
2617 /*
2618 * Initialize the page information.
2619 */
2620 pi = &fw->upage;
2621 pi->minpage = 0;
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);
2627 pi = &fw->npage;
2628 pi->minpage = 0;
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);
2634
2635 /*
2636 * Determine the page info from the initial glyph setting.
2637 */
2638 if (font != 0) {
2639 if (fw->initial_glyph == -1)
2640 fw->initial_glyph = (font->glyphs_used > 0) ?
2641 font->glyphs->encoding : 0;
2642
2643 pi = &fw->npage;
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);
2649
2650 /*
2651 * Set the min/max page numbers for the encoded glyphs.
2652 */
2653 if (font->glyphs_used > 0) {
2654 if (fw->noblanks) {
2655 pi->minpage = font->glyphs->encoding / fw->pagesize;
2656 pi->maxpage =
2657 font->glyphs[font->glyphs_used-1].encoding / fw->pagesize;
2658 } else {
2659 pi->minpage = 0;
2660 pi->maxpage = 0xffff / fw->pagesize;
2661 }
2662 }
2663
2664 /*
2665 * Set the min/max page numbers for the unencoded glyphs.
2666 */
2667 if (font->unencoded_used > 0) {
2668 pi = &fw->upage;
2669
2670 if (fw->noblanks) {
2671 pi->pageno = pi->minpage =
2672 font->glyphs->encoding / fw->pagesize;
2673 pi->maxpage =
2674 font->unencoded[font->unencoded_used-1].encoding /
2675 fw->pagesize;
2676 pi->bcode = pi->pageno * fw->pagesize;
2677 pi->ppage = -1;
2678
2679 /*
2680 * Lower boundary for the next page.
2681 */
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;
2687
2688 } else {
2689 pi->pageno = pi->minpage = 0;
2690 pi->maxpage = 0xffff / fw->pagesize;
2691 pi->ppage = -1;
2692 pi->npage = pi->pageno + 1;
2693 }
2694 }
2695 }
2696
2697 /*
2698 * Provide the initial page info the calling application will need
2699 * to set up the page changing labels.
2700 */
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;
2705
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;
2710 } else {
2711 initialPageInfo->previous_page = fw->upage.ppage;
2712 initialPageInfo->current_page = fw->upage.pageno;
2713 initialPageInfo->next_page = fw->upage.npage;
2714 }
2715
2716 return GTK_WIDGET(fw);
2717 }
2718
2719 gboolean
fontgrid_has_selection(Fontgrid * fw,FontgridSelectionInfo * sinfo)2720 fontgrid_has_selection(Fontgrid *fw, FontgridSelectionInfo *sinfo)
2721 {
2722 FontgridInternalPageInfo *pi;
2723
2724 g_return_val_if_fail(fw != 0, FALSE);
2725
2726 pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
2727
2728 /*
2729 * Set up the selection info to alert the application that the
2730 * base changed.
2731 */
2732 if (sinfo != 0) {
2733 /*
2734 * Initialize the selection info structure.
2735 */
2736 (void) memset((char *) sinfo, 0, sizeof(FontgridSelectionInfo));
2737
2738 if (pi->sel_start == pi->sel_end) {
2739 if (fw->font) {
2740 if (!fw->unencoded)
2741 sinfo->glyphs =
2742 fontgrid_locate_glyph(fw->font->glyphs,
2743 fw->font->glyphs_used,
2744 pi->sel_start, TRUE);
2745 else
2746 sinfo->glyphs =
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;
2753 }
2754 sinfo->num_glyphs = 1;
2755 }
2756 } else {
2757 sinfo->glyphs = 0;
2758 sinfo->num_glyphs = 0;
2759 }
2760
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;
2766 }
2767
2768 return (pi->sel_start == -1) ? FALSE : TRUE;
2769 }
2770
2771 bdf_font_t *
fontgrid_get_font(Fontgrid * fw)2772 fontgrid_get_font(Fontgrid *fw)
2773 {
2774 g_return_val_if_fail(fw != 0, 0);
2775
2776 return fw->font;
2777 }
2778
2779 void
fontgrid_set_font(Fontgrid * fw,bdf_font_t * font,gint32 initial_glyph)2780 fontgrid_set_font(Fontgrid *fw, bdf_font_t *font, gint32 initial_glyph)
2781 {
2782 GtkWidget *w;
2783 gint32 i, boundary;
2784 FontgridInternalPageInfo *pi;
2785 FontgridPageInfo pageinfo;
2786
2787 g_return_if_fail(fw != 0);
2788
2789 if (font == fw->font)
2790 return;
2791
2792 w = GTK_WIDGET(fw);
2793
2794 /*
2795 * Free up the existing font.
2796 */
2797 if (fw->font != 0)
2798 bdf_free_font(fw->font);
2799 fw->font = font;
2800
2801 /*
2802 * Make sure the encoded pages are the default for newly loaded fonts.
2803 */
2804 fw->unencoded = FALSE;
2805
2806 /*
2807 * Set the bits-per-pixel from the font.
2808 */
2809 fw->bpp = (font != 0) ? font->bpp : 1;
2810
2811 /*
2812 * Set the initial glyph code.
2813 */
2814 fw->initial_glyph = initial_glyph;
2815
2816 /*
2817 * Calculate the cell geometry and the rows and columns.
2818 */
2819 fontgrid_set_cell_geometry(fw);
2820 fontgrid_set_rows_cols(fw, 0);
2821
2822 /*
2823 * Initialize the page information.
2824 */
2825 pi = &fw->upage;
2826 pi->minpage = 0;
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);
2832 pi = &fw->npage;
2833 pi->minpage = 0;
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);
2839
2840 /*
2841 * Determine the page info from the initial glyph setting.
2842 */
2843 if (font != 0) {
2844 if (fw->initial_glyph == -1)
2845 fw->initial_glyph = (font->glyphs_used > 0) ?
2846 font->glyphs->encoding : 0;
2847
2848 pi = &fw->npage;
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);
2854
2855 /*
2856 * Set the min/max page numbers for the encoded glyphs.
2857 */
2858 if (font->glyphs_used > 0) {
2859 if (fw->noblanks) {
2860 pi->minpage = font->glyphs->encoding / fw->pagesize;
2861 pi->maxpage =
2862 font->glyphs[font->glyphs_used-1].encoding / fw->pagesize;
2863 } else {
2864 pi->minpage = 0;
2865 pi->maxpage = 0xffff / fw->pagesize;
2866 }
2867 }
2868
2869 /*
2870 * Set the min/max page numbers for the unencoded glyphs.
2871 */
2872 if (font->unencoded_used > 0) {
2873 pi = &fw->upage;
2874
2875 if (fw->noblanks) {
2876 pi->pageno = pi->minpage =
2877 font->glyphs->encoding / fw->pagesize;
2878 pi->maxpage =
2879 font->unencoded[font->unencoded_used-1].encoding /
2880 fw->pagesize;
2881 pi->bcode = pi->pageno * fw->pagesize;
2882 pi->ppage = -1;
2883
2884 /*
2885 * Lower boundary for the next page.
2886 */
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;
2892
2893 } else {
2894 pi->pageno = pi->minpage = 0;
2895 pi->maxpage = 0xffff / fw->pagesize;
2896 pi->ppage = -1;
2897 pi->npage = pi->pageno + 1;
2898 }
2899 }
2900 }
2901
2902 /*
2903 * Signal that a page change has taken place so the application can do
2904 * setup that it needs.
2905 */
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;
2909
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;
2914 } else {
2915 pageinfo.previous_page = fw->upage.ppage;
2916 pageinfo.current_page = fw->upage.pageno;
2917 pageinfo.next_page = fw->upage.npage;
2918 }
2919
2920 g_signal_emit(G_OBJECT(fw), fontgrid_signals[TURN_TO_PAGE], 0, &pageinfo);
2921
2922 /*
2923 * Queue up a resize so the grid will change size.
2924 */
2925 gtk_widget_queue_resize(w);
2926 }
2927
2928 gchar *
fontgrid_get_font_messages(Fontgrid * fw)2929 fontgrid_get_font_messages(Fontgrid *fw)
2930 {
2931 g_return_val_if_fail(fw != 0, 0);
2932
2933 return (fw->font) ? fw->font->acmsgs : 0;
2934 }
2935
2936 guint
fontgrid_get_code_base(Fontgrid * fw)2937 fontgrid_get_code_base(Fontgrid *fw)
2938 {
2939 g_return_val_if_fail(fw != 0, 0);
2940
2941 return fw->base;
2942 }
2943
2944 void
fontgrid_set_code_base(Fontgrid * fw,guint base)2945 fontgrid_set_code_base(Fontgrid *fw, guint base)
2946 {
2947 FontgridInternalPageInfo *pi;
2948 FontgridSelectionInfo sinfo;
2949
2950 g_return_if_fail(fw != 0);
2951
2952 switch (base) {
2953 case 8: case 10: case 16:
2954 if (fw->base != base) {
2955 fw->base = base;
2956 if (!fw->unencoded) {
2957 pi = &fw->npage;
2958 fontgrid_draw_cells(GTK_WIDGET(fw), fw->npage.bcode,
2959 fw->npage.bcode + fw->pagesize,
2960 TRUE, FALSE);
2961 } else
2962 pi = &fw->upage;
2963
2964 /*
2965 * Set up the selection info to alert the application that the
2966 * base changed.
2967 */
2968 if (pi->sel_start == pi->sel_end) {
2969 if (fw->font) {
2970 if (!fw->unencoded)
2971 sinfo.glyphs =
2972 fontgrid_locate_glyph(fw->font->glyphs,
2973 fw->font->glyphs_used,
2974 pi->sel_start, TRUE);
2975 else
2976 sinfo.glyphs =
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;
2983 }
2984 sinfo.num_glyphs = 1;
2985 }
2986 } else {
2987 sinfo.glyphs = 0;
2988 sinfo.num_glyphs = 0;
2989 }
2990
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,
2997 &sinfo);
2998 }
2999 break;
3000 }
3001 }
3002
3003 GtkOrientation
fontgrid_get_orientation(Fontgrid * fw)3004 fontgrid_get_orientation(Fontgrid *fw)
3005 {
3006 g_return_val_if_fail(fw != 0, GTK_ORIENTATION_HORIZONTAL);
3007
3008 return fw->orientation;
3009 }
3010
3011 void
fontgrid_set_orientation(Fontgrid * fw,GtkOrientation dir)3012 fontgrid_set_orientation(Fontgrid *fw, GtkOrientation dir)
3013 {
3014 guint16 tmp;
3015
3016 g_return_if_fail(fw != 0);
3017
3018 if (dir != fw->orientation) {
3019 fw->orientation = dir;
3020
3021 /*
3022 * Need to swap rows and cols and attempt a resize if the object
3023 * has been constructed.
3024 */
3025 tmp = fw->cell_rows;
3026 fw->cell_rows = fw->cell_cols;
3027 fw->cell_cols = tmp;
3028
3029 gtk_widget_queue_resize(GTK_WIDGET(fw));
3030 }
3031 }
3032
3033 void
fontgrid_get_page_info(Fontgrid * fw,FontgridPageInfo * pageinfo)3034 fontgrid_get_page_info(Fontgrid *fw, FontgridPageInfo *pageinfo)
3035 {
3036 g_return_if_fail(fw != 0);
3037 g_return_if_fail(pageinfo != 0);
3038
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;
3042
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;
3047 } else {
3048 pageinfo->previous_page = fw->upage.ppage;
3049 pageinfo->current_page = fw->upage.pageno;
3050 pageinfo->next_page = fw->upage.npage;
3051 }
3052 }
3053
3054 /*
3055 * This is the routine that does the majority of the work for updating
3056 * page changes.
3057 */
3058 static void
fontgrid_page_change_update(Fontgrid * fw,FontgridInternalPageInfo * pi)3059 fontgrid_page_change_update(Fontgrid *fw, FontgridInternalPageInfo *pi)
3060 {
3061 gint32 code;
3062 FontgridPageInfo pageinfo;
3063 FontgridSelectionInfo selinfo;
3064
3065 code = pi->sel_start - pi->bcode;
3066 pi->bcode = pi->pageno * fw->pagesize;
3067
3068 if (fw->from_keyboard) {
3069 fontgrid_deselect_all(fw);
3070 code += pi->bcode;
3071 pi->sel_start = pi->sel_end = code;
3072 Select(code, pi->selmap);
3073 fw->from_keyboard = FALSE;
3074 }
3075 fontgrid_neighbor_pages(fw, pi->pageno, &pi->ppage, &pi->npage);
3076
3077 fontgrid_draw_cells(GTK_WIDGET(fw), pi->bcode,
3078 pi->bcode + (fw->pagesize - 1), TRUE, TRUE);
3079
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;
3083
3084 pageinfo.previous_page = pi->ppage;
3085 pageinfo.current_page = pi->pageno;
3086 pageinfo.next_page = pi->npage;
3087
3088 g_signal_emit(G_OBJECT(fw), fontgrid_signals[TURN_TO_PAGE], 0, &pageinfo);
3089
3090 /*
3091 * If this was called from the keyboard, then indicate the changed
3092 * selection.
3093 */
3094 if (!fw->no_sel_callback && fw->from_keyboard) {
3095 selinfo.glyphs = 0;
3096 selinfo.num_glyphs = 1;
3097 if (fw->font) {
3098 selinfo.glyphs = (!fw->unencoded) ?
3099 fontgrid_locate_glyph(fw->font->glyphs,
3100 fw->font->glyphs_used,
3101 code, TRUE) :
3102 fontgrid_locate_glyph(fw->font->unencoded,
3103 fw->font->unencoded_used,
3104 code, TRUE);
3105 }
3106 if (selinfo.glyphs == 0) {
3107 empty_glyph.encoding = code;
3108 selinfo.glyphs = &empty_glyph;
3109 }
3110
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,
3117 &selinfo);
3118 }
3119 }
3120
3121 void
fontgrid_goto_page(Fontgrid * fw,gint32 pageno)3122 fontgrid_goto_page(Fontgrid *fw, gint32 pageno)
3123 {
3124 guint32 mpage;
3125 FontgridInternalPageInfo *pi;
3126
3127 g_return_if_fail(fw != 0);
3128
3129 pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
3130
3131 mpage = 0xffff / fw->pagesize;
3132
3133 if (pageno < 0)
3134 pageno = 0;
3135 if (pageno > mpage)
3136 pageno = mpage;
3137
3138 if (pageno != pi->pageno) {
3139 pi->pageno = pageno;
3140 fontgrid_page_change_update(fw, pi);
3141 }
3142 }
3143
3144 void
fontgrid_goto_code(Fontgrid * fw,gint32 code)3145 fontgrid_goto_code(Fontgrid *fw, gint32 code)
3146 {
3147 gint32 pageno;
3148 FontgridInternalPageInfo *pi;
3149 FontgridSelectionInfo selinfo;
3150
3151 g_return_if_fail(fw != 0);
3152
3153 pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
3154
3155 if (code < 0)
3156 code = 0;
3157 if (code > 0xffff)
3158 code = 0xffff;
3159
3160 pageno = code / fw->pagesize;
3161
3162 if (pageno != pi->pageno) {
3163 fw->no_sel_callback = TRUE;
3164 pi->pageno = pageno;
3165 fontgrid_page_change_update(fw, pi);
3166 }
3167
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);
3172
3173 selinfo.glyphs = 0;
3174 selinfo.num_glyphs = 1;
3175 if (fw->font) {
3176 selinfo.glyphs = (!fw->unencoded) ?
3177 fontgrid_locate_glyph(fw->font->glyphs,
3178 fw->font->glyphs_used,
3179 code, TRUE) :
3180 fontgrid_locate_glyph(fw->font->unencoded,
3181 fw->font->unencoded_used,
3182 code, TRUE);
3183 }
3184 if (selinfo.glyphs == 0) {
3185 empty_glyph.encoding = code;
3186 selinfo.glyphs = &empty_glyph;
3187 }
3188
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,
3195 &selinfo);
3196 }
3197
3198 void
fontgrid_goto_first_page(Fontgrid * fw)3199 fontgrid_goto_first_page(Fontgrid *fw)
3200 {
3201 FontgridInternalPageInfo *pi;
3202
3203 g_return_if_fail(fw != 0);
3204
3205 pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
3206
3207 if (pi->pageno == pi->minpage)
3208 return;
3209
3210 pi->pageno = pi->minpage;
3211 fontgrid_page_change_update(fw, pi);
3212 }
3213
3214 void
fontgrid_goto_last_page(Fontgrid * fw)3215 fontgrid_goto_last_page(Fontgrid *fw)
3216 {
3217 FontgridInternalPageInfo *pi;
3218
3219 g_return_if_fail(fw != 0);
3220
3221 pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
3222
3223 if (pi->pageno == pi->maxpage)
3224 return;
3225
3226 pi->pageno = pi->maxpage;
3227 fontgrid_page_change_update(fw, pi);
3228 }
3229
3230 void
fontgrid_goto_next_page(Fontgrid * fw)3231 fontgrid_goto_next_page(Fontgrid *fw)
3232 {
3233 FontgridInternalPageInfo *pi;
3234
3235 g_return_if_fail(fw != 0);
3236
3237 pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
3238
3239 if (pi->pageno == pi->maxpage)
3240 return;
3241
3242 pi->pageno = pi->npage;
3243 fontgrid_page_change_update(fw, pi);
3244 }
3245
3246 void
fontgrid_goto_previous_page(Fontgrid * fw)3247 fontgrid_goto_previous_page(Fontgrid *fw)
3248 {
3249 FontgridInternalPageInfo *pi;
3250
3251 g_return_if_fail(fw != 0);
3252
3253 pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
3254
3255 if (pi->pageno == pi->minpage)
3256 return;
3257
3258 pi->pageno = pi->ppage;
3259 fontgrid_page_change_update(fw, pi);
3260 }
3261
3262 gboolean
fontgrid_viewing_unencoded(Fontgrid * fw)3263 fontgrid_viewing_unencoded(Fontgrid *fw)
3264 {
3265 g_return_val_if_fail(fw != 0, FALSE);
3266
3267 return fw->unencoded;
3268 }
3269
3270 void
fontgrid_switch_encoding_view(Fontgrid * fw)3271 fontgrid_switch_encoding_view(Fontgrid *fw)
3272 {
3273 FontgridInternalPageInfo *pi;
3274
3275 g_return_if_fail(fw != 0);
3276
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,
3280 TRUE, TRUE);
3281 }
3282
3283 gchar *
fontgrid_get_font_name(Fontgrid * fw)3284 fontgrid_get_font_name(Fontgrid *fw)
3285 {
3286 g_return_val_if_fail(fw != 0, 0);
3287
3288 return (fw->font) ? fw->font->name : "";
3289 }
3290
3291 void
fontgrid_set_font_name(Fontgrid * fw,gchar * name)3292 fontgrid_set_font_name(Fontgrid *fw, gchar *name)
3293 {
3294 FontgridModificationInfo minfo;
3295
3296 g_return_if_fail(fw != 0);
3297 g_return_if_fail(fw->font != 0);
3298
3299 if (fw->font->name != 0)
3300 free(fw->font->name);
3301
3302 if (name == 0 || *name == 0)
3303 fw->font->name = bdf_make_xlfd_name(fw->font, g_get_prgname(),
3304 "Unknown");
3305 else
3306 fw->font->name = g_strdup(name);
3307
3308 bdf_set_modified(fw->font, 1);
3309
3310 minfo.reason = FONTGRID_MODIFIED;
3311 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3312 }
3313
3314 gboolean
fontgrid_get_font_modified(Fontgrid * fw)3315 fontgrid_get_font_modified(Fontgrid *fw)
3316 {
3317 g_return_val_if_fail(fw != 0, FALSE);
3318
3319 return (fw->font) ? ((fw->font->modified) ? TRUE : FALSE) : FALSE;
3320 }
3321
3322 void
fontgrid_set_font_modified(Fontgrid * fw,gboolean mod)3323 fontgrid_set_font_modified(Fontgrid *fw, gboolean mod)
3324 {
3325 FontgridInternalPageInfo *pi;
3326
3327 g_return_if_fail(fw != 0);
3328
3329 if (fw->font && fw->font->modified != mod) {
3330 bdf_set_modified(fw->font, mod);
3331
3332 if (mod == FALSE) {
3333 /*
3334 * Redraw all the labels to clear those that were showing as
3335 * modified.
3336 */
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);
3340 } else {
3341 /*
3342 * If the font is being marked as modified, then signal the
3343 * application of this state.
3344 */
3345 fprintf(stderr, "MOD\n");
3346 }
3347 }
3348 }
3349
3350 void
fontgrid_set_unicode_glyph_names(Fontgrid * fw,FILE * in)3351 fontgrid_set_unicode_glyph_names(Fontgrid *fw, FILE *in)
3352 {
3353 FontgridModificationInfo minfo;
3354
3355 g_return_if_fail(fw != 0);
3356 g_return_if_fail(in != 0);
3357
3358 if (bdf_set_unicode_glyph_names(in, fw->font, 0)) {
3359 /*
3360 * Redraw the labels.
3361 */
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);
3366 }
3367 }
3368
3369 void
fontgrid_set_adobe_glyph_names(Fontgrid * fw,FILE * in)3370 fontgrid_set_adobe_glyph_names(Fontgrid *fw, FILE *in)
3371 {
3372 FontgridModificationInfo minfo;
3373
3374 g_return_if_fail(fw != 0);
3375 g_return_if_fail(in != 0);
3376
3377 if (bdf_set_adobe_glyph_names(in, fw->font, 0)) {
3378 /*
3379 * Redraw the labels.
3380 */
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);
3385 }
3386 }
3387
3388 void
fontgrid_set_code_glyph_names(Fontgrid * fw,gint ch)3389 fontgrid_set_code_glyph_names(Fontgrid *fw, gint ch)
3390 {
3391 FontgridModificationInfo minfo;
3392
3393 g_return_if_fail(fw != 0);
3394
3395 if (bdf_set_glyph_code_names(ch, fw->font, 0)) {
3396 /*
3397 * Redraw the labels.
3398 */
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);
3403 }
3404 }
3405
3406 void
fontgrid_make_xlfd_font_name(Fontgrid * fw)3407 fontgrid_make_xlfd_font_name(Fontgrid *fw)
3408 {
3409 FontgridModificationInfo minfo;
3410
3411 g_return_if_fail(fw != 0);
3412
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);
3417 }
3418 }
3419
3420 void
fontgrid_update_font_name_from_properties(Fontgrid * fw)3421 fontgrid_update_font_name_from_properties(Fontgrid *fw)
3422 {
3423 FontgridModificationInfo minfo;
3424
3425 g_return_if_fail(fw != 0);
3426
3427 if (bdf_has_xlfd_name(fw->font)) {
3428 bdf_update_name_from_properties(fw->font);
3429
3430 minfo.reason = FONTGRID_NAME_MODIFIED;
3431 minfo.name = fw->font->name;
3432 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3433 }
3434 }
3435
3436 void
fontgrid_update_properties_from_font_name(Fontgrid * fw)3437 fontgrid_update_properties_from_font_name(Fontgrid *fw)
3438 {
3439 FontgridModificationInfo minfo;
3440
3441 g_return_if_fail(fw != 0);
3442
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);
3446 }
3447 }
3448
3449 void
fontgrid_set_font_property(Fontgrid * fw,bdf_property_t * prop)3450 fontgrid_set_font_property(Fontgrid *fw, bdf_property_t *prop)
3451 {
3452 FontgridModificationInfo minfo;
3453 gboolean changed;
3454 bdf_property_t *p;
3455
3456 g_return_if_fail(fw != 0);
3457 g_return_if_fail(prop != 0);
3458
3459 changed = FALSE;
3460
3461 if ((p = bdf_get_font_property(fw->font, prop->name)) == 0)
3462 changed = TRUE;
3463 else if (p->format == prop->format) {
3464 switch (p->format) {
3465 case BDF_ATOM:
3466 /*
3467 * If the atoms are different or one is NULL and the other isn't,
3468 * then the property will be changed.
3469 */
3470 if ((p->value.atom && prop->value.atom &&
3471 strcmp(p->value.atom, prop->value.atom) != 0) ||
3472 p->value.atom != prop->value.atom)
3473 changed = TRUE;
3474 break;
3475 case BDF_INTEGER:
3476 if (p->value.int32 != prop->value.int32)
3477 changed = TRUE;
3478 break;
3479 case BDF_CARDINAL:
3480 if (p->value.card32 != prop->value.card32)
3481 changed = TRUE;
3482 break;
3483 }
3484 }
3485
3486 /*
3487 * If this causes no change, just return.
3488 */
3489 if (changed == FALSE)
3490 return;
3491
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);
3495 }
3496
3497 void
fontgrid_delete_font_property(Fontgrid * fw,gchar * prop_name)3498 fontgrid_delete_font_property(Fontgrid *fw, gchar *prop_name)
3499 {
3500 FontgridModificationInfo minfo;
3501 bdf_property_t *p;
3502
3503 g_return_if_fail(fw != 0);
3504 g_return_if_fail(prop_name != 0);
3505
3506 /*
3507 * If the property doesn't exist, then just return.
3508 */
3509 if ((p = bdf_get_font_property(fw->font, prop_name)) == 0)
3510 return;
3511
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);
3515 }
3516
3517 guint32
fontgrid_get_font_comments(Fontgrid * fw,gchar ** comments)3518 fontgrid_get_font_comments(Fontgrid *fw, gchar **comments)
3519 {
3520 g_return_val_if_fail(fw != 0, 0);
3521
3522 if (comments != 0)
3523 *comments = fw->font->comments;
3524
3525 return fw->font->comments_len;
3526 }
3527
3528 void
fontgrid_set_font_comments(Fontgrid * fw,gchar * comments)3529 fontgrid_set_font_comments(Fontgrid *fw, gchar *comments)
3530 {
3531 FontgridModificationInfo minfo;
3532 unsigned int len;
3533
3534 g_return_if_fail(fw != 0);
3535
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);
3540 }
3541 }
3542
3543 gint
fontgrid_get_font_spacing(Fontgrid * fw)3544 fontgrid_get_font_spacing(Fontgrid *fw)
3545 {
3546 g_return_val_if_fail(fw != 0, -1);
3547
3548 return fw->font->spacing;
3549 }
3550
3551 void
fontgrid_set_font_spacing(Fontgrid * fw,gint spacing)3552 fontgrid_set_font_spacing(Fontgrid *fw, gint spacing)
3553 {
3554 FontgridModificationInfo minfo;
3555 bdf_property_t p;
3556
3557 g_return_if_fail(fw != 0);
3558
3559 if (spacing < BDF_PROPORTIONAL || spacing > BDF_CHARCELL ||
3560 fw->font->spacing == spacing)
3561 return;
3562
3563 p.name = "SPACING";
3564 p.format = BDF_ATOM;
3565 switch (spacing) {
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;
3569 }
3570
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);
3574 }
3575
3576 guint16
fontgrid_get_font_device_width(Fontgrid * fw)3577 fontgrid_get_font_device_width(Fontgrid *fw)
3578 {
3579 g_return_val_if_fail(fw != 0, 0);
3580
3581 return fw->font->monowidth;
3582 }
3583
3584 void
fontgrid_set_font_device_width(Fontgrid * fw,guint16 dwidth)3585 fontgrid_set_font_device_width(Fontgrid *fw, guint16 dwidth)
3586 {
3587 FontgridModificationInfo minfo;
3588
3589 g_return_if_fail(fw != 0);
3590
3591 /*
3592 * Only set the global device width if this is not a proportional font or
3593 * if there the device width changed.
3594 */
3595 if (fw->font->spacing == BDF_PROPORTIONAL ||
3596 fw->font->monowidth == dwidth)
3597 return;
3598
3599 fw->font->monowidth = dwidth;
3600 fw->font->modified = 1;
3601
3602 minfo.reason = FONTGRID_DEVICE_WIDTH_MODIFIED;
3603 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3604 }
3605
3606 void
fontgrid_get_font_info(Fontgrid * fw,FontgridFontInfo * info)3607 fontgrid_get_font_info(Fontgrid *fw, FontgridFontInfo *info)
3608 {
3609 g_return_if_fail(fw != 0);
3610 g_return_if_fail(fw->font != 0);
3611 g_return_if_fail(info != 0);
3612
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));
3626 }
3627
3628 void
fontgrid_set_font_info(Fontgrid * fw,FontgridFontInfo * info)3629 fontgrid_set_font_info(Fontgrid *fw, FontgridFontInfo *info)
3630 {
3631 int mod;
3632 bdf_font_t *f;
3633 bdf_property_t prop;
3634 FontgridModificationInfo minfo;
3635
3636 g_return_if_fail(fw != 0);
3637 g_return_if_fail(fw->font != 0);
3638 g_return_if_fail(info != 0);
3639
3640 f = fw->font;
3641
3642 minfo.reason = FONTGRID_MODIFIED;
3643
3644 /*
3645 * Do some special stuff with the modified field so we know whether to
3646 * call the modified callback or not.
3647 */
3648 mod = f->modified;
3649 f->modified = 0;
3650
3651 /*
3652 * Handle the default character field. If it happens to be -1, then
3653 * delete the font property. Otherwise add it.
3654 */
3655 if (info->default_char < 0)
3656 bdf_delete_font_property(f, "DEFAULT_CHAR");
3657 else {
3658 prop.name = "DEFAULT_CHAR";
3659 prop.format = BDF_CARDINAL;
3660 prop.value.card32 = info->default_char;
3661 bdf_add_font_property(f, &prop);
3662 }
3663
3664 prop.name = "FONT_ASCENT";
3665 prop.format = BDF_INTEGER;
3666 prop.value.int32 = info->font_ascent;
3667 bdf_add_font_property(f, &prop);
3668
3669 prop.name = "FONT_DESCENT";
3670 prop.format = BDF_INTEGER;
3671 prop.value.int32 = info->font_descent;
3672 bdf_add_font_property(f, &prop);
3673
3674 prop.name = "RESOLUTION_X";
3675 prop.format = BDF_CARDINAL;
3676 prop.value.int32 = info->resolution_x;
3677 bdf_add_font_property(f, &prop);
3678
3679 prop.name = "RESOLUTION_Y";
3680 prop.format = BDF_CARDINAL;
3681 prop.value.int32 = info->resolution_y;
3682 bdf_add_font_property(f, &prop);
3683
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;
3691 }
3692 if (prop.value.atom != 0)
3693 bdf_add_font_property(f, &prop);
3694
3695 /*
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
3698 * called.
3699 */
3700 if (f->modified && bdf_has_xlfd_name(f))
3701 fontgrid_update_font_name_from_properties(fw);
3702
3703 /*
3704 * Now determine if the monowidth field will have a resize affect on
3705 * things.
3706 */
3707 if (f->spacing != BDF_PROPORTIONAL) {
3708 if (f->monowidth == 0) {
3709 /*
3710 * Handle the special case of a proportional font being changed to
3711 * some other spacing.
3712 */
3713 f->monowidth = f->bbx.width;
3714 f->modified = 1;
3715 }
3716 if (info->monowidth != f->monowidth) {
3717 /*
3718 * Go ahead and queue up a resize in case the monowidth
3719 * really does change the size.
3720 */
3721 gtk_widget_queue_resize(GTK_WIDGET(fw));
3722 f->monowidth = f->bbx.width = info->monowidth;
3723 f->modified = 1;
3724 }
3725 }
3726 if (f->modified)
3727 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3728 f->modified |= mod;
3729 }
3730
3731 void
fontgrid_translate_glyphs(Fontgrid * fw,gint16 dx,gint16 dy,gboolean all_glyphs)3732 fontgrid_translate_glyphs(Fontgrid *fw, gint16 dx, gint16 dy,
3733 gboolean all_glyphs)
3734 {
3735 GtkWidget *w = (GtkWidget *) fw;
3736 gint32 start, end;
3737 FontgridInternalPageInfo *pi;
3738 FontgridModificationInfo minfo;
3739
3740 g_return_if_fail(fw != 0);
3741
3742 pi = (!fw->unencoded) ? &fw->npage: &fw->upage;
3743
3744 if (all_glyphs) {
3745 start = pi->minpage * fw->pagesize;
3746 end = (pi->maxpage * fw->pagesize) + fw->pagesize;
3747 } else {
3748 start = pi->sel_start;
3749 end = pi->sel_end;
3750 }
3751
3752 if (bdf_translate_glyphs(fw->font, dx, dy, start, end, 0, 0,
3753 fw->unencoded)) {
3754 gtk_widget_queue_resize(w);
3755 if (GTK_WIDGET_REALIZED(w))
3756 gdk_window_clear(w->window);
3757
3758 gtk_widget_queue_resize(w);
3759 if (GTK_WIDGET_REALIZED(w))
3760 gdk_window_clear(w->window);
3761
3762 minfo.reason = FONTGRID_GLYPHS_MODIFIED;
3763 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3764 }
3765 }
3766
3767 void
fontgrid_rotate_glyphs(Fontgrid * fw,gint16 degrees,gboolean all_glyphs)3768 fontgrid_rotate_glyphs(Fontgrid *fw, gint16 degrees, gboolean all_glyphs)
3769 {
3770 GtkWidget *w = (GtkWidget *) fw;
3771 gint32 start, end;
3772 FontgridInternalPageInfo *pi;
3773 FontgridModificationInfo minfo;
3774
3775 g_return_if_fail(fw != 0);
3776
3777 pi = (!fw->unencoded) ? &fw->npage: &fw->upage;
3778
3779 if (all_glyphs) {
3780 start = pi->minpage * fw->pagesize;
3781 end = (pi->maxpage * fw->pagesize) + fw->pagesize;
3782 } else {
3783 start = pi->sel_start;
3784 end = pi->sel_end;
3785 }
3786
3787 if (bdf_rotate_glyphs(fw->font, degrees, start, end, 0, 0,
3788 fw->unencoded)) {
3789 gtk_widget_queue_resize(w);
3790 if (GTK_WIDGET_REALIZED(w))
3791 gdk_window_clear(w->window);
3792
3793 minfo.reason = FONTGRID_GLYPHS_MODIFIED;
3794 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3795 }
3796 }
3797
3798 void
fontgrid_shear_glyphs(Fontgrid * fw,gint16 degrees,gboolean all_glyphs)3799 fontgrid_shear_glyphs(Fontgrid *fw, gint16 degrees, gboolean all_glyphs)
3800 {
3801 GtkWidget *w = (GtkWidget *) fw;
3802 gint32 start, end;
3803 FontgridInternalPageInfo *pi;
3804 FontgridModificationInfo minfo;
3805
3806 g_return_if_fail(fw != 0);
3807
3808 pi = (!fw->unencoded) ? &fw->npage: &fw->upage;
3809
3810 if (all_glyphs) {
3811 start = pi->minpage * fw->pagesize;
3812 end = (pi->maxpage * fw->pagesize) + fw->pagesize;
3813 } else {
3814 start = pi->sel_start;
3815 end = pi->sel_end;
3816 }
3817
3818 if (bdf_shear_glyphs(fw->font, degrees, start, end, 0, 0,
3819 fw->unencoded)) {
3820 gtk_widget_queue_resize(w);
3821 if (GTK_WIDGET_REALIZED(w))
3822 gdk_window_clear(w->window);
3823
3824 minfo.reason = FONTGRID_GLYPHS_MODIFIED;
3825 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3826 }
3827 }
3828
3829 void
fontgrid_embolden_glyphs(Fontgrid * fw,gboolean all_glyphs)3830 fontgrid_embolden_glyphs(Fontgrid *fw, gboolean all_glyphs)
3831 {
3832 GtkWidget *w = (GtkWidget *) fw;
3833 gint resize;
3834 gint32 start, end;
3835 FontgridInternalPageInfo *pi;
3836 FontgridModificationInfo minfo;
3837
3838 g_return_if_fail(fw != 0);
3839
3840 pi = (!fw->unencoded) ? &fw->npage: &fw->upage;
3841
3842 if (all_glyphs) {
3843 start = pi->minpage * fw->pagesize;
3844 end = (pi->maxpage * fw->pagesize) + fw->pagesize;
3845 } else {
3846 start = pi->sel_start;
3847 end = pi->sel_end;
3848 }
3849
3850 resize = 0;
3851 if (bdf_embolden_glyphs(fw->font, start, end, 0, 0,
3852 fw->unencoded, &resize)) {
3853 if (resize) {
3854 gtk_widget_queue_resize(w);
3855 if (GTK_WIDGET_REALIZED(w))
3856 gdk_window_clear(w->window);
3857 } else
3858 /*
3859 * Just redisplay the selection.
3860 */
3861 fontgrid_draw_cells(w, start, end, TRUE, TRUE);
3862
3863 minfo.reason = FONTGRID_GLYPHS_MODIFIED;
3864 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3865 }
3866 }
3867
3868 gboolean
fontgrid_clipboard_empty(Fontgrid * fw)3869 fontgrid_clipboard_empty(Fontgrid *fw)
3870 {
3871 GdkWindow *owner;
3872 gboolean empty = TRUE;
3873 GdkAtom atype;
3874 gint aformat, nitems;
3875 guchar *data;
3876
3877 g_return_val_if_fail(fw != 0, empty);
3878
3879 if ((owner = gdk_selection_owner_get(FONTGRID_CLIPBOARD)) == 0)
3880 return empty;
3881
3882 /*
3883 * Check to see if the clipboard contents are empty or not.
3884 *
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.
3888 */
3889 if (gdk_property_get(owner, FONTGRID_CLIPBOARD, FONTGRID_GLYPHLIST,
3890 0, 4, FALSE, &atype, &aformat, &nitems, &data)) {
3891 if (nitems > 0) {
3892 empty = FALSE;
3893 free((char *) data);
3894 }
3895 }
3896
3897 return empty;
3898 }
3899
3900 static unsigned char *
fontgrid_encode_selection(Fontgrid * fw,guint32 * bytes)3901 fontgrid_encode_selection(Fontgrid *fw, guint32 *bytes)
3902 {
3903 FontgridInternalPageInfo *pi;
3904 bdf_glyph_t *gp;
3905 bdf_glyphlist_t *gl;
3906 guint16 a;
3907 guint32 i, nlen, bcount;
3908 guchar *sel, *sp;
3909
3910 *bytes = 0;
3911
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);
3915
3916 /*
3917 * Calculate the number of bytes that will be needed for everything except
3918 * the name strings and the bitmap data.
3919 */
3920 bcount = (sizeof(unsigned int) << 1) + (6 * sizeof(unsigned short)) +
3921 (((6 * sizeof(unsigned short)) + sizeof(unsigned int)) *
3922 gl->glyphs_used);
3923
3924 /*
3925 * Figure out how much extra will be needed for the names, bitmaps, and
3926 * PSF Unicode mappings.
3927 */
3928 for (i = 0, gp = gl->glyphs; i < gl->glyphs_used; i++, gp++) {
3929 nlen = (gp->name) ? (guint32) (strlen(gp->name) + 1) : 0;
3930 /*
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.
3934 */
3935 bcount += nlen + gp->bytes + 2 + gp->unicode.map_used;
3936 }
3937
3938 /*
3939 * Allocate the storage space needed for the encoded form.
3940 */
3941 sel = sp = g_malloc(bcount);
3942
3943 /*
3944 * Set the returned byte count.
3945 */
3946 *bytes = bcount;
3947
3948 /*
3949 * Encode the 20-byte header.
3950 */
3951 a = (guint16) gl->bpp;
3952 *sp++ = (a >> 8) & 0xff;
3953 *sp++ = a & 0xff;
3954
3955 nlen = (guint32) gl->start;
3956 *sp++ = (nlen >> 24) & 0xff;
3957 *sp++ = (nlen >> 16) & 0xff;
3958 *sp++ = (nlen >> 8) & 0xff;
3959 *sp++ = nlen & 0xff;
3960
3961 nlen = (guint32) gl->end;
3962 *sp++ = (nlen >> 24) & 0xff;
3963 *sp++ = (nlen >> 16) & 0xff;
3964 *sp++ = (nlen >> 8) & 0xff;
3965 *sp++ = nlen & 0xff;
3966
3967 a = (guint16) gl->glyphs_used;
3968 *sp++ = (a >> 8) & 0xff;
3969 *sp++ = a & 0xff;
3970
3971 a = (guint16) gl->bbx.width;
3972 *sp++ = (a >> 8) & 0xff;
3973 *sp++ = a & 0xff;
3974
3975 a = (guint16) gl->bbx.x_offset;
3976 *sp++ = (a >> 8) & 0xff;
3977 *sp++ = a & 0xff;
3978
3979 a = (guint16) gl->bbx.ascent;
3980 *sp++ = (a >> 8) & 0xff;
3981 *sp++ = a & 0xff;
3982
3983 a = (guint16) gl->bbx.descent;
3984 *sp++ = (a >> 8) & 0xff;
3985 *sp++ = a & 0xff;
3986
3987 /*
3988 * Go through each glyph entry and encode the data.
3989 */
3990 for (i = 0, gp = gl->glyphs; i < gl->glyphs_used; i++, gp++) {
3991 /*
3992 * Encode the glyph encoding.
3993 */
3994 nlen = (guint32) gp->encoding;
3995 *sp++ = (nlen >> 24) & 0xff;
3996 *sp++ = (nlen >> 16) & 0xff;
3997 *sp++ = (nlen >> 8) & 0xff;
3998 *sp++ = nlen & 0xff;
3999
4000 /*
4001 * Encode the glyph device width.
4002 */
4003 a = (guint16) gp->dwidth;
4004 *sp++ = (a >> 8) & 0xff;
4005 *sp++ = a & 0xff;
4006
4007 /*
4008 * Encode the glyph name length.
4009 */
4010 nlen = (gp->name) ? (guint32) (strlen(gp->name) + 1) : 0;
4011 a = (guint16) nlen;
4012 *sp++ = (a >> 8) & 0xff;
4013 *sp++ = a & 0xff;
4014
4015 /*
4016 * Encode the four bounding box values needed.
4017 */
4018 a = (guint16) gp->bbx.width;
4019 *sp++ = (a >> 8) & 0xff;
4020 *sp++ = a & 0xff;
4021
4022 a = (guint16) gp->bbx.x_offset;
4023 *sp++ = (a >> 8) & 0xff;
4024 *sp++ = a & 0xff;
4025
4026 a = (guint16) gp->bbx.ascent;
4027 *sp++ = (a >> 8) & 0xff;
4028 *sp++ = a & 0xff;
4029
4030 a = (guint16) gp->bbx.descent;
4031 *sp++ = (a >> 8) & 0xff;
4032 *sp++ = a & 0xff;
4033
4034 /*
4035 * Encode the name if it exists.
4036 */
4037 if (nlen > 0) {
4038 (void) memcpy((char *) sp, gp->name, nlen);
4039 sp += nlen;
4040 }
4041
4042 /*
4043 * Encode the bitmap.
4044 */
4045 if (gp->bytes > 0) {
4046 (void) memcpy((char *) sp, (char *) gp->bitmap, gp->bytes);
4047 sp += gp->bytes;
4048 }
4049
4050 /*
4051 * Encode the PSF Unicode mappings. Even if there aren't any, add
4052 * the encoding.
4053 */
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;
4060 }
4061 }
4062
4063 /*
4064 * Return the selection encoded as a byte stream.
4065 */
4066 return sel;
4067 }
4068
4069 #define GETSHORT(s) ((s[0] << 8) | s[1])
4070 #define GETLONG(s) ((s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3])
4071
4072 static void
fontgrid_decode_selection(Fontgrid * fw,guchar * sel)4073 fontgrid_decode_selection(Fontgrid *fw, guchar *sel)
4074 {
4075 guint32 i, range, nlen;
4076 bdf_glyph_t *gp;
4077 bdf_glyphlist_t *gl;
4078
4079 if (sel == 0)
4080 return;
4081
4082 gl = &fw->clipboard;
4083
4084 /*
4085 * Clear out the bitmaps and names from the existing glyphs.
4086 */
4087 for (gp = gl->glyphs, i = 0; i < gl->glyphs_size; i++, gp++) {
4088 if (gp->name != 0)
4089 free(gp->name);
4090 if (gp->bytes > 0)
4091 free((char *) gp->bitmap);
4092 }
4093
4094 /*
4095 * Extract the glyph list bits per pixel.
4096 */
4097 gl->bpp = GETSHORT(sel);
4098 sel += 2;
4099
4100 /*
4101 * Extract the glyph list starting and ending encodings.
4102 */
4103 gl->start = (int) GETLONG(sel);
4104 sel += 4;
4105
4106 gl->end = (int) GETLONG(sel);
4107 sel += 4;
4108
4109 /*
4110 * Extract the number of encoded glyphs.
4111 */
4112 range = (guint32) GETSHORT(sel);
4113 sel += 2;
4114
4115 /*
4116 * Resize the internal glyph list clipboard if necessary.
4117 */
4118 if (range > gl->glyphs_size) {
4119 if (gl->glyphs_size == 0)
4120 gl->glyphs = (bdf_glyph_t *) malloc(sizeof(bdf_glyph_t) * range);
4121 else
4122 gl->glyphs = (bdf_glyph_t *) realloc((char *) gl->glyphs,
4123 sizeof(bdf_glyph_t) * range);
4124 gl->glyphs_size = range;
4125 }
4126
4127 /*
4128 * Initialize the glyph list.
4129 */
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);
4133
4134 gl->glyphs_used = range;
4135
4136 /*
4137 * Decode the overall metrics of the glyph list.
4138 */
4139 gl->bbx.width = GETSHORT(sel);
4140 sel += 2;
4141 gl->bbx.x_offset = GETSHORT(sel);
4142 sel += 2;
4143 gl->bbx.ascent = GETSHORT(sel);
4144 sel += 2;
4145 gl->bbx.descent = GETSHORT(sel);
4146 sel += 2;
4147 gl->bbx.height = gl->bbx.ascent + gl->bbx.descent;
4148 gl->bbx.y_offset = -gl->bbx.descent;
4149
4150 /*
4151 * Decode the glyphs.
4152 */
4153 for (i = 0, gp = gl->glyphs; i < range; i++, gp++) {
4154 /*
4155 * Get the glyph encoding.
4156 */
4157 gp->encoding = (int) GETLONG(sel);
4158 sel += 4;
4159
4160 /*
4161 * Get the device width.
4162 */
4163 gp->dwidth = GETSHORT(sel);
4164 sel += 2;
4165
4166 /*
4167 * Get the name length.
4168 */
4169 nlen = GETSHORT(sel);
4170 sel += 2;
4171
4172 /*
4173 * Get the bounding box.
4174 */
4175 gp->bbx.width = GETSHORT(sel);
4176 sel += 2;
4177 gp->bbx.x_offset = GETSHORT(sel);
4178 sel += 2;
4179 gp->bbx.ascent = GETSHORT(sel);
4180 sel += 2;
4181 gp->bbx.descent = GETSHORT(sel);
4182 sel += 2;
4183 gp->bbx.height = gp->bbx.ascent + gp->bbx.descent;
4184 gp->bbx.y_offset = -gp->bbx.descent;
4185
4186 /*
4187 * Get the name.
4188 */
4189 if (nlen > 0) {
4190 gp->name = (char *) malloc(nlen);
4191 (void) memcpy(gp->name, (char *) sel, nlen);
4192 sel += nlen;
4193 }
4194
4195 /*
4196 * Get the bitmap.
4197 */
4198
4199 switch (gl->bpp) {
4200 case 1:
4201 gp->bytes = ((gp->bbx.width + 7) >> 3) * gp->bbx.height;
4202 break;
4203 case 2:
4204 gp->bytes = (((gp->bbx.width << 1) + 7) >> 3) * gp->bbx.height;
4205 break;
4206 case 4:
4207 gp->bytes = (((gp->bbx.width << 2) + 7) >> 3) * gp->bbx.height;
4208 break;
4209 case 8:
4210 gp->bytes = gp->bbx.width * gp->bbx.height;
4211 break;
4212 }
4213
4214 if (gp->bytes > 0) {
4215 gp->bitmap = (unsigned char *) malloc(gp->bytes);
4216 (void) memcpy((char *) gp->bitmap, (char *) sel, gp->bytes);
4217 sel += gp->bytes;
4218 }
4219
4220 /*
4221 * Get the Unicode mappings.
4222 */
4223 gp->unicode.map_used = GETSHORT(sel);
4224 sel += 2;
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;
4232 }
4233 }
4234 }
4235
4236 /*
4237 * This function assumes the fontgrid is realized so a GdkWindow exists.
4238 */
4239 void
fontgrid_copy_selection(Fontgrid * fw)4240 fontgrid_copy_selection(Fontgrid *fw)
4241 {
4242 GtkWidget *w;
4243 GdkWindow *win;
4244 guint32 bytes;
4245 guchar *sel;
4246
4247 g_return_if_fail(fw != 0);
4248
4249 w = GTK_WIDGET(fw);
4250
4251 /*
4252 * Make sure the widget owns the clipboard property.
4253 */
4254 if ((win = gdk_selection_owner_get(FONTGRID_CLIPBOARD)) == 0 ||
4255 win != w->window)
4256 gdk_selection_owner_set(w->window, FONTGRID_CLIPBOARD, GDK_CURRENT_TIME,
4257 FALSE);
4258
4259 /*
4260 * Encode the selection as a byte stream for the clipboard.
4261 */
4262 if ((sel = fontgrid_encode_selection(fw, &bytes)) == 0)
4263 return;
4264
4265 gdk_property_change(w->window, FONTGRID_CLIPBOARD, FONTGRID_GLYPHLIST,
4266 8, GDK_PROP_MODE_REPLACE, sel, (gint) bytes);
4267
4268 /*
4269 * Free the data because the property now has control over it.
4270 */
4271 g_free(sel);
4272 }
4273
4274 void
fontgrid_cut_selection(Fontgrid * fw)4275 fontgrid_cut_selection(Fontgrid *fw)
4276 {
4277 gint32 code, start, end;
4278 bdf_glyph_t *gp;
4279 FontgridInternalPageInfo *pi;
4280 FontgridModificationInfo minfo;
4281 FontgridSelectionInfo sinfo;
4282
4283 g_return_if_fail(fw != 0);
4284
4285 fontgrid_copy_selection(fw);
4286
4287 pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
4288 code = pi->sel_start;
4289
4290 if (bdf_delete_glyphs(fw->font, pi->sel_start, pi->sel_end,
4291 fw->unencoded)) {
4292 start = pi->sel_start;
4293 end = pi->sel_end;
4294
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);
4299
4300 /*
4301 * Set up and emit the modified signal.
4302 */
4303 minfo.reason = FONTGRID_GLYPHS_DELETED;
4304 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
4305
4306 /*
4307 * Set up and call the selection start signal.
4308 */
4309 gp = (!fw->unencoded) ?
4310 fontgrid_locate_glyph(fw->font->glyphs, fw->font->glyphs_used,
4311 code, TRUE) :
4312 fontgrid_locate_glyph(fw->font->unencoded,
4313 fw->font->unencoded_used, code, TRUE);
4314 if (gp == 0) {
4315 empty_glyph.encoding = code;
4316 gp = &empty_glyph;
4317 }
4318
4319 sinfo.glyphs = gp;
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,
4326 &sinfo);
4327 }
4328 }
4329
4330 void
fontgrid_paste_selection(Fontgrid * fw,FontgridPasteType paste_type)4331 fontgrid_paste_selection(Fontgrid *fw, FontgridPasteType paste_type)
4332 {
4333 GtkWidget *w = GTK_WIDGET(fw);
4334 GdkWindow *win;
4335 GdkAtom atype;
4336 gint afmt, nitems, unenc, doresize;
4337 gint32 i;
4338 unsigned int ng;
4339 guchar *data;
4340 bdf_font_t *font;
4341 bdf_glyph_t *gp;
4342 bdf_glyphlist_t *gl;
4343 FontgridInternalPageInfo *pi;
4344 bdf_glyphlist_t overflow;
4345 FontgridModificationInfo minfo;
4346 FontgridSelectionInfo sinfo;
4347
4348 g_return_if_fail(fw != 0);
4349 g_return_if_fail(GTK_WIDGET_REALIZED(w));
4350
4351 if ((win = gdk_selection_owner_get(FONTGRID_CLIPBOARD)) == 0) {
4352 gdk_selection_owner_set(w->window, FONTGRID_CLIPBOARD,
4353 GDK_CURRENT_TIME, FALSE);
4354 /*
4355 * Return here because there was no owner of the selection.
4356 */
4357 return;
4358 }
4359
4360 doresize = 0;
4361 unenc = fw->unencoded;
4362
4363 pi = (!unenc) ? &fw->npage : &fw->upage;
4364
4365 nitems = 0;
4366 (void) gdk_property_get(win, FONTGRID_CLIPBOARD, FONTGRID_GLYPHLIST,
4367 0, 102400, FALSE, &atype, &afmt, &nitems, &data);
4368
4369 /*
4370 * Attempt to own the clipboard after getting the value if this widget
4371 * does not own it.
4372 */
4373 if (win != w->window)
4374 gdk_selection_owner_set(w->window, FONTGRID_CLIPBOARD, GDK_CURRENT_TIME,
4375 FALSE);
4376
4377 if (nitems > 0) {
4378 font = fw->font;
4379 gl = &fw->clipboard;
4380
4381 /*
4382 * Convert the encoded selection into a glyph list in the internal
4383 * glyph list clipboard.
4384 */
4385 fontgrid_decode_selection(fw, data);
4386
4387 /*
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.
4391 */
4392 if (unenc) {
4393 fontgrid_deselect_all(fw);
4394 pi->sel_start = font->unencoded_used;
4395 gl->start = 0;
4396 gl->end = gl->glyphs_used - 1;
4397 }
4398
4399 /*
4400 * Set the end point of the selection.
4401 */
4402 pi->sel_end = pi->sel_start + (gl->end - gl->start);
4403
4404 /*
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.
4410 */
4411 if (!unenc && pi->sel_end > 0xffff) {
4412 /*
4413 * Determine if any of the glyphs would actually get encoded after
4414 * 0xffff or if those are all empty glyphs.
4415 */
4416 for (ng = 0, gp = gl->glyphs; ng < gl->glyphs_used; ng++, gp++) {
4417 if (pi->sel_start + (gp->encoding - gl->start) > 0xffff)
4418 /*
4419 * The glyph list does contain glyphs that will overflow.
4420 */
4421 break;
4422 }
4423
4424 if (ng < gl->glyphs_used) {
4425 /*
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.
4430 */
4431 (void) memcpy((char *) &overflow.bbx, (char *) &gl->bbx,
4432 sizeof(bdf_bbx_t));
4433 overflow.bpp = font->bpp;
4434 overflow.glyphs_used = gl->glyphs_used - ng;
4435 overflow.glyphs = gp;
4436 overflow.start = 0;
4437 overflow.end = overflow.glyphs_used - 1;
4438
4439 /*
4440 * Add the glyphs to the unencoded area.
4441 */
4442 doresize = bdf_replace_glyphs(font, font->unencoded_used,
4443 &overflow, 1);
4444 }
4445
4446 /*
4447 * Adjust the glyph list and selection to fit within the 0xffff
4448 * limit before pasting the glyphs into the font.
4449 */
4450 gl->glyphs_used = ng;
4451 gl->end -= pi->sel_end - 0xffff;
4452 pi->sel_end = 0xffff;
4453 }
4454
4455 /*
4456 * If the grid is in insert mode, then determine if moving glyphs
4457 * forward from the insert location would cause an overflow.
4458 */
4459 if (!unenc &&
4460 (!fw->overwrite || paste_type == FONTGRID_INSERT_PASTE)) {
4461 doresize += bdf_insert_glyphs(font, pi->sel_start, gl);
4462 /*
4463 * Force a page recalculation to be done so the application can
4464 * update if needed.
4465 */
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);
4469 else
4470 doresize += bdf_replace_glyphs(font, pi->sel_start, gl, unenc);
4471
4472 /*
4473 * If the paste has more than one glyph, make sure the whole
4474 * range is selected.
4475 */
4476 for (i = pi->sel_start; i <= pi->sel_end; i++)
4477 Select(i, pi->selmap);
4478
4479 /*
4480 * If the incoming glyphs changed the font bounding box, then
4481 * determine the new geometry and attempt a resize.
4482 */
4483 if (doresize) {
4484 fontgrid_set_cell_geometry(fw);
4485 fontgrid_set_rows_cols(fw, 0);
4486 gtk_widget_queue_resize(w);
4487 } else
4488 fontgrid_draw_cells(w, pi->sel_start, pi->sel_end, TRUE, TRUE);
4489
4490 /*
4491 * Update the number of pages used.
4492 */
4493 if (unenc) {
4494 if (fw->noblanks) {
4495 if (font->unencoded_used == 0)
4496 pi->maxpage = 0;
4497 else {
4498 gp = font->unencoded + (font->unencoded_used - 1);
4499 pi->maxpage = gp->encoding / fw->pagesize;
4500 }
4501 }
4502 } else {
4503 if (fw->noblanks) {
4504 if (font->glyphs_used == 0)
4505 pi->maxpage = 0;
4506 else {
4507 gp = font->glyphs + (font->glyphs_used - 1);
4508 pi->maxpage = gp->encoding / fw->pagesize;
4509 }
4510 }
4511 }
4512
4513 /*
4514 * Set up and call the modified callback.
4515 */
4516 /*
4517 * Set up and emit the modified signal.
4518 */
4519 minfo.reason = FONTGRID_GLYPHS_PASTED;
4520 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
4521
4522 if (pi->sel_start == pi->sel_end) {
4523 /*
4524 * Set up and call the selection start signal.
4525 */
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,
4531 TRUE);
4532 if (gp == 0) {
4533 empty_glyph.encoding = pi->sel_start;
4534 gp = &empty_glyph;
4535 }
4536
4537 sinfo.glyphs = gp;
4538 sinfo.num_glyphs = 1;
4539 } else {
4540 sinfo.glyphs = 0;
4541 sinfo.num_glyphs = 0;
4542 }
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,
4549 &sinfo);
4550
4551 /*
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.
4555 */
4556 gdk_property_change(w->window, FONTGRID_CLIPBOARD,
4557 FONTGRID_GLYPHLIST, 8, GDK_PROP_MODE_REPLACE,
4558 data, (gint) nitems);
4559
4560 g_free((char *) data);
4561 }
4562 }
4563
4564 void
fontgrid_update_metrics(Fontgrid * fw,bdf_metrics_t * metrics)4565 fontgrid_update_metrics(Fontgrid *fw, bdf_metrics_t *metrics)
4566 {
4567 FontgridModificationInfo mi;
4568
4569 g_return_if_fail(fw != 0);
4570 g_return_if_fail(fw->font != 0);
4571
4572 if (bdf_set_font_bbx(fw->font, metrics)) {
4573 /*
4574 * Need to resize.
4575 */
4576
4577 /*
4578 * Calculate the cell geometry and the rows and columns.
4579 */
4580 fontgrid_set_cell_geometry(fw);
4581 fontgrid_set_rows_cols(fw, 0);
4582
4583 gtk_widget_queue_resize(GTK_WIDGET(fw));
4584
4585 mi.reason = FONTGRID_FONT_METRICS_MODIFIED;
4586 mi.name = 0;
4587 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &mi);
4588 }
4589 }
4590
4591 void
fontgrid_update_glyph(Fontgrid * fw,bdf_glyph_t * glyph,gboolean unencoded)4592 fontgrid_update_glyph(Fontgrid *fw, bdf_glyph_t *glyph, gboolean unencoded)
4593 {
4594 FontgridInternalPageInfo *pi;
4595 bdf_glyph_t *gp;
4596 bdf_glyphlist_t gl;
4597 FontgridModificationInfo mi;
4598
4599 g_return_if_fail(fw != 0);
4600 g_return_if_fail(fw->font != 0);
4601
4602 gl.bpp = fw->font->bpp;
4603 gl.start = gl.end = glyph->encoding;
4604 gl.glyphs = glyph;
4605 gl.glyphs_used = 1;
4606 memcpy((char *) &gl.bbx, (char *) &glyph->bbx, sizeof(bdf_bbx_t));
4607
4608 if (bdf_replace_glyphs(fw->font, glyph->encoding, &gl, unencoded)) {
4609 /*
4610 * The font geometry was changed by the glyph being pasted.
4611 * A resize will be needed.
4612 */
4613
4614 /*
4615 * Calculate the cell geometry and the rows and columns.
4616 */
4617 fontgrid_set_cell_geometry(fw);
4618 fontgrid_set_rows_cols(fw, 0);
4619
4620 gtk_widget_queue_resize(GTK_WIDGET(fw));
4621
4622 mi.reason = FONTGRID_FONT_METRICS_MODIFIED;
4623 mi.name = 0;
4624 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &mi);
4625 } else
4626 /*
4627 * Simply redraw the cells that were modified.
4628 */
4629 fontgrid_draw_cells(GTK_WIDGET(fw), glyph->encoding, glyph->encoding,
4630 TRUE, TRUE);
4631
4632 pi = (fw->unencoded) ? &fw->upage : &fw->npage;
4633 if (unencoded) {
4634 if (fw->noblanks) {
4635 if (fw->font->unencoded_used == 0)
4636 pi->maxpage = 0;
4637 else {
4638 gp = fw->font->unencoded + (fw->font->unencoded_used - 1);
4639 pi->maxpage = gp->encoding / fw->pagesize;
4640 }
4641 }
4642 } else {
4643 if (fw->noblanks) {
4644 if (fw->font->glyphs_used == 0)
4645 pi->maxpage = 0;
4646 else {
4647 gp = fw->font->glyphs + (fw->font->glyphs_used - 1);
4648 pi->maxpage = gp->encoding / fw->pagesize;
4649 }
4650 }
4651 }
4652
4653 mi.reason = FONTGRID_GLYPHS_MODIFIED;
4654 mi.name = 0;
4655 mi.start = mi.end = glyph->encoding;
4656 mi.unencoded = fw->unencoded;
4657 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &mi);
4658 }
4659
4660 void
fontgrid_update_psf_mappings(Fontgrid * fw,gint32 encoding,bdf_psf_unimap_t * mappings)4661 fontgrid_update_psf_mappings(Fontgrid *fw, gint32 encoding,
4662 bdf_psf_unimap_t *mappings)
4663 {
4664 FontgridModificationInfo mi;
4665
4666 g_return_if_fail(fw != 0);
4667 g_return_if_fail(fw->font != 0);
4668
4669 if (bdf_replace_mappings(fw->font, encoding, mappings, fw->unencoded)) {
4670 mi.reason = FONTGRID_PSF_MAPPINGS_MODIFIED;
4671 mi.name = 0;
4672 mi.start = mi.end = encoding;
4673 mi.unencoded = fw->unencoded;
4674 g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &mi);
4675 }
4676 }
4677
4678 gboolean
fontgrid_select_next_glyph(Fontgrid * fw,gint32 code)4679 fontgrid_select_next_glyph(Fontgrid *fw, gint32 code)
4680 {
4681 bdf_glyph_t *gp;
4682 gint32 pageno;
4683 guint32 count;
4684 FontgridInternalPageInfo *pi;
4685 FontgridSelectionInfo sinfo;
4686
4687 g_return_val_if_fail(fw != NULL, FALSE);
4688 g_return_val_if_fail(IS_FONTGRID(fw), FALSE);
4689
4690 if (!fw->unencoded) {
4691 pi = &fw->npage;
4692 gp = (fw->font && fw->font->glyphs_used) ?
4693 (fw->font->glyphs + (fw->font->glyphs_used - 1)) : 0;
4694 } else {
4695 pi = &fw->upage;
4696 gp = (fw->font && fw->font->unencoded_used) ?
4697 (fw->font->unencoded + (fw->font->unencoded_used - 1)) : 0;
4698 }
4699
4700 if ((count = fw->count) == 0)
4701 count = 1;
4702
4703 /*
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.
4706 */
4707 if ((fw->unencoded &&
4708 (gp == 0 || code == gp->encoding)) ||
4709 code == 0xffff) {
4710 gdk_beep();
4711 return FALSE;
4712 }
4713
4714 code += count;
4715
4716 if (fw->unencoded && code > gp->encoding)
4717 code = gp->encoding;
4718 else if (code > 0xffff)
4719 code = 0xffff;
4720
4721 fontgrid_deselect_all(fw);
4722
4723 pageno = code / fw->pagesize;
4724 if (pageno != pi->pageno) {
4725 fw->no_sel_callback = TRUE;
4726 fontgrid_goto_page(fw, pageno);
4727 }
4728
4729 pi->sel_start = pi->sel_end = code;
4730 Select(code, pi->selmap);
4731 fontgrid_draw_cells(GTK_WIDGET(fw), code, code, FALSE, TRUE);
4732
4733 /*
4734 * Reset the count.
4735 */
4736 fw->count = 0;
4737
4738 /*
4739 * Set up and emit the selection start signal.
4740 */
4741 if (!fw->unencoded)
4742 gp = fontgrid_locate_glyph(fw->font->glyphs, fw->font->glyphs_used,
4743 code, TRUE);
4744 else
4745 gp = fontgrid_locate_glyph(fw->font->unencoded, fw->font->unencoded_used,
4746 code, TRUE);
4747 if (gp == 0) {
4748 empty_glyph.encoding = code;
4749 gp = &empty_glyph;
4750 }
4751 sinfo.glyphs = gp;
4752 sinfo.num_glyphs = 1;
4753 sinfo.start = pi->sel_start;
4754 sinfo.end = pi->sel_end;
4755 sinfo.base = fw->base;
4756 sinfo.unencoded = fw->unencoded;
4757
4758 sinfo.reason = FONTGRID_START_SELECTION;
4759 g_signal_emit(G_OBJECT(fw), fontgrid_signals[SELECTION_START], 0,
4760 &sinfo);
4761 return TRUE;
4762 }
4763
4764 gboolean
fontgrid_select_previous_glyph(Fontgrid * fw,gint32 code)4765 fontgrid_select_previous_glyph(Fontgrid *fw, gint32 code)
4766 {
4767 bdf_glyph_t *gp;
4768 gint32 pageno;
4769 guint32 count;
4770 FontgridInternalPageInfo *pi;
4771 FontgridSelectionInfo sinfo;
4772
4773 g_return_val_if_fail(fw != NULL, FALSE);
4774 g_return_val_if_fail(IS_FONTGRID(fw), FALSE);
4775
4776 if (!fw->unencoded) {
4777 pi = &fw->npage;
4778 gp = (fw->font && fw->font->glyphs_used) ?
4779 (fw->font->glyphs + (fw->font->glyphs_used - 1)) : 0;
4780 } else {
4781 pi = &fw->upage;
4782 gp = (fw->font && fw->font->unencoded_used) ?
4783 (fw->font->unencoded + (fw->font->unencoded_used - 1)) : 0;
4784 }
4785
4786 if ((count = fw->count) == 0)
4787 count = 1;
4788
4789 if (code == 0) {
4790 gdk_beep();
4791 return FALSE;
4792 }
4793
4794 code -= count;
4795
4796 if (code < 0)
4797 code = 0;
4798
4799 fontgrid_deselect_all(fw);
4800
4801 pageno = code / fw->pagesize;
4802 if (pageno != pi->pageno) {
4803 fw->no_sel_callback = TRUE;
4804 fontgrid_goto_page(fw, pageno);
4805 }
4806
4807 pi->sel_start = pi->sel_end = code;
4808 Select(code, pi->selmap);
4809 fontgrid_draw_cells(GTK_WIDGET(fw), code, code, FALSE, TRUE);
4810
4811 /*
4812 * Reset the count.
4813 */
4814 fw->count = 0;
4815
4816 /*
4817 * Set up and emit the selection start signal.
4818 */
4819 if (!fw->unencoded)
4820 gp = fontgrid_locate_glyph(fw->font->glyphs, fw->font->glyphs_used,
4821 code, TRUE);
4822 else
4823 gp = fontgrid_locate_glyph(fw->font->unencoded, fw->font->unencoded_used,
4824 code, TRUE);
4825 if (gp == 0) {
4826 empty_glyph.encoding = code;
4827 gp = &empty_glyph;
4828 }
4829 sinfo.glyphs = gp;
4830 sinfo.num_glyphs = 1;
4831 sinfo.start = pi->sel_start;
4832 sinfo.end = pi->sel_end;
4833 sinfo.base = fw->base;
4834 sinfo.unencoded = fw->unencoded;
4835
4836 sinfo.reason = FONTGRID_START_SELECTION;
4837 g_signal_emit(G_OBJECT(fw), fontgrid_signals[SELECTION_START], 0,
4838 &sinfo);
4839 return TRUE;
4840 }
4841