Port to GtkApplication
[gcalctool.git] / src / math-window.c
blob7ec47232c9ded514176f37778bbae27dcc37aeb4
1 /*
2 * Copyright (C) 1987-2008 Sun Microsystems, Inc. All Rights Reserved.
3 * Copyright (C) 2008-2011 Robert Ancell.
5 * This program is free software: you can redistribute it and/or modify it under
6 * the terms of the GNU General Public License as published by the Free Software
7 * Foundation, either version 2 of the License, or (at your option) any later
8 * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
9 * license.
12 #include <glib/gi18n.h>
13 #include <gtk/gtk.h>
14 #include <gdk/gdkkeysyms.h>
16 #include "math-window.h"
17 #include "math-preferences.h"
19 enum {
20 PROP_0,
21 PROP_EQUATION
24 struct MathWindowPrivate
26 GtkWidget *menu_bar;
27 MathEquation *equation;
28 MathDisplay *display;
29 MathButtons *buttons;
30 MathPreferencesDialog *preferences_dialog;
31 gboolean right_aligned;
32 GtkWidget *mode_basic_menu_item, *mode_advanced_menu_item, *mode_financial_menu_item, *mode_programming_menu_item;
35 G_DEFINE_TYPE (MathWindow, math_window, GTK_TYPE_APPLICATION_WINDOW);
38 MathWindow *
39 math_window_new(GtkApplication *app, MathEquation *equation)
41 return g_object_new(math_window_get_type(),
42 "application", app,
43 "equation", equation, NULL);
47 GtkWidget *
48 math_window_get_menu_bar(MathWindow *window)
50 g_return_val_if_fail(window != NULL, NULL);
51 return window->priv->menu_bar;
55 MathEquation *
56 math_window_get_equation(MathWindow *window)
58 g_return_val_if_fail(window != NULL, NULL);
59 return window->priv->equation;
63 MathDisplay *
64 math_window_get_display(MathWindow *window)
66 g_return_val_if_fail(window != NULL, NULL);
67 return window->priv->display;
71 MathButtons *
72 math_window_get_buttons(MathWindow *window)
74 g_return_val_if_fail(window != NULL, NULL);
75 return window->priv->buttons;
79 void
80 math_window_critical_error(MathWindow *window, const gchar *title, const gchar *contents)
82 GtkWidget *dialog;
84 g_return_if_fail(window != NULL);
85 g_return_if_fail(title != NULL);
86 g_return_if_fail(contents != NULL);
88 dialog = gtk_message_dialog_new(NULL, 0,
89 GTK_MESSAGE_ERROR,
90 GTK_BUTTONS_NONE,
91 "%s", title);
92 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
93 "%s", contents);
94 gtk_dialog_add_buttons(GTK_DIALOG(dialog), GTK_STOCK_QUIT, GTK_RESPONSE_ACCEPT, NULL);
96 gtk_dialog_run(GTK_DIALOG(dialog));
98 gtk_widget_destroy(GTK_WIDGET(window));
102 static void
103 copy_cb(GtkWidget *widget, MathWindow *window)
105 math_equation_copy(window->priv->equation);
109 static void
110 paste_cb(GtkWidget *widget, MathWindow *window)
112 math_equation_paste(window->priv->equation);
116 static void
117 undo_cb(GtkWidget *widget, MathWindow *window)
119 math_equation_undo(window->priv->equation);
123 static void
124 redo_cb(GtkWidget *widget, MathWindow *window)
126 math_equation_redo(window->priv->equation);
130 static void
131 mode_changed_cb(GtkWidget *menu, MathWindow *window)
133 int mode;
135 if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menu)))
136 return;
138 mode = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(menu), "calcmode"));
139 math_buttons_set_mode(window->priv->buttons, mode);
143 static void
144 show_preferences_cb(GtkMenuItem *menu, MathWindow *window)
146 if (!window->priv->preferences_dialog) {
147 window->priv->preferences_dialog = math_preferences_dialog_new(window->priv->equation);
148 gtk_window_set_transient_for(GTK_WINDOW(window->priv->preferences_dialog), GTK_WINDOW(window));
150 gtk_window_present(GTK_WINDOW(window->priv->preferences_dialog));
154 static void
155 help_cb(GtkWidget *widget, MathWindow *window)
157 GdkScreen *screen;
158 GError *error = NULL;
160 screen = gtk_widget_get_screen(GTK_WIDGET(window));
161 gtk_show_uri(screen, "help:gcalctool", gtk_get_current_event_time(), &error);
163 if (error != NULL)
165 GtkWidget *d;
166 /* Translators: Error message displayed when unable to launch help browser */
167 const char *message = _("Unable to open help file");
169 d = gtk_message_dialog_new(GTK_WINDOW (window),
170 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
171 GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
172 "%s", message);
173 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG (d),
174 "%s", error->message);
175 g_signal_connect(d, "response", G_CALLBACK(gtk_widget_destroy), NULL);
176 gtk_window_present(GTK_WINDOW(d));
178 g_error_free(error);
183 static void
184 about_cb(GtkWidget *widget, MathWindow *window)
186 const gchar *authors[] = {
187 "Rich Burridge <rich.burridge@gmail.com>",
188 "Robert Ancell <robert.ancell@gmail.com>",
189 "Klaus Niederkrüger <kniederk@umpa.ens-lyon.fr>",
190 "Robin Sonefors <ozamosi@flukkost.nu>",
191 NULL
193 const gchar *documenters[] = {
194 "Sun Microsystems",
195 NULL
198 /* The translator credits. Please translate this with your name(s). */
199 const gchar *translator_credits = _("translator-credits");
201 /* The license this software is under (GPL2+) */
202 char *license = _("Gcalctool is free software; you can redistribute it and/or modify\n"
203 "it under the terms of the GNU General Public License as published by\n"
204 "the Free Software Foundation; either version 2 of the License, or\n"
205 "(at your option) any later version.\n"
206 "\n"
207 "Gcalctool is distributed in the hope that it will be useful,\n"
208 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
209 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
210 "GNU General Public License for more details.\n"
211 "\n"
212 "You should have received a copy of the GNU General Public License\n"
213 "along with Gcalctool; if not, write to the Free Software Foundation, Inc.,\n"
214 "51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA");
216 gtk_show_about_dialog(GTK_WINDOW(window),
217 "name",
218 /* Program name in the about dialog */
219 _("Gcalctool"),
220 "version", VERSION,
221 "copyright",
222 /* Copyright notice in the about dialog */
223 _("\xc2\xa9 1986–2010 The Gcalctool authors"),
224 "license", license,
225 "comments",
226 /* Short description in the about dialog */
227 _("Calculator with financial and scientific modes."),
228 "authors", authors,
229 "documenters", documenters,
230 "translator_credits", translator_credits,
231 "logo-icon-name", "accessories-calculator",
232 NULL);
236 static void
237 quit_cb(GtkWidget *widget, MathWindow *window)
239 gtk_widget_destroy(GTK_WIDGET(window));
243 static gboolean
244 key_press_cb(MathWindow *window, GdkEventKey *event)
246 gboolean result;
247 g_signal_emit_by_name(window->priv->display, "key-press-event", event, &result);
249 if (math_buttons_get_mode (window->priv->buttons) == PROGRAMMING && (event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK) {
250 switch(event->keyval)
252 /* Binary */
253 case GDK_KEY_b:
254 math_equation_set_base (window->priv->equation, 2);
255 return TRUE;
256 /* Octal */
257 case GDK_KEY_o:
258 math_equation_set_base (window->priv->equation, 8);
259 return TRUE;
260 /* Decimal */
261 case GDK_KEY_d:
262 math_equation_set_base (window->priv->equation, 10);
263 return TRUE;
264 /* Hexdecimal */
265 case GDK_KEY_h:
266 math_equation_set_base (window->priv->equation, 16);
267 return TRUE;
271 return result;
275 static void
276 scroll_changed_cb(GtkAdjustment *adjustment, MathWindow *window)
278 if (window->priv->right_aligned)
279 gtk_adjustment_set_value(adjustment, gtk_adjustment_get_upper(adjustment) - gtk_adjustment_get_page_size(adjustment));
283 static void
284 scroll_value_changed_cb(GtkAdjustment *adjustment, MathWindow *window)
286 if (gtk_adjustment_get_value(adjustment) == gtk_adjustment_get_upper(adjustment) - gtk_adjustment_get_page_size(adjustment))
287 window->priv->right_aligned = TRUE;
288 else
289 window->priv->right_aligned = FALSE;
293 static void
294 button_mode_changed_cb(MathButtons *buttons, GParamSpec *spec, MathWindow *window)
296 GtkWidget *menu;
298 switch(math_buttons_get_mode(buttons))
300 default:
301 case BASIC:
302 menu = window->priv->mode_basic_menu_item;
303 //FIXME: Should it revert to decimal mode? math_equation_set_number_format(window->priv->equation, DEC);
304 break;
306 case ADVANCED:
307 menu = window->priv->mode_advanced_menu_item;
308 break;
310 case FINANCIAL:
311 menu = window->priv->mode_financial_menu_item;
312 break;
314 case PROGRAMMING:
315 menu = window->priv->mode_programming_menu_item;
316 break;
318 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), TRUE);
322 static GtkWidget *
323 add_menu(GtkWidget *menu_bar, const gchar *name)
325 GtkWidget *menu_item, *menu;
327 menu_item = gtk_menu_item_new_with_mnemonic(name);
328 gtk_menu_shell_append(GTK_MENU_SHELL(menu_bar), menu_item);
329 gtk_widget_show(menu_item);
330 menu = gtk_menu_new();
331 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), menu);
333 return menu;
337 static GtkWidget *
338 add_menu_item(GtkWidget *menu, GtkWidget *menu_item, GCallback callback, gpointer callback_data)
340 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
341 gtk_widget_show(menu_item);
342 if (callback)
343 g_signal_connect(G_OBJECT(menu_item), "activate", callback, callback_data);
344 return menu_item;
348 static GtkWidget *
349 radio_menu_item_new(GSList **group, const gchar *name)
351 GtkWidget *menu_item;
352 menu_item = gtk_radio_menu_item_new_with_mnemonic(*group, name);
353 *group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(menu_item));
354 return menu_item;
358 static void
359 create_menu(MathWindow *window)
361 GtkAccelGroup *accel_group;
362 GtkWidget *menu, *menu_item;
363 GSList *group = NULL;
365 accel_group = gtk_accel_group_new();
366 gtk_window_add_accel_group(GTK_WINDOW(window), accel_group);
368 /* Calculator menu */
369 #define CALCULATOR_MENU_LABEL _("_Calculator")
370 /* Mode menu */
371 #define MODE_MENU_LABEL _("_Mode")
372 /* Help menu label */
373 #define HELP_MENU_LABEL _("_Help")
374 /* Basic menu label */
375 #define MODE_BASIC_LABEL _("_Basic")
376 /* Advanced menu label */
377 #define MODE_ADVANCED_LABEL _("_Advanced")
378 /* Financial menu label */
379 #define MODE_FINANCIAL_LABEL _("_Financial")
380 /* Programming menu label */
381 #define MODE_PROGRAMMING_LABEL _("_Programming")
382 /* Help>Contents menu label */
383 #define HELP_CONTENTS_LABEL _("_Contents")
385 menu = add_menu(window->priv->menu_bar, CALCULATOR_MENU_LABEL);
386 add_menu_item(menu, gtk_image_menu_item_new_from_stock(GTK_STOCK_COPY, accel_group), G_CALLBACK(copy_cb), window);
387 add_menu_item(menu, gtk_image_menu_item_new_from_stock(GTK_STOCK_PASTE, accel_group), G_CALLBACK(paste_cb), window);
388 menu_item = add_menu_item(menu, gtk_image_menu_item_new_from_stock(GTK_STOCK_UNDO, accel_group), G_CALLBACK(undo_cb), window);
389 gtk_widget_add_accelerator(menu_item, "activate", accel_group, GDK_KEY_z, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
390 menu_item = add_menu_item(menu, gtk_image_menu_item_new_from_stock(GTK_STOCK_REDO, accel_group), G_CALLBACK(redo_cb), window);
391 gtk_widget_add_accelerator(menu_item, "activate", accel_group, GDK_KEY_z, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_ACCEL_VISIBLE);
392 add_menu_item(menu, gtk_separator_menu_item_new(), NULL, NULL);
393 add_menu_item(menu, gtk_image_menu_item_new_from_stock(GTK_STOCK_PREFERENCES, accel_group), G_CALLBACK(show_preferences_cb), window);
394 add_menu_item(menu, gtk_separator_menu_item_new(), NULL, NULL);
395 menu_item = add_menu_item(menu, gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, accel_group), G_CALLBACK(quit_cb), window);
396 gtk_widget_add_accelerator(menu_item, "activate", accel_group, GDK_KEY_w, GDK_CONTROL_MASK, 0);
398 menu = add_menu(window->priv->menu_bar, MODE_MENU_LABEL);
399 window->priv->mode_basic_menu_item = add_menu_item(menu, radio_menu_item_new(&group, MODE_BASIC_LABEL), G_CALLBACK(mode_changed_cb), window);
400 g_object_set_data(G_OBJECT(window->priv->mode_basic_menu_item), "calcmode", GINT_TO_POINTER(BASIC));
401 window->priv->mode_advanced_menu_item = add_menu_item(menu, radio_menu_item_new(&group, MODE_ADVANCED_LABEL), G_CALLBACK(mode_changed_cb), window);
402 g_object_set_data(G_OBJECT(window->priv->mode_advanced_menu_item), "calcmode", GINT_TO_POINTER(ADVANCED));
403 window->priv->mode_financial_menu_item = add_menu_item(menu, radio_menu_item_new(&group, MODE_FINANCIAL_LABEL), G_CALLBACK(mode_changed_cb), window);
404 g_object_set_data(G_OBJECT(window->priv->mode_financial_menu_item), "calcmode", GINT_TO_POINTER(FINANCIAL));
405 window->priv->mode_programming_menu_item = add_menu_item(menu, radio_menu_item_new(&group, MODE_PROGRAMMING_LABEL), G_CALLBACK(mode_changed_cb), window);
406 g_object_set_data(G_OBJECT(window->priv->mode_programming_menu_item), "calcmode", GINT_TO_POINTER(PROGRAMMING));
408 menu = add_menu(window->priv->menu_bar, HELP_MENU_LABEL);
409 menu_item = add_menu_item(menu, gtk_menu_item_new_with_mnemonic(HELP_CONTENTS_LABEL), G_CALLBACK(help_cb), window);
410 gtk_widget_add_accelerator(menu_item, "activate", accel_group, GDK_KEY_F1, 0, GTK_ACCEL_VISIBLE);
411 add_menu_item(menu, gtk_image_menu_item_new_from_stock(GTK_STOCK_ABOUT, accel_group), G_CALLBACK(about_cb), window);
415 static void
416 create_gui(MathWindow *window)
418 GtkWidget *main_vbox, *vbox;
419 GtkWidget *scrolled_window;
421 main_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
422 gtk_container_add(GTK_CONTAINER(window), main_vbox);
423 gtk_widget_show(main_vbox);
425 window->priv->menu_bar = gtk_menu_bar_new();
426 gtk_box_pack_start(GTK_BOX(main_vbox), window->priv->menu_bar, FALSE, FALSE, 0);
427 gtk_widget_show(window->priv->menu_bar);
429 create_menu(window);
431 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6);
432 gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
433 gtk_box_pack_start(GTK_BOX(main_vbox), vbox, TRUE, TRUE, 0);
434 gtk_widget_show(vbox);
436 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
437 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER);
438 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(scrolled_window), FALSE, FALSE, 0);
439 g_signal_connect(gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(scrolled_window)), "changed", G_CALLBACK(scroll_changed_cb), window);
440 g_signal_connect(gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(scrolled_window)), "value-changed", G_CALLBACK(scroll_value_changed_cb), window);
441 window->priv->right_aligned = TRUE;
442 gtk_widget_show(scrolled_window);
444 window->priv->display = math_display_new_with_equation(window->priv->equation);
445 gtk_container_add(GTK_CONTAINER(scrolled_window), GTK_WIDGET(window->priv->display));
446 gtk_widget_show(GTK_WIDGET(window->priv->display));
448 window->priv->buttons = math_buttons_new(window->priv->equation);
449 g_signal_connect(window->priv->buttons, "notify::mode", G_CALLBACK(button_mode_changed_cb), window);
450 button_mode_changed_cb(window->priv->buttons, NULL, window);
451 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(window->priv->buttons), TRUE, TRUE, 0);
452 gtk_widget_show(GTK_WIDGET(window->priv->buttons));
456 static void
457 math_window_set_property(GObject *object,
458 guint prop_id,
459 const GValue *value,
460 GParamSpec *pspec)
462 MathWindow *self;
464 self = MATH_WINDOW(object);
466 switch (prop_id) {
467 case PROP_EQUATION:
468 self->priv->equation = g_value_get_object(value);
469 create_gui(self);
470 break;
471 default:
472 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
473 break;
478 static void
479 math_window_get_property(GObject *object,
480 guint prop_id,
481 GValue *value,
482 GParamSpec *pspec)
484 MathWindow *self;
486 self = MATH_WINDOW(object);
488 switch (prop_id) {
489 case PROP_EQUATION:
490 g_value_set_object(value, self->priv->equation);
491 break;
492 default:
493 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
494 break;
499 static void
500 math_window_class_init(MathWindowClass *klass)
502 GObjectClass *object_class = G_OBJECT_CLASS(klass);
504 object_class->get_property = math_window_get_property;
505 object_class->set_property = math_window_set_property;
507 g_type_class_add_private(klass, sizeof(MathWindowPrivate));
509 g_object_class_install_property(object_class,
510 PROP_EQUATION,
511 g_param_spec_object("equation",
512 "equation",
513 "Equation being calculated",
514 math_equation_get_type(),
515 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
519 static void
520 math_window_init(MathWindow *window)
522 window->priv = G_TYPE_INSTANCE_GET_PRIVATE(window, math_window_get_type(), MathWindowPrivate);
523 gtk_window_set_title(GTK_WINDOW(window),
524 /* Title of main window */
525 _("Calculator"));
526 gtk_window_set_icon_name(GTK_WINDOW(window), "accessories-calculator");
527 gtk_window_set_role(GTK_WINDOW(window), "gcalctool");
528 gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
529 g_signal_connect_after(G_OBJECT(window), "key-press-event", G_CALLBACK(key_press_cb), NULL);