4 #include <gdk/gdkkeysyms.h>
6 #include <gtkmathview/gtkmathview.h>
9 #define XLINK_NS_URI "http://www.w3.org/1999/xlink"
11 static GtkWidget* window;
12 static GtkWidget* main_area;
13 static GtkWidget* scrolled_area;
14 static GtkWidget* status_bar;
15 static GtkMenuItem* anti_aliasing_item;
16 static GtkMenuItem* transparency_item;
17 static GtkMenuItem* font_size_item;
18 static GdkCursor* normal_cursor;
19 static GdkCursor* link_cursor;
21 static gchar* doc_name = NULL;
22 static GdomeElement* root_selected = NULL;
23 static GdomeElement* first_selected = NULL;
24 static GdomeElement* last_selected = NULL;
25 static GdomeElement* cursor = NULL;
26 static gboolean selecting = FALSE;
27 static gboolean button_pressed = FALSE;
29 static guint statusbar_context;
31 static guint edit_timeout_id;
32 static GdomeElement* cursor_ptr = NULL;
33 static gboolean cursor_active = FALSE;
35 static void create_widget_set(gpointer);
36 static GtkWidget* get_main_menu(void);
37 static void options_selection_mode(GtkWidget*, guint);
38 static void options_font_size(GtkWidget*, guint);
39 static void options_verbosity(GtkWidget*, guint);
40 static void options_anti_aliasing(GtkWidget*, gpointer);
41 static void options_transparency(GtkWidget*, gpointer);
42 static void edit_delete_selection(GtkWidget*, gpointer);
43 static void edit_select_parent(GtkWidget*, gpointer);
44 static void help_about(GtkWidget*, gpointer);
46 extern int edit_timeout(gpointer);
47 extern void push_char(gpointer, gchar);
49 static GtkItemFactoryEntry menu_items[] = {
50 { "/_File", NULL, NULL, 0, "<Branch>" },
51 { "/File/_Quit", "<control>Q", gtk_main_quit, 0, NULL },
53 { "/_Edit", NULL, NULL, 0, "<Branch>" },
54 { "/Edit/Delete Selection", NULL, edit_delete_selection, 0, NULL },
55 { "/Edit/Select Parent", NULL, edit_select_parent, 0, NULL },
57 { "/_Options", NULL, NULL, 0, "<Branch>" },
58 { "/Options/_Selection Mode", NULL, NULL, 0, "<Branch>" },
59 { "/Options/Selection Mode/_Structure", NULL, options_selection_mode, 0, "<RadioItem>" },
60 { "/Options/Selection Mode/_Linear", NULL, options_selection_mode, 1, "/Options/Selection Mode/Structure" },
61 { "/Options/Default _Font Size", NULL, NULL, 0, "<Branch>" },
62 { "/Options/Default Font Size/8pt", NULL, options_font_size, 8, "<RadioItem>" },
63 { "/Options/Default Font Size/10pt", NULL, options_font_size, 10, "/Options/Default Font Size/8pt" },
64 { "/Options/Default Font Size/12pt", NULL, options_font_size, 12, "/Options/Default Font Size/8pt" },
65 { "/Options/Default Font Size/14pt", NULL, options_font_size, 14, "/Options/Default Font Size/8pt" },
66 { "/Options/Default Font Size/18pt", NULL, options_font_size, 18, "/Options/Default Font Size/8pt" },
67 { "/Options/Default Font Size/24pt", NULL, options_font_size, 24, "/Options/Default Font Size/8pt" },
68 { "/Options/Default Font Size/48pt", NULL, options_font_size, 48, "/Options/Default Font Size/8pt" },
69 { "/Options/Default Font Size/72pt", NULL, options_font_size, 72, "/Options/Default Font Size/8pt" },
70 { "/Options/Verbosity", NULL, NULL, 0, "<Branch>" },
71 { "/Options/Verbosity/_Errors", NULL, options_verbosity, 0, "<RadioItem>" },
72 { "/Options/Verbosity/_Warnings", NULL, options_verbosity, 1, "/Options/Verbosity/Errors" },
73 { "/Options/Verbosity/_Info", NULL, options_verbosity, 2, "/Options/Verbosity/Errors" },
74 { "/Options/Verbosity/_Debug", NULL, options_verbosity, 3, "/Options/Verbosity/Errors" },
75 { "/Options/sep1", NULL, NULL, 0, "<Separator>" },
76 { "/Options/_Anti Aliasing", NULL, options_anti_aliasing, 0, "<ToggleItem>" },
77 { "/Options/_Transparency", NULL, options_transparency, 0, "<ToggleItem>" },
79 { "/_Help" , NULL, NULL, 0, "<LastBranch>" },
80 { "/Help/About...", NULL, help_about, 0, NULL }
84 quick_message(const char* msg)
88 GtkWidget* okay_button;
90 /* Create the widgets */
92 dialog = gtk_dialog_new();
93 label = gtk_label_new (msg);
94 okay_button = gtk_button_new_with_label("OK");
96 gtk_widget_set_usize(dialog, 300, 100);
98 /* Ensure that the dialog box is destroyed when the user clicks ok. */
100 gtk_signal_connect_object (GTK_OBJECT (okay_button), "clicked",
101 GTK_SIGNAL_FUNC (gtk_widget_destroy), dialog);
102 gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->action_area),
105 /* Add the label, and show everything we've added to the dialog. */
107 gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), label);
108 gtk_widget_show_all (dialog);
112 load_error_msg(const char* name)
114 char* msg = g_strdup_printf("Could not load\n`%s'", name);
124 cursor_active = FALSE;
125 if (cursor_ptr != NULL &&
126 gtk_math_view_is_selected(main_area, cursor_ptr))
127 gtk_math_view_reset_selection(main_area, cursor_ptr);
136 cursor_active = FALSE;
137 if (cursor_ptr != NULL &&
138 !gtk_math_view_is_selected(main_area, cursor_ptr))
139 gtk_math_view_set_selection(main_area, cursor_ptr);
140 cursor_active = TRUE;
145 GUI_init(int* argc, char*** argv, char* title, guint width, guint height, gpointer context)
147 gtk_init(argc, argv);
149 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
150 gtk_window_set_title(GTK_WINDOW(window), title);
151 gtk_window_set_default_size(GTK_WINDOW(window), width, height);
152 gtk_signal_connect(GTK_OBJECT(window), "delete_event", (GtkSignalFunc) gtk_main_quit, NULL);
153 create_widget_set(context);
155 gtk_widget_show(window);
157 normal_cursor = gdk_cursor_new(GDK_TOP_LEFT_ARROW);
158 link_cursor = gdk_cursor_new(GDK_HAND2);
160 /*edit_timeout_id = gtk_timeout_add(400, edit_timeout, context);*/
166 gtk_timeout_remove(edit_timeout_id);
170 GUI_load_document(GdomeDocument* doc)
172 GtkMathView* math_view;
174 g_return_val_if_fail(doc != NULL, -1);
175 g_return_val_if_fail(main_area != NULL, -1);
176 g_return_val_if_fail(GTK_IS_MATH_VIEW(main_area), -1);
178 math_view = GTK_MATH_VIEW(main_area);
180 if (!gtk_math_view_load_doc(math_view, doc)) return -1;
186 GUI_load_uri(const char* uri)
188 GtkMathView* math_view;
190 g_return_val_if_fail(uri != NULL, -1);
191 g_return_val_if_fail(main_area != NULL, -1);
192 g_return_val_if_fail(GTK_IS_MATH_VIEW(main_area), -1);
194 math_view = GTK_MATH_VIEW(main_area);
196 if (!gtk_math_view_load_uri(math_view, uri)) return -1;
204 gtk_math_view_freeze(GTK_MATH_VIEW(main_area));
210 gtk_math_view_thaw(GTK_MATH_VIEW(main_area));
214 GUI_unload_document()
216 GtkMathView* math_view;
218 g_return_if_fail(main_area != NULL);
219 g_return_if_fail(GTK_IS_MATH_VIEW(main_area));
221 math_view = GTK_MATH_VIEW(main_area);
223 gtk_math_view_unload(math_view);
225 if (doc_name != NULL) g_free(doc_name);
228 gtk_statusbar_pop(GTK_STATUSBAR(status_bar), statusbar_context);
229 gtk_statusbar_push(GTK_STATUSBAR(status_bar), statusbar_context, "");
239 options_selection_mode(GtkWidget* widget, guint mode)
244 options_font_size(GtkWidget* widget, guint size)
246 GtkMathView* math_view;
248 g_return_if_fail(main_area != NULL);
249 g_return_if_fail(GTK_IS_MATH_VIEW(main_area));
251 math_view = GTK_MATH_VIEW(main_area);
253 gtk_math_view_set_font_size(math_view, size);
257 options_anti_aliasing(GtkWidget* widget, gpointer data)
259 gboolean aa = gtk_math_view_get_anti_aliasing(GTK_MATH_VIEW(main_area));
260 gtk_math_view_set_anti_aliasing(GTK_MATH_VIEW(main_area), !aa);
264 options_transparency(GtkWidget* widget, gpointer data)
266 gboolean t = gtk_math_view_get_transparency(GTK_MATH_VIEW(main_area));
267 gtk_math_view_set_transparency(GTK_MATH_VIEW(main_area), !t);
271 options_verbosity(GtkWidget* widget, guint level)
273 gtk_math_view_set_log_verbosity(GTK_MATH_VIEW(main_area), level);
277 edit_delete_selection(GtkWidget* widget, gpointer data)
279 if (root_selected != NULL)
282 gtk_math_view_freeze(GTK_MATH_VIEW(main_area));
283 printf("about to remove element %p\n", root_selected);
284 delete_element(root_selected);
285 gdome_el_unref(root_selected, &exc);
287 root_selected = NULL;
288 gtk_math_view_thaw(GTK_MATH_VIEW(main_area));
293 edit_select_parent(GtkWidget* widget, gpointer data)
295 if (root_selected != NULL)
297 GdomeException exc = 0;
298 GdomeElement* parent = gdome_cast_el(gdome_n_parentNode(root_selected, &exc));
300 gdome_el_unref(root_selected, &exc);
302 root_selected = parent;
303 gtk_math_view_set_selection(GTK_MATH_VIEW(main_area), root_selected);
308 help_about(GtkWidget* widget, gpointer data)
314 dialog = gtk_dialog_new();
315 label = gtk_label_new("\n MathML Viewer \n Copyright (C) 2000-2002 Luca Padovani \n");
316 ok = gtk_button_new_with_label("Close");
318 gtk_signal_connect_object (GTK_OBJECT (ok), "clicked",
319 GTK_SIGNAL_FUNC (gtk_widget_destroy), (gpointer) dialog);
320 gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->action_area),
323 gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), label);
325 gtk_widget_show_all (dialog);
329 #if defined(HAVE_GMETADOM)
331 element_changed(GtkMathView* math_view, GdomeElement* node)
334 GdomeDOMString* name;
335 GdomeDOMString* ns_uri;
337 g_return_if_fail(math_view != NULL);
338 g_return_if_fail(GTK_IS_MATH_VIEW(math_view));
340 name = gdome_str_mkref("href");
341 ns_uri = gdome_str_mkref(XLINK_NS_URI);
343 while (node != NULL && !gdome_el_hasAttributeNS(node, ns_uri, name, &exc))
344 node = gdome_cast_el(gdome_el_parentNode(node, &exc));
346 if (node != NULL && gdome_el_hasAttributeNS(node, ns_uri, name, &exc))
347 gdk_window_set_cursor(GTK_WIDGET(math_view)->window, link_cursor);
349 gdk_window_set_cursor(GTK_WIDGET(math_view)->window, normal_cursor);
351 gdome_str_unref(name);
352 gdome_str_unref(ns_uri);
357 #if defined(HAVE_GMETADOM)
358 action_changed(GtkMathView* math_view, GdomeElement* node)
361 g_return_if_fail(math_view != NULL);
362 g_return_if_fail(GTK_IS_MATH_VIEW(math_view));
366 #if defined(HAVE_GMETADOM)
367 selection_changed(GtkMathView* math_view, GdomeElement* node)
370 g_return_if_fail(math_view != NULL);
371 g_return_if_fail(GTK_IS_MATH_VIEW(math_view));
372 gtk_math_view_set_selection(math_view, node);
379 #if defined(HAVE_GMETADOM)
381 clicked(GtkMathView* math_view, gpointer user_data)
384 GdomeDOMString* name;
385 GdomeDOMString* ns_uri;
388 g_return_if_fail(math_view != NULL);
390 name = gdome_str_mkref("href");
391 ns_uri = gdome_str_mkref(XLINK_NS_URI);
393 p = gtk_math_view_get_element(math_view);
394 while (p != NULL && !gdome_el_hasAttributeNS(p, ns_uri, name, &exc))
395 p = gdome_cast_el(gdome_el_parentNode(p, &exc));
398 GdomeDOMString* href = gdome_el_getAttributeNS(p, ns_uri, name, &exc);
399 g_assert(href != NULL);
401 GUI_load_document(href->str);
402 gdome_str_unref(href);
403 } else if (gtk_math_view_get_action(math_view) != NULL)
404 gtk_math_view_action_toggle(math_view);
410 button_press_event(GtkWidget* widget,
411 GdkEventButton* event,
412 GtkMathView* math_view)
414 g_return_val_if_fail(event != NULL, FALSE);
415 g_return_val_if_fail(math_view != NULL, FALSE);
417 if (event->button == 1)
423 if (root_selected != NULL)
425 gtk_math_view_reset_selection(math_view, root_selected);
426 gdome_el_unref(root_selected, &exc);
428 root_selected = NULL;
431 if (first_selected != NULL)
433 gdome_el_unref(first_selected, &exc);
437 if (last_selected != NULL)
439 gdome_el_unref(last_selected, &exc);
441 last_selected = NULL;
444 first_selected = gtk_math_view_get_element_at(math_view, event->x, event->y);
445 button_pressed = TRUE;
453 motion_notify_event(GtkWidget* widget,
454 GdkEventMotion* event,
455 GtkMathView* math_view)
457 g_return_val_if_fail(event != NULL, FALSE);
458 g_return_val_if_fail(math_view != NULL, FALSE);
460 if (button_pressed && first_selected != NULL)
463 GdomeElement* el = gtk_math_view_get_element_at(math_view, event->x, event->y);
468 if (el != NULL && el != last_selected)
470 if (last_selected != NULL)
472 gdome_el_unref(last_selected, &exc);
479 if (last_selected != NULL)
481 root = find_common_ancestor(first_selected, last_selected);
482 g_assert(root != NULL);
484 if (root != root_selected)
486 gtk_math_view_freeze(math_view);
487 if (root_selected != NULL)
489 gtk_math_view_reset_selection(math_view, root_selected);
490 gdome_el_unref(root_selected, &exc);
493 root_selected = root;
494 gtk_math_view_set_selection(math_view, root_selected);
495 gtk_math_view_thaw(math_view);
499 gdome_el_unref(root, &exc);
509 button_release_event(GtkWidget* widget,
510 GdkEventButton* event,
511 GtkMathView* math_view)
513 g_return_val_if_fail(event != NULL, FALSE);
514 g_return_val_if_fail(math_view != NULL, FALSE);
516 if (event->button == 1)
520 cursor_ptr = first_selected;
524 button_pressed = FALSE;
532 key_press_event(gpointer context,
536 g_return_val_if_fail(widget != NULL, FALSE);
537 g_return_val_if_fail(event != NULL, FALSE);
538 g_return_val_if_fail(context != NULL, FALSE);
540 if (event->type != GDK_KEY_PRESS) return FALSE;
542 switch (event->keyval) {
559 case GDK_KP_Page_Down:
568 if (event->keyval < 0x80) push_char(context, event->keyval);
576 create_widget_set(gpointer context)
578 GtkWidget* main_vbox;
581 main_vbox = gtk_vbox_new(FALSE, 1);
582 gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
583 gtk_container_add(GTK_CONTAINER(window), main_vbox);
584 gtk_widget_show(main_vbox);
586 menu_bar = get_main_menu();
587 gtk_box_pack_start(GTK_BOX(main_vbox), menu_bar, FALSE, TRUE, 0);
588 gtk_widget_show(menu_bar);
590 main_area = gtk_math_view_new(NULL, NULL);
591 gtk_widget_show(main_area);
593 //gtk_math_view_set_log_verbosity(GTK_MATH_VIEW(main_area), 3);
596 gtk_signal_connect_object (GTK_OBJECT (main_area),
597 "selection_changed", GTK_SIGNAL_FUNC (selection_changed),
598 (gpointer) main_area);
600 gtk_signal_connect_object (GTK_OBJECT (main_area),
601 "element_changed", GTK_SIGNAL_FUNC (element_changed),
602 (gpointer) main_area);
604 gtk_signal_connect_object (GTK_OBJECT (main_area),
605 "action_changed", GTK_SIGNAL_FUNC (action_changed),
606 (gpointer) main_area);
608 gtk_signal_connect_object (GTK_OBJECT (main_area),
609 "clicked", GTK_SIGNAL_FUNC(clicked),
610 (gpointer) main_area);
613 gtk_signal_connect_object (GTK_OBJECT (main_area),
614 "button_press_event", GTK_SIGNAL_FUNC(button_press_event),
615 (gpointer) main_area);
617 gtk_signal_connect_object (GTK_OBJECT (main_area),
618 "button_release_event", GTK_SIGNAL_FUNC(button_release_event),
619 (gpointer) main_area);
621 gtk_signal_connect_object (GTK_OBJECT (main_area),
622 "motion_notify_event", GTK_SIGNAL_FUNC(motion_notify_event),
623 (gpointer) main_area);
625 gtk_signal_connect_object (GTK_OBJECT(window),
626 "key_press_event", GTK_SIGNAL_FUNC(key_press_event),
629 gtk_widget_add_events(GTK_WIDGET(main_area),
630 GDK_BUTTON_PRESS_MASK
631 | GDK_BUTTON_RELEASE_MASK
632 | GDK_POINTER_MOTION_MASK
633 | GDK_KEY_PRESS_MASK);
635 scrolled_area = gtk_scrolled_window_new(NULL, NULL);
636 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_area),
637 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
639 gtk_widget_show(scrolled_area);
640 gtk_container_add(GTK_CONTAINER(scrolled_area), main_area);
641 gtk_box_pack_start(GTK_BOX(main_vbox), scrolled_area, TRUE, TRUE, 0);
643 status_bar = gtk_statusbar_new();
644 gtk_widget_show(status_bar);
645 gtk_box_pack_start(GTK_BOX(main_vbox), status_bar, FALSE, TRUE, 0);
646 statusbar_context = gtk_statusbar_get_context_id(GTK_STATUSBAR(status_bar), "filename");
648 gtk_widget_show(main_vbox);
650 if (gtk_math_view_get_anti_aliasing(GTK_MATH_VIEW(main_area)))
651 gtk_menu_item_activate(anti_aliasing_item);
653 gtk_menu_item_activate(font_size_item);
659 GtkItemFactory* item_factory;
660 GtkAccelGroup* accel_group;
661 GtkWidget* menu_item;
663 gint nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
665 accel_group = gtk_accel_group_new();
667 item_factory = gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<main>", accel_group);
669 gtk_item_factory_create_items(item_factory, nmenu_items, menu_items, NULL);
671 gtk_window_add_accel_group(GTK_WINDOW(window), accel_group);
673 menu_item = gtk_item_factory_get_widget(item_factory, "/Options/Anti Aliasing");
674 anti_aliasing_item = GTK_MENU_ITEM(menu_item);
676 menu_item = gtk_item_factory_get_widget(item_factory, "/Options/Transparency");
677 transparency_item = GTK_MENU_ITEM(menu_item);
679 /* !!!BEWARE!!! the default font size must be kept aligned with the definition
680 * in math-engine-configuration.xml
682 menu_item = gtk_item_factory_get_widget(item_factory, "/Options/Default Font Size/12pt");
683 font_size_item = GTK_MENU_ITEM(menu_item);
685 return gtk_item_factory_get_widget(item_factory, "<main>");