Fix incorrect spelling of ones' and two's complement (Bug #642457)
[gcalctool.git] / src / math-window.c
blob42f5df2b7655bed86b48b1d93e3409bed48674ec
1 /* Copyright (c) 1987-2008 Sun Microsystems, Inc. All Rights Reserved.
2 * Copyright (c) 2008-2009 Robert Ancell
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
17 * 02111-1307, USA.
20 #include <glib/gi18n.h>
21 #include <gtk/gtk.h>
22 #include <gdk/gdkkeysyms.h>
24 #include "math-window.h"
25 #include "math-preferences.h"
27 enum {
28 PROP_0,
29 PROP_EQUATION
32 struct MathWindowPrivate
34 GtkWidget *menu_bar;
35 MathEquation *equation;
36 MathDisplay *display;
37 MathButtons *buttons;
38 MathPreferencesDialog *preferences_dialog;
39 gboolean right_aligned;
40 GtkWidget *mode_basic_menu_item, *mode_advanced_menu_item, *mode_financial_menu_item, *mode_programming_menu_item;
43 G_DEFINE_TYPE (MathWindow, math_window, GTK_TYPE_WINDOW);
45 enum {
46 QUIT,
47 LAST_SIGNAL
49 static guint signals[LAST_SIGNAL] = { 0, };
52 MathWindow *
53 math_window_new(MathEquation *equation)
55 return g_object_new(math_window_get_type(), "equation", equation, NULL);
59 GtkWidget *
60 math_window_get_menu_bar(MathWindow *window)
62 return window->priv->menu_bar;
66 MathEquation *
67 math_window_get_equation(MathWindow *window)
69 return window->priv->equation;
73 MathDisplay *
74 math_window_get_display(MathWindow *window)
76 return window->priv->display;
80 MathButtons *
81 math_window_get_buttons(MathWindow *window)
83 return window->priv->buttons;
87 void
88 math_window_critical_error(MathWindow *window, const gchar *title, const gchar *contents)
90 GtkWidget *dialog;
92 dialog = gtk_message_dialog_new(NULL, 0,
93 GTK_MESSAGE_ERROR,
94 GTK_BUTTONS_NONE,
95 "%s", title);
96 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
97 "%s", contents);
98 gtk_dialog_add_buttons(GTK_DIALOG(dialog), GTK_STOCK_QUIT, GTK_RESPONSE_ACCEPT, NULL);
100 gtk_dialog_run(GTK_DIALOG(dialog));
102 g_signal_emit(window, signals[QUIT], 0);
106 static void
107 copy_cb(GtkWidget *widget, MathWindow *window)
109 math_equation_copy(window->priv->equation);
113 static void
114 paste_cb(GtkWidget *widget, MathWindow *window)
116 math_equation_paste(window->priv->equation);
120 static void
121 undo_cb(GtkWidget *widget, MathWindow *window)
123 math_equation_undo(window->priv->equation);
127 static void
128 redo_cb(GtkWidget *widget, MathWindow *window)
130 math_equation_redo(window->priv->equation);
134 static void
135 mode_changed_cb(GtkWidget *menu, MathWindow *window)
137 int mode;
139 if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menu)))
140 return;
142 mode = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(menu), "calcmode"));
143 math_buttons_set_mode(window->priv->buttons, mode);
147 static void
148 show_preferences_cb(GtkMenuItem *menu, MathWindow *window)
150 if (!window->priv->preferences_dialog) {
151 window->priv->preferences_dialog = math_preferences_dialog_new(window->priv->equation);
152 gtk_window_set_transient_for(GTK_WINDOW(window->priv->preferences_dialog), GTK_WINDOW(window));
154 gtk_window_present(GTK_WINDOW(window->priv->preferences_dialog));
158 static void
159 help_cb(GtkWidget *widget, MathWindow *window)
161 GdkScreen *screen;
162 GError *error = NULL;
164 screen = gtk_widget_get_screen(GTK_WIDGET(window));
165 gtk_show_uri(screen, "ghelp:gcalctool", gtk_get_current_event_time(), &error);
167 if (error != NULL)
169 GtkWidget *d;
170 /* Translators: Error message displayed when unable to launch help browser */
171 const char *message = _("Unable to open help file");
173 d = gtk_message_dialog_new(GTK_WINDOW (window),
174 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
175 GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
176 "%s", message);
177 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG (d),
178 "%s", error->message);
179 g_signal_connect(d, "response", G_CALLBACK(gtk_widget_destroy), NULL);
180 gtk_window_present(GTK_WINDOW(d));
182 g_error_free(error);
187 static void
188 about_cb(GtkWidget *widget, MathWindow *window)
190 const gchar *authors[] = {
191 "Rich Burridge <rich.burridge@gmail.com>",
192 "Robert Ancell <robert.ancell@gmail.com>",
193 "Klaus Niederkrüger <kniederk@umpa.ens-lyon.fr>",
194 "Robin Sonefors <ozamosi@flukkost.nu>",
195 NULL
197 const gchar *documenters[] = {
198 "Sun Microsystems",
199 NULL
202 /* The translator credits. Please translate this with your name(s). */
203 const gchar *translator_credits = _("translator-credits");
205 /* The license this software is under (GPL2+) */
206 char *license = _("Gcalctool is free software; you can redistribute it and/or modify\n"
207 "it under the terms of the GNU General Public License as published by\n"
208 "the Free Software Foundation; either version 2 of the License, or\n"
209 "(at your option) any later version.\n"
210 "\n"
211 "Gcalctool is distributed in the hope that it will be useful,\n"
212 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
213 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
214 "GNU General Public License for more details.\n"
215 "\n"
216 "You should have received a copy of the GNU General Public License\n"
217 "along with Gcalctool; if not, write to the Free Software Foundation, Inc.,\n"
218 "51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA");
220 gtk_show_about_dialog(GTK_WINDOW(window),
221 "name",
222 /* Program name in the about dialog */
223 _("Gcalctool"),
224 "version", VERSION,
225 "copyright",
226 /* Copyright notice in the about dialog */
227 _("\xc2\xa9 1986–2010 The Gcalctool authors"),
228 "license", license,
229 "comments",
230 /* Short description in the about dialog */
231 _("Calculator with financial and scientific modes."),
232 "authors", authors,
233 "documenters", documenters,
234 "translator_credits", translator_credits,
235 "logo-icon-name", "accessories-calculator",
236 NULL);
240 static void
241 quit_cb(GtkWidget *widget, MathWindow *window)
243 g_signal_emit(window, signals[QUIT], 0);
247 static gboolean
248 key_press_cb(MathWindow *window, GdkEventKey *event)
250 gboolean result;
251 g_signal_emit_by_name(window->priv->display, "key-press-event", event, &result);
252 return result;
256 static void
257 delete_cb(MathWindow *window, GdkEvent *event)
259 g_signal_emit(window, signals[QUIT], 0);
263 static void
264 scroll_changed_cb(GtkAdjustment *adjustment, MathWindow *window)
266 if (window->priv->right_aligned)
267 gtk_adjustment_set_value(adjustment, gtk_adjustment_get_upper(adjustment) - gtk_adjustment_get_page_size(adjustment));
271 static void
272 scroll_value_changed_cb(GtkAdjustment *adjustment, MathWindow *window)
274 if (gtk_adjustment_get_value(adjustment) == gtk_adjustment_get_upper(adjustment) - gtk_adjustment_get_page_size(adjustment))
275 window->priv->right_aligned = TRUE;
276 else
277 window->priv->right_aligned = FALSE;
281 static void
282 button_mode_changed_cb(MathButtons *buttons, GParamSpec *spec, MathWindow *window)
284 GtkWidget *menu;
286 switch(math_buttons_get_mode(buttons))
288 default:
289 case BASIC:
290 menu = window->priv->mode_basic_menu_item;
291 //FIXME: Should it revert to decimal mode? math_equation_set_number_format(window->priv->equation, DEC);
292 break;
294 case ADVANCED:
295 menu = window->priv->mode_advanced_menu_item;
296 break;
298 case FINANCIAL:
299 menu = window->priv->mode_financial_menu_item;
300 break;
302 case PROGRAMMING:
303 menu = window->priv->mode_programming_menu_item;
304 break;
306 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), TRUE);
310 static GtkWidget *
311 add_menu(GtkWidget *menu_bar, const gchar *name)
313 GtkWidget *menu_item, *menu;
315 menu_item = gtk_menu_item_new_with_mnemonic(name);
316 gtk_menu_shell_append(GTK_MENU_SHELL(menu_bar), menu_item);
317 gtk_widget_show(menu_item);
318 menu = gtk_menu_new();
319 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), menu);
321 return menu;
325 static GtkWidget *
326 add_menu_item(GtkWidget *menu, GtkWidget *menu_item, GCallback callback, gpointer callback_data)
328 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
329 gtk_widget_show(menu_item);
330 if (callback)
331 g_signal_connect(G_OBJECT(menu_item), "activate", callback, callback_data);
332 return menu_item;
336 static GtkWidget *
337 radio_menu_item_new(GSList **group, const gchar *name)
339 GtkWidget *menu_item;
340 menu_item = gtk_radio_menu_item_new_with_mnemonic(*group, name);
341 *group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(menu_item));
342 return menu_item;
346 static void
347 create_menu(MathWindow *window)
349 GtkAccelGroup *accel_group;
350 GtkWidget *menu, *menu_item;
351 GSList *group = NULL;
353 accel_group = gtk_accel_group_new();
354 gtk_window_add_accel_group(GTK_WINDOW(window), accel_group);
356 /* Calculator menu */
357 #define CALCULATOR_MENU_LABEL _("_Calculator")
358 /* Mode menu */
359 #define MODE_MENU_LABEL _("_Mode")
360 /* Help menu label */
361 #define HELP_MENU_LABEL _("_Help")
362 /* Basic menu label */
363 #define MODE_BASIC_LABEL _("_Basic")
364 /* Advanced menu label */
365 #define MODE_ADVANCED_LABEL _("_Advanced")
366 /* Financial menu label */
367 #define MODE_FINANCIAL_LABEL _("_Financial")
368 /* Programming menu label */
369 #define MODE_PROGRAMMING_LABEL _("_Programming")
370 /* Help>Contents menu label */
371 #define HELP_CONTENTS_LABEL _("_Contents")
373 menu = add_menu(window->priv->menu_bar, CALCULATOR_MENU_LABEL);
374 add_menu_item(menu, gtk_image_menu_item_new_from_stock(GTK_STOCK_COPY, accel_group), G_CALLBACK(copy_cb), window);
375 add_menu_item(menu, gtk_image_menu_item_new_from_stock(GTK_STOCK_PASTE, accel_group), G_CALLBACK(paste_cb), window);
376 menu_item = add_menu_item(menu, gtk_image_menu_item_new_from_stock(GTK_STOCK_UNDO, accel_group), G_CALLBACK(undo_cb), window);
377 gtk_widget_add_accelerator(menu_item, "activate", accel_group, GDK_KEY_z, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
378 menu_item = add_menu_item(menu, gtk_image_menu_item_new_from_stock(GTK_STOCK_REDO, accel_group), G_CALLBACK(redo_cb), window);
379 gtk_widget_add_accelerator(menu_item, "activate", accel_group, GDK_KEY_z, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_ACCEL_VISIBLE);
380 add_menu_item(menu, gtk_separator_menu_item_new(), NULL, NULL);
381 add_menu_item(menu, gtk_image_menu_item_new_from_stock(GTK_STOCK_PREFERENCES, accel_group), G_CALLBACK(show_preferences_cb), window);
382 add_menu_item(menu, gtk_separator_menu_item_new(), NULL, NULL);
383 menu_item = add_menu_item(menu, gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, accel_group), G_CALLBACK(quit_cb), window);
384 gtk_widget_add_accelerator(menu_item, "activate", accel_group, GDK_KEY_w, GDK_CONTROL_MASK, 0);
386 menu = add_menu(window->priv->menu_bar, MODE_MENU_LABEL);
387 window->priv->mode_basic_menu_item = add_menu_item(menu, radio_menu_item_new(&group, MODE_BASIC_LABEL), G_CALLBACK(mode_changed_cb), window);
388 g_object_set_data(G_OBJECT(window->priv->mode_basic_menu_item), "calcmode", GINT_TO_POINTER(BASIC));
389 window->priv->mode_advanced_menu_item = add_menu_item(menu, radio_menu_item_new(&group, MODE_ADVANCED_LABEL), G_CALLBACK(mode_changed_cb), window);
390 g_object_set_data(G_OBJECT(window->priv->mode_advanced_menu_item), "calcmode", GINT_TO_POINTER(ADVANCED));
391 window->priv->mode_financial_menu_item = add_menu_item(menu, radio_menu_item_new(&group, MODE_FINANCIAL_LABEL), G_CALLBACK(mode_changed_cb), window);
392 g_object_set_data(G_OBJECT(window->priv->mode_financial_menu_item), "calcmode", GINT_TO_POINTER(FINANCIAL));
393 window->priv->mode_programming_menu_item = add_menu_item(menu, radio_menu_item_new(&group, MODE_PROGRAMMING_LABEL), G_CALLBACK(mode_changed_cb), window);
394 g_object_set_data(G_OBJECT(window->priv->mode_programming_menu_item), "calcmode", GINT_TO_POINTER(PROGRAMMING));
396 menu = add_menu(window->priv->menu_bar, HELP_MENU_LABEL);
397 menu_item = add_menu_item(menu, gtk_menu_item_new_with_mnemonic(HELP_CONTENTS_LABEL), G_CALLBACK(help_cb), window);
398 gtk_widget_add_accelerator(menu_item, "activate", accel_group, GDK_KEY_F1, 0, GTK_ACCEL_VISIBLE);
399 add_menu_item(menu, gtk_image_menu_item_new_from_stock(GTK_STOCK_ABOUT, accel_group), G_CALLBACK(about_cb), window);
403 static void
404 create_gui(MathWindow *window)
406 GtkWidget *main_vbox, *vbox;
407 GtkWidget *scrolled_window;
409 main_vbox = gtk_vbox_new(FALSE, 0);
410 gtk_container_add(GTK_CONTAINER(window), main_vbox);
411 gtk_widget_show(main_vbox);
413 window->priv->menu_bar = gtk_menu_bar_new();
414 gtk_box_pack_start(GTK_BOX(main_vbox), window->priv->menu_bar, FALSE, FALSE, 0);
415 gtk_widget_show(window->priv->menu_bar);
417 create_menu(window);
419 vbox = gtk_vbox_new(FALSE, 6);
420 gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
421 gtk_box_pack_start(GTK_BOX(main_vbox), vbox, TRUE, TRUE, 0);
422 gtk_widget_show(vbox);
424 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
425 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER);
426 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(scrolled_window), FALSE, FALSE, 0);
427 g_signal_connect(gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(scrolled_window)), "changed", G_CALLBACK(scroll_changed_cb), window);
428 g_signal_connect(gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(scrolled_window)), "value-changed", G_CALLBACK(scroll_value_changed_cb), window);
429 window->priv->right_aligned = TRUE;
430 gtk_widget_show(scrolled_window);
432 window->priv->display = math_display_new_with_equation(window->priv->equation);
433 gtk_container_add(GTK_CONTAINER(scrolled_window), GTK_WIDGET(window->priv->display));
434 gtk_widget_show(GTK_WIDGET(window->priv->display));
436 window->priv->buttons = math_buttons_new(window->priv->equation);
437 g_signal_connect(window->priv->buttons, "notify::mode", G_CALLBACK(button_mode_changed_cb), window);
438 button_mode_changed_cb(window->priv->buttons, NULL, window);
439 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(window->priv->buttons), TRUE, TRUE, 0);
440 gtk_widget_show(GTK_WIDGET(window->priv->buttons));
444 static void
445 math_window_set_property(GObject *object,
446 guint prop_id,
447 const GValue *value,
448 GParamSpec *pspec)
450 MathWindow *self;
452 self = MATH_WINDOW(object);
454 switch (prop_id) {
455 case PROP_EQUATION:
456 self->priv->equation = g_value_get_object(value);
457 create_gui(self);
458 break;
459 default:
460 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
461 break;
466 static void
467 math_window_get_property(GObject *object,
468 guint prop_id,
469 GValue *value,
470 GParamSpec *pspec)
472 MathWindow *self;
474 self = MATH_WINDOW(object);
476 switch (prop_id) {
477 case PROP_EQUATION:
478 g_value_set_object(value, self->priv->equation);
479 break;
480 default:
481 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
482 break;
487 static void
488 math_window_class_init(MathWindowClass *klass)
490 GObjectClass *object_class = G_OBJECT_CLASS(klass);
492 object_class->get_property = math_window_get_property;
493 object_class->set_property = math_window_set_property;
495 g_type_class_add_private(klass, sizeof(MathWindowPrivate));
497 g_object_class_install_property(object_class,
498 PROP_EQUATION,
499 g_param_spec_object("equation",
500 "equation",
501 "Equation being calculated",
502 math_equation_get_type(),
503 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
505 signals[QUIT] =
506 g_signal_new("quit",
507 G_TYPE_FROM_CLASS (klass),
508 G_SIGNAL_RUN_LAST,
509 G_STRUCT_OFFSET (MathWindowClass, quit),
510 NULL, NULL,
511 g_cclosure_marshal_VOID__VOID,
512 G_TYPE_NONE, 0);
516 static void
517 math_window_init(MathWindow *window)
519 window->priv = G_TYPE_INSTANCE_GET_PRIVATE(window, math_window_get_type(), MathWindowPrivate);
520 gtk_window_set_title(GTK_WINDOW(window),
521 /* Title of main window */
522 _("Calculator"));
523 gtk_window_set_icon_name(GTK_WINDOW(window), "accessories-calculator");
524 gtk_window_set_role(GTK_WINDOW(window), "gcalctool");
525 gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
526 g_signal_connect_after(G_OBJECT(window), "key-press-event", G_CALLBACK(key_press_cb), NULL);
527 g_signal_connect(G_OBJECT(window), "delete-event", G_CALLBACK(delete_cb), NULL);