2 * Copyright (C) 2000, Luca Padovani <luca.padovani@cs.unibo.it>.
4 * This file is part of GtkMathView, a Gtk widget for MathML.
6 * GtkMathView is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * GtkMathView is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GtkMathView; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 * For details, see the GtkMathView World-Wide-Web page,
21 * http://cs.unibo.it/~lpadovan/mml-widget, or send a mail to
22 * <luca.padovani@cs.unibo.it>
28 #include <gdk/gdkkeysyms.h>
30 #include <gtkmathview/gtkmathview.h>
33 #define XLINK_NS_URI "http://www.w3.org/1999/xlink"
35 static GtkWidget* window;
36 static GtkWidget* main_area;
37 static GtkWidget* scrolled_area;
38 static GtkWidget* status_bar;
39 static GtkMenuItem* anti_aliasing_item;
40 static GtkMenuItem* transparency_item;
41 static GdkCursor* normal_cursor;
42 static GdkCursor* link_cursor;
44 static gchar* doc_name = NULL;
45 static GdomeElement* root_selected = NULL;
47 static guint statusbar_context;
49 static void create_widget_set(gpointer);
50 static GtkWidget* get_main_menu(void);
51 static void file_open(GtkWidget*, gpointer);
52 static void file_re_open(GtkWidget*, gpointer);
53 static void file_close(GtkWidget*, gpointer);
54 static void options_font_manager(GtkWidget*, FontManagerId);
55 static void options_set_font_size(GtkWidget*, gpointer);
56 static void options_change_font_size(GtkWidget*, gboolean);
57 static void options_verbosity(GtkWidget*, guint);
58 static void options_anti_aliasing(GtkWidget*, gpointer);
59 static void options_transparency(GtkWidget*, gpointer);
60 static void selection_delete(GtkWidget*, gpointer);
61 static void selection_parent(GtkWidget*, gpointer);
62 static void selection_reset(GtkWidget*, gpointer);
63 static void help_about(GtkWidget*, gpointer);
65 static GtkItemFactoryEntry menu_items[] = {
66 { "/_File", NULL, NULL, 0, "<Branch>" },
67 { "/File/_Open...", "<control>O", file_open, 0, NULL },
68 { "/File/_Reopen", NULL, file_re_open, 0, NULL },
69 { "/File/_Close", "<control>W", file_close, 0, NULL },
70 { "/File/sep1", NULL, NULL, 0, "<Separator>" },
71 { "/File/_Quit", "<control>Q", gtk_main_quit, 0, NULL },
73 { "/_Selection", NULL, NULL, 0, "<Branch>" },
74 { "/Selection/Reset", NULL, selection_reset, 0, NULL },
75 { "/Selection/Delete", NULL, selection_delete, 0, NULL },
76 { "/Selection/Select Parent", NULL, selection_parent, 0, NULL },
78 { "/_Options", NULL, NULL, 0, "<Branch>" },
79 { "/Options/Default _Font Size", NULL, NULL, 0, "<Branch>" },
80 { "/Options/Default Font Size/Set...", NULL, options_set_font_size, 0, NULL },
81 { "/Options/Default Font Size/sep1", NULL, NULL, 0, "<Separator>" },
82 { "/Options/Default Font Size/Larger", NULL, options_change_font_size, TRUE, NULL },
83 { "/Options/Default Font Size/Smaller", NULL, options_change_font_size, FALSE, NULL },
84 { "/Options/Font Manager", NULL, NULL, 0, "<Branch>" },
85 { "/Options/Font Manager/_GTK", NULL, options_font_manager, FONT_MANAGER_GTK, "<RadioItem>" },
86 { "/Options/Font Manager/_Type 1", NULL, options_font_manager, FONT_MANAGER_T1, "/Options/Font Manager/GTK" },
87 { "/Options/Verbosity", NULL, NULL, 0, "<Branch>" },
88 { "/Options/Verbosity/_Errors", NULL, options_verbosity, 0, "<RadioItem>" },
89 { "/Options/Verbosity/_Warnings", NULL, options_verbosity, 1, "/Options/Verbosity/Errors" },
90 { "/Options/Verbosity/_Info", NULL, options_verbosity, 2, "/Options/Verbosity/Errors" },
91 { "/Options/Verbosity/_Debug", NULL, options_verbosity, 3, "/Options/Verbosity/Errors" },
92 { "/Options/sep1", NULL, NULL, 0, "<Separator>" },
93 { "/Options/_Anti Aliasing", NULL, options_anti_aliasing, 0, "<ToggleItem>" },
94 { "/Options/_Transparency", NULL, options_transparency, 0, "<ToggleItem>" },
96 { "/_Help" , NULL, NULL, 0, "<LastBranch>" },
97 { "/Help/About...", NULL, help_about, 0, NULL }
101 quick_message(const char* msg)
105 GtkWidget* okay_button;
107 /* Create the widgets */
109 dialog = gtk_dialog_new();
110 label = gtk_label_new (msg);
111 okay_button = gtk_button_new_with_label("OK");
113 gtk_widget_set_usize(dialog, 300, 100);
115 /* Ensure that the dialog box is destroyed when the user clicks ok. */
117 gtk_signal_connect_object (GTK_OBJECT (okay_button), "clicked",
118 GTK_SIGNAL_FUNC (gtk_widget_destroy), dialog);
119 gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->action_area),
122 /* Add the label, and show everything we've added to the dialog. */
124 gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), label);
125 gtk_widget_show_all (dialog);
129 load_error_msg(const char* name)
131 char* msg = g_strdup_printf("Could not load\n`%s'", name);
137 GUI_init(int* argc, char*** argv, char* title, guint width, guint height, gpointer context)
139 gtk_init(argc, argv);
141 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
142 gtk_window_set_title(GTK_WINDOW(window), title);
143 gtk_window_set_default_size(GTK_WINDOW(window), width, height);
144 gtk_signal_connect(GTK_OBJECT(window), "delete_event", (GtkSignalFunc) gtk_main_quit, NULL);
145 create_widget_set(context);
147 gtk_widget_show(window);
149 normal_cursor = gdk_cursor_new(GDK_TOP_LEFT_ARROW);
150 link_cursor = gdk_cursor_new(GDK_HAND2);
152 /*edit_timeout_id = gtk_timeout_add(400, edit_timeout, context);*/
161 GUI_load_document(GdomeDocument* doc)
163 GtkMathView* math_view;
165 g_return_val_if_fail(doc != NULL, -1);
166 g_return_val_if_fail(main_area != NULL, -1);
167 g_return_val_if_fail(GTK_IS_MATH_VIEW(main_area), -1);
169 math_view = GTK_MATH_VIEW(main_area);
171 if (!gtk_math_view_load_doc(math_view, doc)) return -1;
179 gtk_math_view_freeze(GTK_MATH_VIEW(main_area));
185 gtk_math_view_thaw(GTK_MATH_VIEW(main_area));
189 GUI_unload_document()
191 GtkMathView* math_view;
193 g_return_if_fail(main_area != NULL);
194 g_return_if_fail(GTK_IS_MATH_VIEW(main_area));
196 math_view = GTK_MATH_VIEW(main_area);
198 gtk_math_view_unload(math_view);
200 if (doc_name != NULL) g_free(doc_name);
203 gtk_statusbar_pop(GTK_STATUSBAR(status_bar), statusbar_context);
204 gtk_statusbar_push(GTK_STATUSBAR(status_bar), statusbar_context, "");
214 GUI_set_font_manager(FontManagerId id)
217 GtkMathView* math_view;
219 g_return_if_fail(id != FONT_MANAGER_UNKNOWN);
220 g_return_if_fail(main_area != NULL);
221 g_return_if_fail(GTK_IS_MATH_VIEW(main_area));
223 t1 = id == FONT_MANAGER_T1;
225 math_view = GTK_MATH_VIEW(main_area);
227 gtk_math_view_freeze(math_view);
229 if (id != gtk_math_view_get_font_manager_type(math_view))
230 gtk_math_view_set_font_manager_type(math_view, id);
232 gtk_widget_set_sensitive(anti_aliasing_item, t1);
233 gtk_widget_set_sensitive(transparency_item, t1);
237 gtk_math_view_set_anti_aliasing(math_view, GTK_CHECK_MENU_ITEM(anti_aliasing_item)->active);
238 gtk_math_view_set_transparency(math_view, GTK_CHECK_MENU_ITEM(transparency_item)->active);
241 gtk_math_view_thaw(math_view);
245 store_filename(GtkFileSelection* selector, GtkWidget* user_data)
247 gchar* selected_filename = gtk_file_selection_get_filename (GTK_FILE_SELECTION(user_data));
248 if (selected_filename != NULL)
249 GUI_load_document(selected_filename);
253 file_close(GtkWidget* widget, gpointer data)
255 GUI_unload_document();
259 file_re_open(GtkWidget* widget, gpointer data)
261 if (doc_name != NULL) {
262 GUI_load_document(doc_name);
267 file_open(GtkWidget* widget, gpointer data)
269 GtkWidget* fs = gtk_file_selection_new("Open File");
271 gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION(fs)->ok_button),
272 "clicked", GTK_SIGNAL_FUNC (store_filename), (gpointer) fs);
274 /* Ensure that the dialog box is destroyed when the user clicks a button. */
276 gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION(fs)->ok_button),
277 "clicked", GTK_SIGNAL_FUNC (gtk_widget_destroy),
280 gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION(fs)->cancel_button),
281 "clicked", GTK_SIGNAL_FUNC (gtk_widget_destroy),
284 /* Display that dialog */
286 gtk_widget_show (fs);
290 options_font_manager(GtkWidget* widget, FontManagerId id)
292 g_return_if_fail(id != FONT_MANAGER_UNKNOWN);
293 GUI_set_font_manager(id);
297 options_anti_aliasing(GtkWidget* widget, gpointer data)
299 gboolean aa = gtk_math_view_get_anti_aliasing(GTK_MATH_VIEW(main_area));
300 gtk_math_view_set_anti_aliasing(GTK_MATH_VIEW(main_area), !aa);
304 options_transparency(GtkWidget* widget, gpointer data)
306 gboolean t = gtk_math_view_get_transparency(GTK_MATH_VIEW(main_area));
307 gtk_math_view_set_transparency(GTK_MATH_VIEW(main_area), !t);
311 options_verbosity(GtkWidget* widget, guint level)
313 gtk_math_view_set_log_verbosity(GTK_MATH_VIEW(main_area), level);
317 selection_delete(GtkWidget* widget, gpointer data)
319 if (root_selected != NULL)
322 gtk_math_view_freeze(GTK_MATH_VIEW(main_area));
323 printf("about to remove element %p\n", root_selected);
324 delete_element(root_selected);
325 gdome_el_unref(root_selected, &exc);
327 root_selected = NULL;
328 gtk_math_view_thaw(GTK_MATH_VIEW(main_area));
333 selection_parent(GtkWidget* widget, gpointer data)
335 if (root_selected != NULL)
337 GdomeException exc = 0;
338 GdomeElement* parent = gdome_n_parentNode(root_selected, &exc);
340 gdome_el_unref(root_selected, &exc);
342 root_selected = parent;
343 /* gtk_math_view_set_selection(GTK_MATH_VIEW(main_area), root_selected); */
348 selection_reset(GtkWidget* widget, gpointer data)
350 if (root_selected != NULL)
352 GdomeException exc = 0;
353 /* gtk_math_view_reset_selection(GTK_MATH_VIEW(main_area), root_selected); */
354 gdome_el_unref(root_selected, &exc);
356 root_selected = NULL;
361 help_about(GtkWidget* widget, gpointer data)
367 dialog = gtk_dialog_new();
368 label = gtk_label_new("\n MathML Viewer \n Copyright (C) 2000-2003 Luca Padovani \n");
369 ok = gtk_button_new_with_label("Close");
371 gtk_signal_connect_object (GTK_OBJECT (ok), "clicked",
372 GTK_SIGNAL_FUNC (gtk_widget_destroy), (gpointer) dialog);
373 gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->action_area),
376 gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), label);
378 gtk_widget_show_all (dialog);
382 change_default_font_size(GtkSpinButton* widget, GtkSpinButton* spin)
384 g_return_if_fail(spin != NULL);
385 gtk_math_view_set_font_size( GTK_MATH_VIEW(main_area), gtk_spin_button_get_value_as_int(spin));
389 options_change_font_size(GtkWidget* widget, gboolean larger)
391 gfloat size = gtk_math_view_get_font_size (GTK_MATH_VIEW(main_area));
392 if (larger) size = size / 0.71;
393 else size = size * 0.71;
394 if (size < 1) size = 1;
395 gtk_math_view_set_font_size (GTK_MATH_VIEW(main_area), (gint) size + 0.5);
399 options_set_font_size(GtkWidget* widget, gpointer data)
408 dialog = gtk_dialog_new();
409 label = gtk_label_new("Default font size:");
410 ok = gtk_button_new_with_label("OK");
411 cancel = gtk_button_new_with_label("Cancel");
413 adj = gtk_adjustment_new (gtk_math_view_get_font_size (GTK_MATH_VIEW(main_area)), 1, 200, 1, 1, 1);
414 spin = gtk_spin_button_new (GTK_ADJUSTMENT(adj), 1, 0);
415 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spin), TRUE);
417 gtk_signal_connect (GTK_OBJECT (ok), "clicked",
418 GTK_SIGNAL_FUNC (change_default_font_size), (gpointer) spin);
420 gtk_signal_connect_object (GTK_OBJECT (ok), "clicked",
421 GTK_SIGNAL_FUNC (gtk_widget_destroy), (gpointer) dialog);
423 gtk_signal_connect_object (GTK_OBJECT (ok), "clicked",
424 GTK_SIGNAL_FUNC (gtk_widget_destroy), (gpointer) dialog);
426 gtk_signal_connect_object (GTK_OBJECT (cancel), "clicked",
427 GTK_SIGNAL_FUNC (gtk_widget_destroy), (gpointer) dialog);
429 gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), 5);
431 gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->action_area), ok);
432 gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->action_area), cancel);
433 gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), label);
434 gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), spin);
436 gtk_widget_show_all (dialog);
440 #if defined(HAVE_GMETADOM)
442 element_changed(GtkMathView* math_view, GdomeElement* elem)
444 GdomeDOMString* link = NULL;
446 g_return_if_fail(math_view != NULL);
447 g_return_if_fail(GTK_IS_MATH_VIEW(math_view));
449 /* printf("pointer is on %p\n", elem); */
451 link = find_hyperlink(elem, XLINK_NS_URI, "href");
453 gdk_window_set_cursor(GTK_WIDGET(math_view)->window, link_cursor);
455 gdk_window_set_cursor(GTK_WIDGET(math_view)->window, normal_cursor);
458 gdome_str_unref(link);
464 selection_changed(GtkMathView* math_view, GdomeElement* first, GdomeElement* last)
466 g_return_if_fail(math_view != NULL);
467 g_return_if_fail(GTK_IS_MATH_VIEW(math_view));
468 g_return_if_fail(first != NULL);
470 /* printf("selection changed %p %p\n", first, last); */
474 GdomeException exc = 0;
476 if (root_selected != NULL)
478 gdome_el_unref(root_selected, &exc);
482 root_selected = find_common_ancestor(first, last);
483 /* printf("selecting root %p\n", first, last, root_selected); */
484 /* gtk_math_view_set_selection(math_view, root_selected); */
490 #if defined(HAVE_GMETADOM)
492 clicked(GtkMathView* math_view, GdomeElement* elem)
495 GdomeDOMString* name;
496 GdomeDOMString* ns_uri;
499 g_return_if_fail(math_view != NULL);
501 /* printf("clicked on %p\n", elem); */
505 GdomeElement* action;
506 GdomeDOMString* href = find_hyperlink(elem, XLINK_NS_URI, "href");
509 /* printf("hyperlink %s\n", href->str); */
510 gdome_str_unref(href);
513 action = find_self_or_ancestor(elem, MATHML_NS_URI, "maction");
514 /* printf("action? %p\n", action); */
517 gtk_math_view_freeze(math_view);
518 action_toggle(action);
519 gtk_math_view_thaw(math_view);
520 gdome_el_unref(action, &exc);
529 key_press_event(gpointer context,
533 g_return_val_if_fail(widget != NULL, FALSE);
534 g_return_val_if_fail(event != NULL, FALSE);
535 g_return_val_if_fail(context != NULL, FALSE);
537 if (event->type != GDK_KEY_PRESS) return FALSE;
539 switch (event->keyval) {
556 case GDK_KP_Page_Down:
564 case GDK_BackSpace: push_char(context, event->keyval); break;
566 if (event->keyval < 0x80) push_char(context, event->keyval);
574 create_widget_set(gpointer context)
576 GtkWidget* main_vbox;
579 main_vbox = gtk_vbox_new(FALSE, 1);
580 gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
581 gtk_container_add(GTK_CONTAINER(window), main_vbox);
582 gtk_widget_show(main_vbox);
584 menu_bar = get_main_menu();
585 gtk_box_pack_start(GTK_BOX(main_vbox), menu_bar, FALSE, TRUE, 0);
586 gtk_widget_show(menu_bar);
588 main_area = gtk_math_view_new(NULL, NULL);
589 gtk_widget_show(main_area);
591 //gtk_math_view_set_log_verbosity(GTK_MATH_VIEW(main_area), 3);
594 gtk_signal_connect_object (GTK_OBJECT (main_area),
595 "selection_changed", GTK_SIGNAL_FUNC (selection_changed),
596 (gpointer) main_area);
598 gtk_signal_connect_object (GTK_OBJECT (main_area),
599 "element_changed", GTK_SIGNAL_FUNC (element_changed),
600 (gpointer) main_area);
602 gtk_signal_connect_object (GTK_OBJECT (main_area),
603 "action_changed", GTK_SIGNAL_FUNC (action_changed),
604 (gpointer) main_area);
606 gtk_signal_connect_object (GTK_OBJECT (main_area),
607 "clicked", GTK_SIGNAL_FUNC(clicked),
608 (gpointer) main_area);
611 gtk_signal_connect_object (GTK_OBJECT(window),
612 "key_press_event", GTK_SIGNAL_FUNC(key_press_event),
615 gtk_widget_add_events(GTK_WIDGET(main_area),
616 GDK_BUTTON_PRESS_MASK
617 | GDK_BUTTON_RELEASE_MASK
618 | GDK_POINTER_MOTION_MASK
619 | GDK_KEY_PRESS_MASK);
621 scrolled_area = gtk_scrolled_window_new(NULL, NULL);
622 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_area),
623 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
625 gtk_widget_show(scrolled_area);
626 gtk_container_add(GTK_CONTAINER(scrolled_area), main_area);
627 gtk_box_pack_start(GTK_BOX(main_vbox), scrolled_area, TRUE, TRUE, 0);
629 status_bar = gtk_statusbar_new();
630 gtk_widget_show(status_bar);
631 gtk_box_pack_start(GTK_BOX(main_vbox), status_bar, FALSE, TRUE, 0);
632 statusbar_context = gtk_statusbar_get_context_id(GTK_STATUSBAR(status_bar), "filename");
634 gtk_widget_show(main_vbox);
636 if (gtk_math_view_get_anti_aliasing(GTK_MATH_VIEW(main_area)))
637 gtk_menu_item_activate(anti_aliasing_item);
644 GtkWidget* main_vbox;
647 main_vbox = gtk_vbox_new(FALSE, 1);
648 gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
649 gtk_container_add(GTK_CONTAINER(window), main_vbox);
650 gtk_widget_show(main_vbox);
652 menu_bar = get_main_menu();
653 gtk_box_pack_start(GTK_BOX(main_vbox), menu_bar, FALSE, TRUE, 0);
654 gtk_widget_show(menu_bar);
656 main_area = gtk_math_view_new(NULL, NULL);
657 gtk_widget_show(main_area);
659 gtk_signal_connect_object (GTK_OBJECT (main_area),
660 "selection_changed", GTK_SIGNAL_FUNC (selection_changed),
661 (gpointer) main_area);
663 gtk_signal_connect_object (GTK_OBJECT (main_area),
664 "element_changed", GTK_SIGNAL_FUNC (element_changed),
665 (gpointer) main_area);
667 gtk_signal_connect_object (GTK_OBJECT (main_area),
668 "clicked", GTK_SIGNAL_FUNC(clicked),
669 (gpointer) main_area);
671 gtk_widget_add_events(GTK_WIDGET(main_area),
672 GDK_BUTTON_PRESS_MASK
673 | GDK_BUTTON_RELEASE_MASK
674 | GDK_POINTER_MOTION_MASK);
676 scrolled_area = gtk_scrolled_window_new(NULL, NULL);
677 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_area),
678 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
679 gtk_widget_show(scrolled_area);
680 gtk_container_add(GTK_CONTAINER(scrolled_area), main_area);
681 gtk_box_pack_start(GTK_BOX(main_vbox), scrolled_area, TRUE, TRUE, 0);
683 status_bar = gtk_statusbar_new();
684 gtk_widget_show(status_bar);
685 gtk_box_pack_start(GTK_BOX(main_vbox), status_bar, FALSE, TRUE, 0);
686 statusbar_context = gtk_statusbar_get_context_id(GTK_STATUSBAR(status_bar), "filename");
688 gtk_widget_show(main_vbox);
690 if (gtk_math_view_get_anti_aliasing(GTK_MATH_VIEW(main_area)))
691 gtk_menu_item_activate(anti_aliasing_item);
698 GtkItemFactory* item_factory;
699 GtkAccelGroup* accel_group;
700 GtkWidget* menu_item;
702 gint nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
704 accel_group = gtk_accel_group_new();
706 item_factory = gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<main>", accel_group);
708 gtk_item_factory_create_items(item_factory, nmenu_items, menu_items, NULL);
710 gtk_window_add_accel_group(GTK_WINDOW(window), accel_group);
712 menu_item = gtk_item_factory_get_widget(item_factory, "/Options/Anti Aliasing");
713 anti_aliasing_item = GTK_MENU_ITEM(menu_item);
715 menu_item = gtk_item_factory_get_widget(item_factory, "/Options/Transparency");
716 transparency_item = GTK_MENU_ITEM(menu_item);
718 return gtk_item_factory_get_widget(item_factory, "<main>");