]> git.kernelconcepts.de Git - gbdfed.git/blob - guiedit.c
Fixup several compile faults due to changes in recent distributions,
[gbdfed.git] / guiedit.c
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 "gbdfed.h"
24 #include "labcon.h"
25
26 /*
27  * The global glyphtest widget.
28  */
29 GtkWidget *glyphtest = 0;
30 static GtkWidget *gtest_dialog = 0;
31 static GtkWidget *gtest_erase = 0;
32
33 static void
34 guiedit_glyphtest_baseline(GtkWidget *w, gpointer data)
35 {
36     GtkToggleButton *tb;
37
38     tb = GTK_TOGGLE_BUTTON(w);
39     glyphtest_show_baseline(GLYPHTEST(glyphtest),
40                             gtk_toggle_button_get_active(tb));
41 }
42
43 static void
44 guiedit_glyphtest_direction(GtkWidget *w, gpointer data)
45 {
46     GtkToggleButton *tb;
47     gint dir;
48
49     tb = GTK_TOGGLE_BUTTON(w);
50     dir = gtk_toggle_button_get_active(tb) ?
51         GLYPHTEST_RIGHT_TO_LEFT : GLYPHTEST_LEFT_TO_RIGHT;
52     glyphtest_change_direction(GLYPHTEST(glyphtest), dir);
53 }
54
55 static void
56 guiedit_glyphtest_erase(GtkWidget *w, gpointer data)
57 {
58     glyphtest_erase(GLYPHTEST(glyphtest));
59
60     /*
61      * Disable the clear button until a glyph is added.
62      */
63     gtk_widget_set_sensitive(gtest_erase, FALSE);
64 }
65
66 static void
67 guiedit_glyphtest_enable_erase(GtkWidget *w, gpointer data)
68 {
69     /*
70      * Enable the clear button if a glyph is added.
71      */
72     gtk_widget_set_sensitive(gtest_erase, TRUE);
73 }
74
75 void
76 guiedit_show_glyphtest(GtkWidget *w, gpointer data)
77 {
78     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(data);
79     GtkWidget *hbox, *vbox, *frame, *cb;
80
81     if (gtest_dialog == 0) {
82         gtest_dialog = gtk_dialog_new();
83         (void) g_signal_connect(G_OBJECT(gtest_dialog),
84                                 "delete_event",
85                                 G_CALLBACK(gtk_widget_hide), 0);
86
87         vbox = gtk_vbox_new(FALSE, 0);
88
89         frame = gtk_frame_new("Test Glyphs");
90         gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN);
91
92         glyphtest = glyphtest_new();
93         (void) g_signal_connect(G_OBJECT(glyphtest), "add_glyph",
94                                 G_CALLBACK(guiedit_glyphtest_enable_erase),
95                                 0);
96         gtk_container_add(GTK_CONTAINER(frame), glyphtest);
97
98         gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, FALSE, 0);
99
100         hbox = gtk_hbox_new(FALSE, 0);
101         cb = gtk_check_button_new_with_label("Show Baseline");
102         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb), TRUE);
103         (void) g_signal_connect(G_OBJECT(cb), "toggled",
104                                 G_CALLBACK(guiedit_glyphtest_baseline),
105                                 0);
106         gtk_box_pack_start(GTK_BOX(hbox), cb, FALSE, FALSE, 2);
107         cb = gtk_check_button_new_with_label("Draw Right To Left");
108         (void) g_signal_connect(G_OBJECT(cb), "toggled",
109                                 G_CALLBACK(guiedit_glyphtest_direction),
110                                 0);
111         gtk_box_pack_start(GTK_BOX(hbox), cb, FALSE, FALSE, 2);
112
113         gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
114
115         gtk_container_add(GTK_CONTAINER(GTK_DIALOG(gtest_dialog)->vbox),
116                           vbox);
117
118         /*
119          * Add the buttons.
120          */
121         hbox = GTK_DIALOG(gtest_dialog)->action_area;
122
123         gtest_erase = gtk_button_new_with_label("Erase");
124         gtk_widget_set_sensitive(gtest_erase, FALSE);
125         (void) g_signal_connect(G_OBJECT(gtest_erase), "clicked",
126                                 G_CALLBACK(guiedit_glyphtest_erase), 0);
127         gtk_container_add(GTK_CONTAINER(hbox), gtest_erase);
128
129         cb = gtk_button_new_with_label("Close");
130         (void) g_signal_connect_object(G_OBJECT(cb), "clicked",
131                                        G_CALLBACK(gtk_widget_hide),
132                                        (gpointer) gtest_dialog,
133                                        G_CONNECT_SWAPPED);
134         gtk_container_add(GTK_CONTAINER(hbox), cb);
135         gtk_widget_show_all(GTK_DIALOG(gtest_dialog)->vbox);
136         gtk_widget_show_all(GTK_DIALOG(gtest_dialog)->action_area);
137     }
138
139     guiutil_show_dialog_centered(gtest_dialog, ed->shell);
140 }
141
142 void
143 guiedit_set_unicode_glyph_names(GtkWidget *w, gpointer data)
144 {
145     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(data);
146     FILE *in;
147
148     if (options.unicode_name_file == 0) {
149         guiutil_error_message(ed->shell,
150                               "Unicode Glyph Names: No file provided.");
151         return;
152     }
153
154     if ((in = fopen(options.unicode_name_file, "r")) == 0) {
155         sprintf(buffer1, "Unicode Glyph Names: Unable to open %s.",
156                 options.unicode_name_file);
157         guiutil_error_message(ed->shell, buffer1);
158     }
159
160     fontgrid_set_unicode_glyph_names(FONTGRID(ed->fgrid), in);
161
162     fclose(in);
163 }
164
165 void
166 guiedit_set_adobe_glyph_names(GtkWidget *w, gpointer data)
167 {
168     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(data);
169     FILE *in;
170
171     if (options.adobe_name_file == 0) {
172         guiutil_error_message(ed->shell,
173                               "Adobe Glyph Names: No file provided.");
174         return;
175     }
176
177     if ((in = fopen(options.adobe_name_file, "r")) == 0) {
178         sprintf(buffer1, "Adobe Glyph Names: Unable to open %s.",
179                 options.adobe_name_file);
180         guiutil_error_message(ed->shell, buffer1);
181     }
182
183     fontgrid_set_adobe_glyph_names(FONTGRID(ed->fgrid), in);
184
185     fclose(in);
186 }
187
188 void
189 guiedit_set_uni_glyph_names(GtkWidget *w, gpointer data)
190 {
191     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(data);
192
193     fontgrid_set_code_glyph_names(FONTGRID(ed->fgrid), 'u');
194 }
195
196 void
197 guiedit_set_zerox_glyph_names(GtkWidget *w, gpointer data)
198 {
199     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(data);
200
201     fontgrid_set_code_glyph_names(FONTGRID(ed->fgrid), 'x');
202 }
203
204 void
205 guiedit_set_uplus_glyph_names(GtkWidget *w, gpointer data)
206 {
207     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(data);
208
209     fontgrid_set_code_glyph_names(FONTGRID(ed->fgrid), '+');
210 }
211
212 void
213 guiedit_set_bslashu_glyph_names(GtkWidget *w, gpointer data)
214 {
215     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(data);
216
217     fontgrid_set_code_glyph_names(FONTGRID(ed->fgrid), '\\');
218 }
219
220 static void
221 guiedit_select_property(GtkTreeSelection *selection, gpointer data)
222 {
223     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(data);
224     gchar *prop_name;
225     bdf_font_t *font;
226     bdf_property_t *prop;
227     GtkToggleButton *tb;
228     gboolean from_font = TRUE;
229     GtkTreeModel *model;
230     GtkTreeIter iter;
231     GValue val;
232
233     /*
234      * This is called after the list is cleared as well, so return if there is
235      * no selection.
236      */
237     if (gtk_tree_selection_get_selected(selection, &model, &iter) == FALSE)
238       return;
239
240     font = fontgrid_get_font(FONTGRID(ed->fgrid));
241
242     (void) memset((char *) &val, 0, sizeof(GValue));
243
244     gtk_tree_model_get_value(model, &iter, 0, &val);
245     prop_name = (gchar *) g_value_get_string(&val);
246
247     if ((prop = bdf_get_font_property(font, prop_name)) == 0) {
248         from_font = FALSE;
249         prop = bdf_get_property(prop_name);
250     }
251
252     gtk_entry_set_text(GTK_ENTRY(ed->finfo_prop_name), prop_name);
253
254     g_value_unset(&val);
255
256     /*
257      * Always clear the property value field in case of ATOM properties with
258      * no actual value.
259      */
260     gtk_entry_set_text(GTK_ENTRY(ed->finfo_prop_value), "");
261
262     if (from_font) {
263         switch (prop->format) {
264           case BDF_ATOM:
265             if (prop->value.atom != 0)
266               gtk_entry_set_text(GTK_ENTRY(ed->finfo_prop_value),
267                                  prop->value.atom);
268             break;
269           case BDF_INTEGER:
270             sprintf(buffer1, "%d", prop->value.int32);
271             gtk_entry_set_text(GTK_ENTRY(ed->finfo_prop_value), buffer1);
272             break;
273           case BDF_CARDINAL:
274             sprintf(buffer1, "%d", prop->value.card32);
275             gtk_entry_set_text(GTK_ENTRY(ed->finfo_prop_value), buffer1);
276             break;
277         }
278     }
279
280     tb = GTK_TOGGLE_BUTTON(ed->finfo_prop_format[prop->format]);
281     gtk_toggle_button_set_active(tb, TRUE);
282
283     /*
284      * Change the sensitivity of the Delete button depending on whether the
285      * property was defined in the font or not.  If the property came from the
286      * font and is one of FONT_ASCENT or FONT_DESCENT, do not allow them to be
287      * deleted.
288      */
289     if (from_font && (strncmp(prop_name, "FONT_ASCENT", 11) == 0 ||
290                       strncmp(prop_name, "FONT_DESCENT", 12) == 0))
291       from_font = FALSE;
292     gtk_widget_set_sensitive(ed->finfo_delete_prop, from_font);
293
294     /*
295      * Always change the sensitivity of the Apply button to False when a
296      * property is selected.
297      */
298     gtk_widget_set_sensitive(ed->finfo_apply_prop, FALSE);
299 }
300
301 /*
302  * Called whenever a new font is loaded into this editor.
303  */
304 void
305 guiedit_update_font_info(gbdfed_editor_t *ed)
306 {
307     GtkToggleButton *tb;
308     GtkTextBuffer *text;
309     bdf_font_t *font;
310     guint32 i, nprops;
311     bdf_property_t *props;
312     GtkListStore *store;
313     GtkTreeIter iter;
314
315     /*
316      * Simply return if the editor's info dialog doesn't exist yet.
317      */
318     if (ed->finfo_dialog == 0)
319       return;
320
321     font = fontgrid_get_font(FONTGRID(ed->fgrid));
322
323     /*
324      * Set the dialog title.
325      */
326     if (ed->file == 0)
327       sprintf(buffer1, "(unnamed%d) Info Edit", ed->id);
328     else
329       sprintf(buffer1, "%s Info Edit", ed->file);
330     gtk_window_set_title(GTK_WINDOW(ed->finfo_dialog), buffer1);
331
332     /*
333      * Update the font properties.
334      */
335     store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ed->finfo_font_props)));
336     gtk_list_store_clear(store);
337
338     if ((nprops = bdf_font_property_list(font, &props)) > 0) {
339         for (i = 0; i < nprops; i++) {
340             gtk_list_store_append(store, &iter);
341             gtk_list_store_set(store, &iter, 0, props[i].name, -1);
342         }
343         free((char *) props);
344     }
345
346     /*
347      * Update the defined properties.
348      */
349     store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ed->finfo_all_props)));
350     gtk_list_store_clear(store);
351
352     if ((nprops = bdf_property_list(&props)) > 0) {
353         for (i = 0; i < nprops; i++) {
354             gtk_list_store_append(store, &iter);
355             gtk_list_store_set(store, &iter, 0, props[i].name, -1);
356         }
357         free((char *) props);
358     }
359
360     /*
361      * Clear the property name and value fields.
362      */
363     gtk_entry_set_text(GTK_ENTRY(ed->finfo_prop_name), "");
364     gtk_entry_set_text(GTK_ENTRY(ed->finfo_prop_value), "");
365
366     /*
367      * Turn off the property apply button until something gets edited.
368      */
369     gtk_widget_set_sensitive(ed->finfo_apply_prop, FALSE);
370
371     /*
372      * Update the font comments.
373      */
374     text = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ed->finfo_comments));
375     if (font && font->comments_len > 0)
376       gtk_text_buffer_set_text(text, font->comments, font->comments_len);
377     else
378       gtk_text_buffer_set_text(text, "", 0);
379
380     gtk_widget_set_sensitive(ed->finfo_apply_comments, FALSE);
381
382     /*
383      * Update the font spacing.
384      */
385     if (font)
386       tb = GTK_TOGGLE_BUTTON(ed->finfo_spacing[font->spacing >> 4]);
387     else
388       tb = GTK_TOGGLE_BUTTON(ed->finfo_spacing[options.font_opts.font_spacing >> 4]);
389     gtk_toggle_button_set_active(tb, TRUE);
390
391     /*
392      * Update the device width value.
393      */
394     gtk_widget_set_sensitive(ed->finfo_dwidth, TRUE);
395     if (font && font->spacing != BDF_PROPORTIONAL)
396       sprintf(buffer1, "%hd", font->monowidth);
397     else
398       (void) strcpy(buffer1, "0");
399     gtk_entry_set_text(GTK_ENTRY(ed->finfo_dwidth), buffer1);
400
401     if (font)
402       sprintf(buffer1, "%d", font->font_ascent);
403     else
404       sprintf(buffer1, "0");
405     gtk_entry_set_text(GTK_ENTRY(ed->finfo_ascent), buffer1);
406
407     if (font)
408       sprintf(buffer1, "%d", font->font_descent);
409     else
410       sprintf(buffer1, "0");
411     gtk_entry_set_text(GTK_ENTRY(ed->finfo_descent), buffer1);
412
413     if ((!font && options.font_opts.font_spacing == BDF_PROPORTIONAL) ||
414         font->spacing == BDF_PROPORTIONAL)
415       gtk_widget_set_sensitive(ed->finfo_dwidth, FALSE);
416
417     /*
418      * Finally, update the remaining information.
419      */
420     if (font)
421       sprintf(buffer1, "%d", font->glyphs_used);
422     else
423       sprintf(buffer1, "0");
424     gtk_label_set_text(GTK_LABEL(ed->finfo_enc_count), buffer1);
425
426     if (font)
427       sprintf(buffer1, "%d", font->unencoded_used);
428     else
429       sprintf(buffer1, "0");
430     gtk_label_set_text(GTK_LABEL(ed->finfo_unenc_count), buffer1);
431
432     if (font) {
433         gtk_spin_button_set_value(GTK_SPIN_BUTTON(ed->finfo_hres),
434                                   (gfloat) font->resolution_x);
435         gtk_spin_button_set_value(GTK_SPIN_BUTTON(ed->finfo_vres),
436                                   (gfloat) font->resolution_y);
437     }
438
439     if (font) {
440         switch (fontgrid_get_code_base(FONTGRID(ed->fgrid))) {
441           case 8: sprintf(buffer1, "%o", font->default_glyph); break;
442           case 10: sprintf(buffer1, "%d", font->default_glyph); break;
443           case 16: sprintf(buffer1, "%04x", font->default_glyph); break;
444         }
445         gtk_entry_set_text(GTK_ENTRY(ed->finfo_default_char), buffer1);
446     }
447
448     if (font)
449       sprintf(buffer1, "%hd", font->bpp);
450     else
451       sprintf(buffer1, "%d", options.font_opts.bits_per_pixel);
452     gtk_label_set_text(GTK_LABEL(ed->finfo_bpp), buffer1);
453
454     gtk_widget_set_sensitive(ed->finfo_apply_info, FALSE);
455 }
456
457 void
458 guiedit_update_code_base(gbdfed_editor_t *ed)
459 {
460     bdf_font_t *font;
461
462     if (ed->finfo_dialog == 0)
463       return;
464
465     font = fontgrid_get_font(FONTGRID(ed->fgrid));
466
467     switch (fontgrid_get_code_base(FONTGRID(ed->fgrid))) {
468       case 8: sprintf(buffer1, "%o", font->default_glyph); break;
469       case 10: sprintf(buffer1, "%d", font->default_glyph); break;
470       case 16: sprintf(buffer1, "%04x", font->default_glyph); break;
471     }
472     gtk_entry_set_text(GTK_ENTRY(ed->finfo_default_char), buffer1);
473 }
474
475 void
476 guiedit_update_font_details(gbdfed_editor_t *ed)
477 {
478     bdf_font_t *font;
479
480     if (ed->finfo_dialog == 0)
481       return;
482
483     font = fontgrid_get_font(FONTGRID(ed->fgrid));
484
485     sprintf(buffer1, "%d", font->glyphs_used);
486     gtk_label_set_text(GTK_LABEL(ed->finfo_enc_count), buffer1);
487     sprintf(buffer1, "%d", font->unencoded_used);
488     gtk_label_set_text(GTK_LABEL(ed->finfo_unenc_count), buffer1);
489 }
490
491 static void
492 enable_apply(GtkWidget *w, gpointer data)
493 {
494     gtk_widget_set_sensitive(w, TRUE);
495 }
496
497 static void
498 guiedit_enable_comment_buttons(GtkWidget *w, gpointer data)
499 {
500     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(data);
501
502     gtk_widget_set_sensitive(ed->finfo_erase_comments, TRUE);
503     gtk_widget_set_sensitive(ed->finfo_apply_comments, TRUE);
504 }
505
506 static void
507 guiedit_apply_property(GtkWidget *w, gpointer data)
508 {
509     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(data);
510     GtkToggleButton *tb;
511     gchar *v;
512     bdf_property_t prop;
513
514     /*
515      * Get the property info.
516      */
517     prop.name = (char *) gtk_entry_get_text(GTK_ENTRY(ed->finfo_prop_name));
518     tb = GTK_TOGGLE_BUTTON(ed->finfo_prop_format[BDF_ATOM]);
519     if (gtk_toggle_button_get_active(tb))
520       prop.format = BDF_ATOM;
521     tb = GTK_TOGGLE_BUTTON(ed->finfo_prop_format[BDF_INTEGER]);
522     if (gtk_toggle_button_get_active(tb))
523       prop.format = BDF_INTEGER;
524     tb = GTK_TOGGLE_BUTTON(ed->finfo_prop_format[BDF_CARDINAL]);
525     if (gtk_toggle_button_get_active(tb))
526       prop.format = BDF_CARDINAL;
527
528     v = (char *) gtk_entry_get_text(GTK_ENTRY(ed->finfo_prop_value));
529     switch (prop.format) {
530       case BDF_ATOM: prop.value.atom = v; break;
531       case BDF_INTEGER: prop.value.int32 = _bdf_atol(v, 0, 10); break;
532       case BDF_CARDINAL: prop.value.card32 = _bdf_atoul(v, 0, 10); break;
533     }
534
535     fontgrid_set_font_property(FONTGRID(ed->fgrid), &prop);
536
537     if (bdf_is_xlfd_property(prop.name))
538       ed->finfo_xlfd_props_modified = TRUE;
539
540     /*
541      * Turn the apply button back off.
542      */
543     gtk_widget_set_sensitive(ed->finfo_apply_prop, FALSE);
544 }
545
546 static void
547 guiedit_delete_property(GtkWidget *w, gpointer data)
548 {
549     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(data);
550     gchar *name;
551
552     name = (char *) gtk_entry_get_text(GTK_ENTRY(ed->finfo_prop_name));
553
554     fontgrid_delete_font_property(FONTGRID(ed->fgrid), name);
555
556     /*
557      * Make sure the Apply button is activated in case the delete was
558      * unintentional so the user can apply it again.
559      */
560     gtk_widget_set_sensitive(ed->finfo_apply_prop, TRUE);
561 }
562
563 static void
564 guiedit_erase_comments(GtkWidget *w, gpointer data)
565 {
566     GtkTextBuffer *text;
567     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(data);
568     gchar *comments;
569
570     fontgrid_set_font_comments(FONTGRID(ed->fgrid), 0);
571
572     /*
573      * Clear out the comments text widget.
574      */
575     text = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ed->finfo_comments));
576     gtk_text_buffer_set_text(text, "", 0);
577
578     /*
579      * Disable the Erase button until the next change in the comment text.
580      */
581     gtk_widget_set_sensitive(ed->finfo_erase_comments, FALSE);
582
583     /*
584      * If the font contains no comments either, disable the Apply button.  If
585      * it has comments, then enable the Apply button so that the existing
586      * comments can be removed if wanted.
587      */
588     if (fontgrid_get_font_comments(FONTGRID(ed->fgrid), &comments) == 0)
589       gtk_widget_set_sensitive(ed->finfo_apply_comments, FALSE);
590     else
591       gtk_widget_set_sensitive(ed->finfo_apply_comments, TRUE);
592
593     /*
594      * Force the focus back to the comments widget.
595      */
596     gtk_widget_grab_focus(ed->finfo_comments);
597 }
598
599 static void
600 guiedit_apply_comments(GtkWidget *w, gpointer data)
601 {
602     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(data);
603     gchar *comments;
604     GtkTextBuffer *text;
605     GtkTextIter start, end;
606
607     text = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ed->finfo_comments));
608     gtk_text_buffer_get_bounds(text, &start, &end);
609     comments = gtk_text_buffer_get_text(text, &start, &end, TRUE);
610
611     fontgrid_set_font_comments(FONTGRID(ed->fgrid), comments);
612
613     /*
614      * Disable the Apply button until the next change in the comment text.
615      */
616     gtk_widget_set_sensitive(ed->finfo_apply_comments, FALSE);
617
618     /*
619      * Force the focus back to the comments widget.
620      */
621     gtk_widget_grab_focus(ed->finfo_comments);
622 }
623
624 static void
625 guiedit_change_spacing(GtkWidget *w, gpointer data)
626 {
627     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(data);
628
629     /*
630      * Enable the device width input field depending on which radio button was
631      * toggled.
632      */
633     if (w == ed->finfo_spacing[BDF_PROPORTIONAL >> 4])
634       gtk_widget_set_sensitive(ed->finfo_dwidth, FALSE);
635     else
636       gtk_widget_set_sensitive(ed->finfo_dwidth, TRUE);
637
638     /*
639      * Enable the Apply button.
640      */
641     gtk_widget_set_sensitive(ed->finfo_apply_info, TRUE);
642 }
643
644 static void
645 guiedit_apply_details(GtkWidget *w, gpointer data)
646 {
647     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(data);
648     GtkToggleButton *tb;
649     const gchar *v;
650     bdf_property_t sp;
651     FontgridFontInfo finfo;
652
653     v = gtk_entry_get_text(GTK_ENTRY(ed->finfo_dwidth));
654     finfo.monowidth = (guint16) _bdf_atos((char *) v, 0, 10);
655     
656     /*
657      * Get the current spacing value.
658      */
659     finfo.spacing = 0;
660     tb = GTK_TOGGLE_BUTTON(ed->finfo_spacing[BDF_PROPORTIONAL >> 4]);
661     if (gtk_toggle_button_get_active(tb))
662       finfo.spacing = BDF_PROPORTIONAL;
663     tb = GTK_TOGGLE_BUTTON(ed->finfo_spacing[BDF_MONOWIDTH >> 4]);
664     if (gtk_toggle_button_get_active(tb))
665       finfo.spacing = BDF_MONOWIDTH;
666     tb = GTK_TOGGLE_BUTTON(ed->finfo_spacing[BDF_CHARCELL >> 4]);
667     if (gtk_toggle_button_get_active(tb))
668       finfo.spacing = BDF_CHARCELL;
669
670     /*
671      * Make sure a property gets added to the font as well so it
672      * gets saved in the event there is no XLFD name.
673      */
674     sp.name = "SPACING";
675     sp.format = BDF_ATOM;
676     switch (finfo.spacing) {
677       case BDF_PROPORTIONAL: sp.value.atom = "P"; break;
678       case BDF_MONOWIDTH: sp.value.atom = "M"; break;
679       case BDF_CHARCELL: sp.value.atom = "C"; break;
680     }
681     bdf_add_font_property(fontgrid_get_font(FONTGRID(ed->fgrid)), &sp);
682
683     /*
684      * Set the font spacing values on all of the visible glyph editors.
685      */
686     guigedit_set_font_spacing(finfo.spacing, finfo.monowidth);
687
688     /*
689      * Get the default character.
690      */
691     v = gtk_entry_get_text(GTK_ENTRY(ed->finfo_default_char));
692     finfo.default_char =
693         (glong) _bdf_atol((char *) v, 0,
694                           fontgrid_get_code_base(FONTGRID(ed->fgrid)));
695
696     finfo.resolution_x = (glong)
697         gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(ed->finfo_hres));
698     finfo.resolution_y = (glong)
699         gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(ed->finfo_vres));
700
701     v = gtk_entry_get_text(GTK_ENTRY(ed->finfo_ascent));
702     finfo.font_ascent = (glong) _bdf_atol((char *) v, 0, 10);
703     v = gtk_entry_get_text(GTK_ENTRY(ed->finfo_descent));
704     finfo.font_descent = (glong) _bdf_atol((char *) v, 0, 10);
705
706     /*
707      * Turn off the Apply button until something else changes.
708      */
709     gtk_widget_set_sensitive(ed->finfo_apply_info, FALSE);
710 }
711
712 static void
713 notebook_switch_page(GtkNotebook *nb, GtkNotebookPage *nbp, gint pageno,
714                      gpointer data)
715 {
716     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(data);
717
718     /*
719      * Whenever the comments page is shown, force the focus on the text
720      * widget.
721      */
722     if (pageno == 2)
723       gtk_widget_grab_focus(ed->finfo_comments);
724 }
725
726 #define CLINFOMSG "Font Info: Some XLFD properties were modified.\nDo you wish to update the font name with these changes?"
727
728 static void
729 close_finfo(GtkWidget *w, gint response, gpointer data)
730 {
731     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(data);
732
733     if (ed->finfo_xlfd_props_modified == TRUE) {
734         if (guiutil_yes_or_no(ed->finfo_dialog, CLINFOMSG, TRUE))
735           fontgrid_update_font_name_from_properties(FONTGRID(ed->fgrid));
736     }
737     ed->finfo_xlfd_props_modified = FALSE;
738
739     gtk_widget_hide(ed->finfo_dialog);
740 }
741
742 static void
743 finfo_sync_res(GtkWidget *w, GdkEventFocus *ev, gpointer data)
744 {
745     gfloat v;
746     GtkSpinButton *b;
747
748     b = GTK_SPIN_BUTTON(data);
749     v = (gfloat) gtk_spin_button_get_value(b);
750
751     if (v != (gfloat) gtk_spin_button_get_value(GTK_SPIN_BUTTON(w))) {
752         gtk_spin_button_set_value(GTK_SPIN_BUTTON(w), v);
753
754 #if 0
755         /*
756          * Enable the apply button.
757          */
758         gtk_widget_set_sensitive(pref_apply, TRUE);
759 #endif
760     }
761 }
762
763 void
764 guiedit_show_font_info(GtkWidget *w, gpointer data)
765 {
766     GtkWidget *hbox, *vbox, *frame, *label, *button, *table;
767     GtkWidget *nb, *vbox1, *hbox1, *swin, *image;
768     GtkTextBuffer *text;
769     GtkRadioButton *rb;
770     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(data);
771     bdf_font_t *font;
772     GtkListStore *store;
773     GtkTreeViewColumn *column;
774     GtkCellRenderer *cell_renderer;
775     GtkTreeSelection *sel;
776     GtkAdjustment *adj;
777     gint idx;
778
779     if (ed->finfo_dialog == 0) {
780         font = fontgrid_get_font(FONTGRID(ed->fgrid));
781
782         ed->finfo_dialog = gtk_dialog_new();
783
784         (void) g_signal_connect(G_OBJECT(ed->finfo_dialog),
785                                 "delete_event",
786                                 G_CALLBACK(gtk_widget_hide), 0);
787
788         nb = ed->finfo_notebook = gtk_notebook_new();
789
790         (void) g_signal_connect(G_OBJECT(nb), "switch_page",
791                                 G_CALLBACK(notebook_switch_page),
792                                 GUINT_TO_POINTER(ed->id));
793
794         /*
795          * Create the font info page.
796          */
797
798         /*
799          * Create the Apply button first so it can be used in callbacks
800          * for the data fields.
801          */
802         ed->finfo_apply_info = gtk_button_new_from_stock(GTK_STOCK_APPLY);
803         (void) g_signal_connect(G_OBJECT(ed->finfo_apply_info), "clicked",
804                                 G_CALLBACK(guiedit_apply_details),
805                                 GUINT_TO_POINTER(ed->id));
806
807         
808         vbox = gtk_vbox_new(FALSE, 0);
809
810         frame = gtk_frame_new("Glyph Counts");
811         gtk_container_set_border_width(GTK_CONTAINER(frame), 3);
812
813         hbox = gtk_hbox_new(FALSE, 0);
814         gtk_container_set_border_width(GTK_CONTAINER(hbox), 3);
815
816         ed->finfo_enc_count = gtk_label_new("0");
817         gtk_misc_set_alignment(GTK_MISC(ed->finfo_enc_count), 0.0, 0.5);
818         label = labcon_new_label_defaults("Encoded:",
819                                           ed->finfo_enc_count, 0);
820         gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 5);
821
822         ed->finfo_unenc_count = gtk_label_new("0");
823         gtk_misc_set_alignment(GTK_MISC(ed->finfo_unenc_count), 0.0, 0.5);
824         label = labcon_new_label_defaults("Unencoded:",
825                                           ed->finfo_unenc_count, 0);
826         gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 5);
827
828         gtk_container_add(GTK_CONTAINER(frame), hbox);
829
830         gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
831
832         frame = gtk_frame_new("Default Character");
833         gtk_container_set_border_width(GTK_CONTAINER(frame), 3);
834
835         hbox = gtk_hbox_new(FALSE, 0);
836         gtk_container_set_border_width(GTK_CONTAINER(hbox), 3);
837
838         ed->finfo_default_char = gtk_widget_new(gtk_entry_get_type(),
839                                                 "max_length", 4, NULL);
840         gtk_widget_set_size_request(ed->finfo_default_char, 75, -1);
841         g_signal_connect_object(G_OBJECT(ed->finfo_default_char), "changed",
842                                 G_CALLBACK(enable_apply),
843                                 (gpointer) ed->finfo_apply_info,
844                                 G_CONNECT_SWAPPED);
845         gtk_box_pack_start(GTK_BOX(hbox), ed->finfo_default_char,
846                            FALSE, FALSE, 0);
847         gtk_container_add(GTK_CONTAINER(frame), hbox);
848
849         gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
850
851         frame = gtk_frame_new("Font Spacing");
852         gtk_container_set_border_width(GTK_CONTAINER(frame), 3);
853
854         hbox = gtk_hbox_new(FALSE, 0);
855         gtk_container_set_border_width(GTK_CONTAINER(hbox), 3);
856
857         idx = BDF_PROPORTIONAL >> 4;
858
859         button = ed->finfo_spacing[idx] =
860             gtk_radio_button_new_with_label(0, "Proportional");
861         g_signal_connect(G_OBJECT(ed->finfo_spacing[idx]), "toggled",
862                          G_CALLBACK(guiedit_change_spacing),
863                          GUINT_TO_POINTER(ed->id));
864         gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
865
866         idx++;
867         rb = GTK_RADIO_BUTTON(button);
868         button = ed->finfo_spacing[idx] =
869             gtk_radio_button_new_with_label_from_widget(rb, "Monowidth");
870         g_signal_connect(G_OBJECT(ed->finfo_spacing[idx]), "toggled",
871                          G_CALLBACK(guiedit_change_spacing),
872                          GUINT_TO_POINTER(ed->id));
873         gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
874
875         idx++;
876         rb = GTK_RADIO_BUTTON(button);
877         button = ed->finfo_spacing[idx] =
878             gtk_radio_button_new_with_label_from_widget(rb, "Character Cell");
879         g_signal_connect(G_OBJECT(ed->finfo_spacing[idx]), "toggled",
880                          G_CALLBACK(guiedit_change_spacing),
881                          GUINT_TO_POINTER(ed->id));
882         gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
883
884         gtk_container_add(GTK_CONTAINER(frame), hbox);
885         gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
886
887         frame = gtk_frame_new("Font Resolution");
888         gtk_container_set_border_width(GTK_CONTAINER(frame), 3);
889
890         hbox = gtk_hbox_new(FALSE, 0);
891         gtk_container_set_border_width(GTK_CONTAINER(hbox), 3);
892
893         adj = (GtkAdjustment *) gtk_adjustment_new(0.0, 20.0, 1200.0,
894                                                    1.0, 10.0, 0.0);
895         ed->finfo_hres = gtk_spin_button_new(adj, 1.0, 0);
896         gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(ed->finfo_hres), TRUE);
897         gtk_widget_set_size_request(ed->finfo_hres, 75, -1);
898         g_signal_connect_object(G_OBJECT(ed->finfo_hres), "value-changed",
899                                 G_CALLBACK(enable_apply),
900                                 (gpointer) ed->finfo_apply_info,
901                                 G_CONNECT_SWAPPED);
902         label = labcon_new_label_defaults("Horizontal:", ed->finfo_hres, 0);
903         gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
904
905         adj = (GtkAdjustment *) gtk_adjustment_new(0.0, 20.0, 1200.0,
906                                                    1.0, 10.0, 0.0);
907         ed->finfo_vres = gtk_spin_button_new(adj, 1.0, 0);
908         gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(ed->finfo_vres), TRUE);
909         gtk_widget_set_size_request(ed->finfo_vres, 75, -1);
910         g_signal_connect_object(G_OBJECT(ed->finfo_vres), "value-changed",
911                                 G_CALLBACK(enable_apply),
912                                 (gpointer) ed->finfo_apply_info,
913                                 G_CONNECT_SWAPPED);
914         g_signal_connect(G_OBJECT(ed->finfo_vres), "focus-in-event",
915                          G_CALLBACK(finfo_sync_res),
916                          (gpointer) ed->finfo_hres);
917
918         label = labcon_new_label_defaults("Vertical:", ed->finfo_vres, label);
919         gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
920
921         ed->finfo_bpp = gtk_label_new("1");
922         label = labcon_new_label_defaults("Bits Per Pixel:", ed->finfo_bpp,
923                                           label);
924         gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
925
926         gtk_container_add(GTK_CONTAINER(frame), hbox);
927         gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
928
929         frame = gtk_frame_new("Font Metrics");
930         gtk_container_set_border_width(GTK_CONTAINER(frame), 3);
931
932         hbox = gtk_hbox_new(FALSE, 0);
933         gtk_container_set_border_width(GTK_CONTAINER(hbox), 3);
934
935         ed->finfo_dwidth = gtk_widget_new(gtk_entry_get_type(),
936                                           "max_length", 4, NULL);
937         gtk_widget_set_size_request(ed->finfo_dwidth, 75, -1);
938         g_signal_connect_object(G_OBJECT(ed->finfo_dwidth), "changed",
939                                 G_CALLBACK(enable_apply),
940                                 (gpointer) ed->finfo_apply_info,
941                                 G_CONNECT_SWAPPED);
942         label = labcon_new_label_defaults("Device Width:",
943                                           ed->finfo_dwidth, label);
944         gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
945
946         ed->finfo_ascent = gtk_widget_new(gtk_entry_get_type(),
947                                           "max_length", 4, NULL);
948         gtk_widget_set_size_request(ed->finfo_ascent, 75, -1);
949         g_signal_connect_object(G_OBJECT(ed->finfo_ascent), "changed",
950                                 G_CALLBACK(enable_apply),
951                                 (gpointer) ed->finfo_apply_info,
952                                 G_CONNECT_SWAPPED);
953         label = labcon_new_label_defaults("Font Ascent:", ed->finfo_ascent,
954                                           label);
955         gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
956
957         ed->finfo_descent = gtk_widget_new(gtk_entry_get_type(),
958                                            "max_length", 4, NULL);
959         gtk_widget_set_size_request(ed->finfo_descent, 75, -1);
960         g_signal_connect_object(G_OBJECT(ed->finfo_descent), "changed",
961                                 G_CALLBACK(enable_apply),
962                                 (gpointer) ed->finfo_apply_info,
963                                 G_CONNECT_SWAPPED);
964         label = labcon_new_label_defaults("Font Descent:",
965                                           ed->finfo_descent, label);
966         gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
967
968         gtk_container_add(GTK_CONTAINER(frame), hbox);
969
970         gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
971
972         /*
973          * Finally, add the Apply button.
974          */
975         gtk_box_pack_end(GTK_BOX(vbox), ed->finfo_apply_info, FALSE, FALSE, 5);
976
977         label = gtk_label_new("Font Info");
978         gtk_notebook_append_page(GTK_NOTEBOOK(nb), vbox, label);
979
980         /*
981          * Create the font properties editor.
982          */
983         vbox = gtk_vbox_new(FALSE, 5);
984
985         table = gtk_table_new(1, 2, TRUE);
986
987         swin = gtk_scrolled_window_new(0, 0);
988         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swin),
989                                        GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
990         gtk_container_set_border_width(GTK_CONTAINER(swin), 3);
991
992         store = gtk_list_store_new(1, G_TYPE_STRING);
993         ed->finfo_font_props =
994             gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
995         g_object_unref(store);
996
997         gtk_widget_set_size_request(ed->finfo_font_props, -1, 200);
998         gtk_container_add(GTK_CONTAINER(swin), ed->finfo_font_props);
999
1000         cell_renderer = gtk_cell_renderer_text_new();
1001         column = gtk_tree_view_column_new_with_attributes("Font Properties",
1002                                                           cell_renderer,
1003                                                           "text", 0,
1004                                                           NULL);
1005
1006         gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
1007         gtk_tree_view_append_column(GTK_TREE_VIEW(ed->finfo_font_props),
1008                                     column);
1009         sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(ed->finfo_font_props));
1010
1011         (void) g_signal_connect(G_OBJECT(sel), "changed",
1012                                 G_CALLBACK(guiedit_select_property),
1013                                 GUINT_TO_POINTER(ed->id));
1014
1015         gtk_table_attach(GTK_TABLE(table), swin, 0, 1, 0, 1,
1016                          GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 0, 0);
1017
1018         swin = gtk_scrolled_window_new(0, 0);
1019         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swin),
1020                                        GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
1021         gtk_container_set_border_width(GTK_CONTAINER(swin), 3);
1022
1023         store = gtk_list_store_new(1, G_TYPE_STRING);
1024         ed->finfo_all_props =
1025             gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
1026         g_object_unref(store);
1027
1028         gtk_widget_set_size_request(ed->finfo_all_props, -1, 200);
1029         gtk_container_add(GTK_CONTAINER(swin), ed->finfo_all_props);
1030
1031         cell_renderer = gtk_cell_renderer_text_new();
1032         column = gtk_tree_view_column_new_with_attributes("All Properties",
1033                                                           cell_renderer,
1034                                                           "text", 0,
1035                                                           NULL);
1036
1037         gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
1038         gtk_tree_view_append_column(GTK_TREE_VIEW(ed->finfo_all_props),
1039                                     column);
1040         sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(ed->finfo_all_props));
1041
1042         (void) g_signal_connect(G_OBJECT(sel), "changed",
1043                                 G_CALLBACK(guiedit_select_property),
1044                                 GUINT_TO_POINTER(ed->id));
1045
1046         gtk_table_attach(GTK_TABLE(table), swin, 1, 2, 0, 1,
1047                          GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 0, 0);
1048
1049         gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 2);
1050
1051         frame = gtk_frame_new("Property");
1052         gtk_container_set_border_width(GTK_CONTAINER(frame), 3);
1053
1054         vbox1 = gtk_vbox_new(FALSE, 5);
1055
1056         table = gtk_table_new(3, 2, FALSE);
1057
1058         label = gtk_label_new("Name:");
1059         gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
1060         gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1,
1061                          GTK_FILL, GTK_FILL, 5, 0);
1062
1063         label = gtk_label_new("Value:");
1064         gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
1065         gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2,
1066                          GTK_FILL, GTK_FILL, 5, 0);
1067
1068         label = gtk_label_new("Type:");
1069         gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
1070         gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3,
1071                          GTK_FILL, GTK_FILL, 5, 0);
1072
1073         ed->finfo_prop_name = gtk_entry_new();
1074         gtk_table_attach(GTK_TABLE(table), ed->finfo_prop_name, 1, 2, 0, 1,
1075                          GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 5);
1076
1077         ed->finfo_prop_value = gtk_entry_new();
1078         gtk_table_attach(GTK_TABLE(table), ed->finfo_prop_value, 1, 2, 1, 2,
1079                          GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 5);
1080
1081         hbox = gtk_hbox_new(FALSE, 2);
1082         button = ed->finfo_prop_format[BDF_ATOM] =
1083             gtk_radio_button_new_with_label(0, "String");
1084         gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1085         rb = GTK_RADIO_BUTTON(button);
1086         button = ed->finfo_prop_format[BDF_INTEGER] =
1087             gtk_radio_button_new_with_label_from_widget(rb, "Integer");
1088         gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1089         rb = GTK_RADIO_BUTTON(button);
1090         button = ed->finfo_prop_format[BDF_CARDINAL] =
1091             gtk_radio_button_new_with_label_from_widget(rb, "Cardinal");
1092         gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1093
1094         gtk_table_attach(GTK_TABLE(table), hbox, 1, 2, 2, 3,
1095                          GTK_FILL, GTK_FILL, 0, 0);
1096
1097         gtk_box_pack_start(GTK_BOX(vbox1), table, FALSE, FALSE, 0);
1098
1099         hbox = gtk_hbox_new(FALSE, 0);
1100
1101         hbox1 = gtk_hbox_new(FALSE, 0);
1102         label = gtk_label_new_with_mnemonic("_Apply To Font Properties");
1103         image = gtk_image_new_from_stock(GTK_STOCK_APPLY,
1104                                          GTK_ICON_SIZE_BUTTON);
1105         gtk_box_pack_start(GTK_BOX(hbox1), image, FALSE, FALSE, 0);
1106         gtk_box_pack_start(GTK_BOX(hbox1), label, FALSE, FALSE, 0);
1107
1108         button = ed->finfo_apply_prop = gtk_button_new();
1109         gtk_container_add(GTK_CONTAINER(button), hbox1);
1110
1111         (void) g_signal_connect(G_OBJECT(button), "clicked",
1112                                 G_CALLBACK(guiedit_apply_property),
1113                                 GUINT_TO_POINTER(ed->id));
1114
1115         gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 5);
1116
1117         (void) g_signal_connect_object(G_OBJECT(ed->finfo_prop_value),
1118                                        "changed",
1119                                        G_CALLBACK(enable_apply),
1120                                        (gpointer) button,
1121                                        G_CONNECT_SWAPPED);
1122
1123         button = ed->finfo_prop_format[BDF_ATOM];
1124         (void) g_signal_connect_object(G_OBJECT(button),
1125                                        "toggled",
1126                                        G_CALLBACK(enable_apply),
1127                                        (gpointer) ed->finfo_apply_prop,
1128                                        G_CONNECT_SWAPPED);
1129
1130         button = ed->finfo_prop_format[BDF_INTEGER];
1131         (void) g_signal_connect_object(G_OBJECT(button),
1132                                        "toggled",
1133                                        G_CALLBACK(enable_apply),
1134                                        (gpointer) ed->finfo_apply_prop,
1135                                        G_CONNECT_SWAPPED);
1136
1137         button = ed->finfo_prop_format[BDF_CARDINAL];
1138         (void) g_signal_connect_object(G_OBJECT(button),
1139                                        "toggled",
1140                                        G_CALLBACK(enable_apply),
1141                                        (gpointer) ed->finfo_apply_prop,
1142                                        G_CONNECT_SWAPPED);
1143
1144         hbox1 = gtk_hbox_new(FALSE, 0);
1145         label = gtk_label_new_with_mnemonic("_Delete From Font Properties");
1146         image = gtk_image_new_from_stock(GTK_STOCK_DELETE,
1147                                          GTK_ICON_SIZE_BUTTON);
1148         gtk_box_pack_start(GTK_BOX(hbox1), image, FALSE, FALSE, 0);
1149         gtk_box_pack_start(GTK_BOX(hbox1), label, FALSE, FALSE, 0);
1150
1151         button = ed->finfo_delete_prop = gtk_button_new();
1152         gtk_container_add(GTK_CONTAINER(button), hbox1);
1153
1154         (void) g_signal_connect(G_OBJECT(button), "clicked",
1155                                 G_CALLBACK(guiedit_delete_property),
1156                                 GUINT_TO_POINTER(ed->id));
1157
1158         gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 5);
1159
1160         gtk_box_pack_start(GTK_BOX(vbox1), hbox, FALSE, FALSE, 2);
1161
1162         gtk_container_add(GTK_CONTAINER(frame), vbox1);
1163
1164         gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 2);
1165
1166         label = gtk_label_new("Font Properties");
1167         gtk_notebook_append_page(GTK_NOTEBOOK(nb), vbox, label);
1168
1169         /*
1170          * Create the font comment editor.
1171          */
1172         frame = gtk_frame_new("Comments");
1173         gtk_container_set_border_width(GTK_CONTAINER(frame), 3);
1174
1175         table = gtk_table_new(2, 2, FALSE);
1176
1177         text = gtk_text_buffer_new(NULL);
1178         ed->finfo_comments = gtk_text_view_new_with_buffer(text);
1179         gtk_widget_set_size_request(ed->finfo_comments, 400, 200);
1180
1181         swin = gtk_scrolled_window_new(NULL, NULL);
1182         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swin),
1183                                        GTK_POLICY_NEVER,
1184                                        GTK_POLICY_ALWAYS);
1185         gtk_container_add(GTK_CONTAINER(swin), ed->finfo_comments);
1186         gtk_table_attach(GTK_TABLE(table), swin, 0, 1, 0, 1,
1187                          GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 5, 5);
1188
1189         hbox = gtk_hbox_new(FALSE, 0);
1190         button = ed->finfo_apply_comments =
1191             gtk_button_new_from_stock(GTK_STOCK_APPLY);
1192
1193         (void) g_signal_connect(G_OBJECT(button), "clicked",
1194                                 G_CALLBACK(guiedit_apply_comments),
1195                                 GUINT_TO_POINTER(ed->id));
1196         (void) g_signal_connect_data((gpointer) text,
1197                                      "changed",
1198                                      G_CALLBACK(guiedit_enable_comment_buttons),
1199                                      GUINT_TO_POINTER(ed->id), NULL, 0);
1200         gtk_container_add(GTK_CONTAINER(hbox), button);
1201
1202         button = ed->finfo_erase_comments =
1203             gtk_button_new_from_stock(GTK_STOCK_CLEAR);
1204
1205         (void) g_signal_connect(G_OBJECT(button), "clicked",
1206                                 G_CALLBACK(guiedit_erase_comments),
1207                                 GUINT_TO_POINTER(ed->id));
1208
1209         gtk_container_add(GTK_CONTAINER(hbox), button);
1210         gtk_table_attach(GTK_TABLE(table), hbox, 0, 2, 1, 2,
1211                          GTK_FILL, GTK_FILL, 0, 5);
1212         gtk_container_add(GTK_CONTAINER(frame), table);
1213
1214         label = gtk_label_new("Font Comments");
1215         gtk_notebook_append_page(GTK_NOTEBOOK(nb), frame, label);
1216
1217         gtk_container_add(GTK_CONTAINER(GTK_DIALOG(ed->finfo_dialog)->vbox),
1218                           nb);
1219
1220         /*
1221          * Add the buttons.
1222          */
1223         gtk_dialog_add_button(GTK_DIALOG(ed->finfo_dialog),
1224                               GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE);
1225
1226         g_signal_connect(G_OBJECT(ed->finfo_dialog), "response",
1227                          G_CALLBACK(close_finfo), GUINT_TO_POINTER(ed->id));
1228
1229         guiedit_update_font_info(ed);
1230
1231         gtk_widget_show_all(GTK_DIALOG(ed->finfo_dialog)->vbox);
1232         gtk_widget_show_all(GTK_DIALOG(ed->finfo_dialog)->action_area);
1233     }
1234
1235     /*
1236      * Center the dialog and show it.
1237      */
1238     guiutil_show_dialog_centered(ed->finfo_dialog, ed->shell);
1239 }
1240
1241 void
1242 guiedit_show_font_properties(GtkWidget *w, gpointer data)
1243 {
1244     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(data);
1245     guiedit_show_font_info(w, data);
1246     gtk_notebook_set_current_page(GTK_NOTEBOOK(ed->finfo_notebook), 1);
1247 }
1248
1249 void
1250 guiedit_show_font_comments(GtkWidget *w, gpointer data)
1251 {
1252     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(data);
1253     guiedit_show_font_info(w, data);
1254     gtk_notebook_set_current_page(GTK_NOTEBOOK(ed->finfo_notebook), 2);
1255 }
1256
1257 /*
1258  * Called when the font name is used to update the properties so the font info
1259  * editor list of properties is updated.
1260  */
1261 void
1262 guiedit_update_font_properties(gbdfed_editor_t *ed)
1263 {
1264     gchar *prop;
1265     guint32 i, nprops;
1266     bdf_font_t *font;
1267     bdf_property_t *props;
1268     GtkTreeModel *model;
1269     GtkTreeSelection *selection;
1270     GtkTreePath *row;
1271     GtkTreeView *tview;
1272     GtkTreeIter iter;
1273     GValue val;
1274
1275     /*
1276      * Update the font properties list if the font info dialog has been
1277      * created.
1278      */
1279     if (ed->finfo_dialog == 0)
1280       return;
1281
1282     font = fontgrid_get_font(FONTGRID(ed->fgrid));
1283
1284     /*
1285      * This will be the name of the currently selected property, if one
1286      * is selected.
1287      */
1288     prop = 0;
1289
1290     selection =
1291         gtk_tree_view_get_selection(GTK_TREE_VIEW(ed->finfo_font_props));
1292     if (gtk_tree_selection_get_selected(selection, &model, &iter) != FALSE) {
1293         memset((char *) &val, 0, sizeof(GValue));
1294         gtk_tree_model_get_value(model, &iter, 0, &val);
1295         prop = (gchar *) g_value_get_string(&val);
1296     }
1297
1298     /*
1299      * This will track the row that needs to be reselected once the list has
1300      * been updated.
1301      */
1302     row = 0;
1303
1304     gtk_list_store_clear(GTK_LIST_STORE(model));
1305
1306     if ((nprops = bdf_font_property_list(font, &props)) != 0) {
1307         for (i = 0; i < nprops; i++) {
1308             if (prop && strcmp(prop, props[i].name) == 0)
1309               row = gtk_tree_path_new_from_indices(i, -1);
1310             gtk_list_store_append(GTK_LIST_STORE(model), &iter);
1311             gtk_list_store_set(GTK_LIST_STORE(model), &iter,
1312                                0, props[i].name, -1);
1313         }
1314     }
1315
1316     if (row != 0) {
1317         gtk_tree_selection_select_path(selection, row);
1318
1319         /*
1320          * Make sure the selected property is made visible.
1321          */
1322         tview = gtk_tree_selection_get_tree_view(selection);
1323         gtk_tree_view_scroll_to_cell(tview, row, NULL, TRUE, 0.5, 0.5);
1324     }
1325
1326     /*
1327      * Make sure memory is deallocated when necessary.
1328      */
1329     if (prop != 0)
1330       g_value_unset(&val);
1331 }
1332
1333 void
1334 guiedit_copy_selection(GtkWidget *w, gpointer data)
1335 {
1336     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(data);
1337
1338     fontgrid_copy_selection(FONTGRID(ed->fgrid));
1339 }
1340
1341 void
1342 guiedit_cut_selection(GtkWidget *w, gpointer data)
1343 {
1344     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(data);
1345
1346     fontgrid_cut_selection(FONTGRID(ed->fgrid));
1347 }
1348
1349 void
1350 guiedit_paste_selection(GtkWidget *w, gpointer data)
1351 {
1352     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(data);
1353
1354     fontgrid_paste_selection(FONTGRID(ed->fgrid), FONTGRID_NORMAL_PASTE);
1355 }
1356
1357 void
1358 guiedit_overlay_selection(GtkWidget *w, gpointer data)
1359 {
1360     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(data);
1361
1362     fontgrid_paste_selection(FONTGRID(ed->fgrid), FONTGRID_OVERLAY_PASTE);
1363 }
1364
1365 void
1366 guiedit_insert_selection(GtkWidget *w, gpointer data)
1367 {
1368     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(data);
1369
1370     fontgrid_paste_selection(FONTGRID(ed->fgrid), FONTGRID_INSERT_PASTE);
1371 }