[gcalctool] Split the UI into different files and stop storing it in a global variable
- From: Robert Ancell <rancell src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gcalctool] Split the UI into different files and stop storing it in a global variable
- Date: Mon, 5 Apr 2010 08:07:58 +0000 (UTC)
commit 7b44ee71bb0c5a78132fb0f23a709f5b87f00d93
Author: Robert Ancell <robert ancell gmail com>
Date: Sun Apr 4 14:46:18 2010 +1000
Split the UI into different files and stop storing it in a global variable
data/Makefile.am | 2 +-
data/gcalctool.ui | 8 +-
data/gcalctoolrc | 132 ---
src/Makefile.am | 10 +-
src/calctool.c | 6 +-
src/calctool.h | 2 +
src/display.c | 53 +-
src/gtk.c | 2270 --------------------------------------------------
src/ui-buttons.c | 657 +++++++++++++++
src/ui-buttons.h | 24 +
src/ui-display.c | 495 +++++++++++
src/ui-display.h | 31 +
src/ui-financial.c | 359 ++++++++
src/ui-financial.h | 24 +
src/ui-internal.h | 30 +
src/ui-preferences.c | 321 +++++++
src/ui-preferences.h | 26 +
src/ui.c | 393 +++++++++
src/ui.h | 83 ++-
19 files changed, 2471 insertions(+), 2455 deletions(-)
---
diff --git a/data/Makefile.am b/data/Makefile.am
index 92a47c1..0995645 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -20,7 +20,7 @@ Utilities_DATA = $(Utilities_in_files:.desktop.in=.desktop)
man1_MANS = gcalctool.1
-EXTRA_DIST = $(ui_DATA) $(schema_in_files) gcalctool.desktop.in $(man1_MANS) gcalctoolrc
+EXTRA_DIST = $(ui_DATA) $(schema_in_files) gcalctool.desktop.in $(man1_MANS)
DISTCLEANFILES = \
Makefile.in \
diff --git a/data/gcalctool.ui b/data/gcalctool.ui
index d90de31..e7d0f50 100644
--- a/data/gcalctool.ui
+++ b/data/gcalctool.ui
@@ -94,7 +94,7 @@
<property name="label" translatable="yes" comments="View|Basic menu item">_Basic</property>
<property name="use_underline">True</property>
<property name="active">True</property>
- <signal name="activate" handler="mode_radio_cb"/>
+ <signal name="activate" handler="mode_changed_cb"/>
</object>
</child>
<child>
@@ -103,7 +103,7 @@
<property name="label" translatable="yes" comments="View|Advanced menu item">_Advanced</property>
<property name="use_underline">True</property>
<property name="group">view_basic_menu</property>
- <signal name="activate" handler="mode_radio_cb"/>
+ <signal name="activate" handler="mode_changed_cb"/>
</object>
</child>
<child>
@@ -112,7 +112,7 @@
<property name="label" translatable="yes" comments="View|Financial menu item">_Financial</property>
<property name="use_underline">True</property>
<property name="group">view_basic_menu</property>
- <signal name="activate" handler="mode_radio_cb"/>
+ <signal name="activate" handler="mode_changed_cb"/>
</object>
</child>
<child>
@@ -121,7 +121,7 @@
<property name="label" translatable="yes" comments="View|Programming menu item">_Programming</property>
<property name="use_underline">True</property>
<property name="group">view_basic_menu</property>
- <signal name="activate" handler="mode_radio_cb"/>
+ <signal name="activate" handler="mode_changed_cb"/>
</object>
</child>
</object>
diff --git a/src/Makefile.am b/src/Makefile.am
index 6b22fb7..d552067 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -32,8 +32,16 @@ gcalctool_SOURCES = \
financial.h \
register.c \
register.h \
- gtk.c \
+ ui.c \
ui.h \
+ ui-buttons.c \
+ ui-buttons.h \
+ ui-display.c \
+ ui-display.h \
+ ui-financial.c \
+ ui-financial.h \
+ ui-preferences.c \
+ ui-preferences.h \
unittest.c \
unittest.h
diff --git a/src/calctool.c b/src/calctool.c
index 46b1070..eb71c2a 100644
--- a/src/calctool.c
+++ b/src/calctool.c
@@ -36,6 +36,8 @@
static CalculatorVariables calc_state;
CalculatorVariables *v;
+GCalctoolUI *X;
+
static void
version()
{
@@ -221,8 +223,8 @@ main(int argc, char **argv)
get_options(argc, argv);
- ui_load();
- ui_start();
+ X = ui_new();
+ ui_start(X);
currency_free_resources();
diff --git a/src/calctool.h b/src/calctool.h
index f945057..0f1f7bf 100644
--- a/src/calctool.h
+++ b/src/calctool.h
@@ -25,6 +25,7 @@
#include "config.h"
#include "mp.h"
#include "display.h"
+#include "ui.h"
/* To make lint happy. */
#define SNPRINTF (void) snprintf
@@ -59,5 +60,6 @@ typedef struct {
} CalculatorVariables;
extern CalculatorVariables *v; /* Calctool variables and options. */
+extern GCalctoolUI *X;
#endif /* CALCTOOL_H */
diff --git a/src/display.c b/src/display.c
index b3ed337..650047e 100644
--- a/src/display.c
+++ b/src/display.c
@@ -32,6 +32,7 @@
#include "mp-equation.h"
#include "register.h"
#include "currency.h"
+#include "calctool.h"
static GCDisplayState *
get_state(GCDisplay *display)
@@ -203,7 +204,7 @@ display_set_number(GCDisplay *display, const MPNumber *x)
display_set_string(display, text, -1);
enabled = display_get_unsigned_integer(display, &bit_value);
- ui_set_bitfield(enabled, bit_value);
+ ui_set_bitfield(X, enabled, bit_value);
}
@@ -251,7 +252,7 @@ display_refresh(GCDisplay *display)
cursor = display_get_cursor(display);
display_make_text(display, localized, MAX_LOCALIZED, &cursor);
- ui_set_display(localized, cursor);
+ ui_set_display(X, localized, cursor);
}
@@ -286,7 +287,7 @@ display_set_cursor(GCDisplay *display, int cursor)
void
display_set_error(GCDisplay *display, const char *message)
{
- ui_set_statusbar(message);
+ ui_set_statusbar(X, message);
}
@@ -314,24 +315,6 @@ copy_state(GCDisplayState *dst, GCDisplayState *src)
}
-static void
-update_undo_redo_button_sensitivity(GCDisplay *display)
-{
- int undo = 0;
- int redo = 0;
-
- if (display->h.current != display->h.end) {
- redo = 1;
- }
-
- if (display->h.current != display->h.begin) {
- undo = 1;
- }
-
- ui_set_undo_enabled(undo, redo);
-}
-
-
void
display_clear_stack(GCDisplay *display)
{
@@ -344,7 +327,6 @@ display_clear_stack(GCDisplay *display)
i = ((i + 1) % UNDO_HISTORY_LENGTH);
}
display->h.begin = display->h.end = display->h.current;
- update_undo_redo_button_sensitivity(display);
}
@@ -376,7 +358,6 @@ display_push(GCDisplay *display)
}
copy_state(&(display->h.e[display->h.current]), &(display->h.e[c]));
- update_undo_redo_button_sensitivity(display);
}
@@ -385,11 +366,10 @@ display_pop(GCDisplay *display)
{
if (display->h.current != display->h.begin) {
display->h.current = ((display->h.current - 1) % UNDO_HISTORY_LENGTH);
- ui_set_statusbar("");
+ ui_set_statusbar(X, "");
} else {
- ui_set_statusbar(_("No undo history"));
+ ui_set_statusbar(X, _("No undo history"));
}
- update_undo_redo_button_sensitivity(display);
display_refresh(display);
}
@@ -400,11 +380,10 @@ display_unpop(GCDisplay *display)
{
if (display->h.current != display->h.end) {
display->h.current = ((display->h.current + 1) % UNDO_HISTORY_LENGTH);
- ui_set_statusbar("");
+ ui_set_statusbar(X, "");
} else {
- ui_set_statusbar(_("No redo steps"));
+ ui_set_statusbar(X, _("No redo steps"));
}
- update_undo_redo_button_sensitivity(display);
get_state(display)->cursor = -1;
display_refresh(display);
}
@@ -448,7 +427,7 @@ display_insert(GCDisplay *display, int cursor_start, int cursor_end, const char
}
cursor = 0;
- for (c = ui_get_display(); *c; c = g_utf8_next_char(c), cursor++) {
+ for (c = ui_get_display(X); *c; c = g_utf8_next_char(c), cursor++) {
gboolean use = TRUE;
/* Ignore selected part */
@@ -502,7 +481,7 @@ display_backspace(GCDisplay *display, int cursor_start, int cursor_end)
/* If cursor is at end of the line then delete the last character preserving accuracy */
if (cursor_start < 0) {
int len;
- len = g_utf8_strlen(ui_get_display(), -1);
+ len = g_utf8_strlen(ui_get_display(X), -1);
display_insert(display, len - 1, len, "");
} else if (cursor_start != cursor_end) {
display_insert(display, cursor_start, cursor_end, "");
@@ -933,7 +912,7 @@ do_shift(GCDisplay *display, int count)
if (!display_is_usable_number(display, &z)) {
/* Translators: This message is displayed in the status bar when a bit
shift operation is performed and the display does not contain a number */
- ui_set_statusbar(_("No sane value to bitwise shift"));
+ ui_set_statusbar(X, _("No sane value to bitwise shift"));
}
else {
mp_shift(&z, count, display_get_answer(display));
@@ -949,7 +928,7 @@ do_factorize()
if (!display_is_usable_number(&v->display, &value)) {
/* Translators: Error displayed when trying to factorize a non-integer value */
- ui_set_statusbar(_("Need an integer to factorize"));
+ ui_set_statusbar(X, _("Need an integer to factorize"));
return;
}
display_clear(&v->display);
@@ -975,7 +954,7 @@ do_sto(GCDisplay *display, const char *name)
MPNumber t;
if (!display_is_usable_number(display, &t))
- ui_set_statusbar(_("No sane value to store"));
+ ui_set_statusbar(X, _("No sane value to store"));
else
register_set_value(name, &t);
}
@@ -1006,7 +985,7 @@ display_do_function(GCDisplay *display, int function, gpointer arg, int cursor_s
display_set_cursor(display, cursor_start);
ans = display_get_answer(display);
- ui_set_statusbar("");
+ ui_set_statusbar(X, "");
switch (function) {
case FN_CLEAR:
@@ -1126,7 +1105,7 @@ display_do_function(GCDisplay *display, int function, gpointer arg, int cursor_s
break;
}
if (message)
- ui_set_statusbar(message);
+ ui_set_statusbar(X, message);
}
break;
@@ -1140,5 +1119,5 @@ display_do_function(GCDisplay *display, int function, gpointer arg, int cursor_s
}
enabled = display_get_unsigned_integer(display, &bit_value);
- ui_set_bitfield(enabled, bit_value);
+ ui_set_bitfield(X, enabled, bit_value);
}
diff --git a/src/ui-buttons.c b/src/ui-buttons.c
new file mode 100644
index 0000000..9326a4e
--- /dev/null
+++ b/src/ui-buttons.c
@@ -0,0 +1,657 @@
+/* Copyright (c) 2008-2009 Robert Ancell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include "ui-buttons.h"
+#include "ui-internal.h"
+#include "register.h"
+
+#define UI_BASIC_FILE UI_DIR "/buttons-basic.ui"
+#define UI_ADVANCED_FILE UI_DIR "/buttons-advanced.ui"
+#define UI_FINANCIAL_FILE UI_DIR "/buttons-financial.ui"
+#define UI_PROGRAMMING_FILE UI_DIR "/buttons-programming.ui"
+
+#define GET_OBJECT(ui, name) \
+ gtk_builder_get_object((ui), (name))
+#define GET_WIDGET(ui, name) \
+ GTK_WIDGET(GET_OBJECT(ui, name))
+
+static char *registers[] = {"a", "b", "c", "x", "y", "z", NULL};
+
+typedef enum {
+ POPUP_RIGHT, /* Place popup to right of baseframe */
+ POPUP_LEFT, /* Place popup to left of baseframe */
+ POPUP_ABOVE, /* Place popup above baseframe */
+ POPUP_BELOW, /* Place popup below baseframe */
+ POPUP_LOR, /* Place popup to right or left of baseframe */
+ POPUP_AOB, /* Place popup above or below baseframe */
+ POPUP_CENTERED /* Center popup within baseframe */
+} PopupLocation;
+
+#define WM_WIDTH_FACTOR 10
+#define WM_HEIGHT_FACTOR 30
+
+typedef struct {
+ const char *widget_name;
+ const char *data;
+/* const char *colour;
+ int alpha;*/
+} ButtonData;
+
+static ButtonData button_data[] = {
+ {"pi", "Ï?"},
+ {"eulers_number", "e"},
+ {"random", "rand"},
+ {"ans", "ans"},
+ {"numeric_point", "."},
+ {"add", "+"},
+ {"multiply", "Ã?"},
+ {"divide", "÷"},
+ {"modulus_divide", " mod "},
+ {"x_pow_y", "^"},
+ {"percentage", "%"},
+ {"factorial", "!"},
+ {"abs", "|"},
+ {"root", "â??"},
+ {"logarithm", "log"},
+ {"natural_logarithm", "ln"},
+ {"sine", "sin"},
+ {"cosine", "cos"},
+ {"tangent", "tan"},
+ {"hyperbolic_sine", "sinh"},
+ {"hyperbolic_cosine", "cosh"},
+ {"hyperbolic_tangent", "tanh"},
+ {"inverse", "�¹"},
+ {"and", "â?§"},
+ {"or", "â?¨"},
+ {"xor", "â?»"},
+ {"not", "¬"},
+ {"integer_portion", "int"},
+ {"fractional_portion", "frac"},
+ {"ones_complement", "ones"},
+ {"twos_complement", "twos"},
+ {"trunc", "trunc"},
+ {"start_group", "("},
+ {"end_group", ")"},
+ {NULL, NULL}
+};
+
+static const char *subscript_digits[] = {"â??", "â??", "â??", "â??", "â??", "â??", "â??", "â??", "â??", "â??", NULL};
+static const char *superscript_digits[] = {"�", "¹", "²", "³", "�", "�", "�", "�", "�", "�", NULL};
+
+
+static void
+set_tint (GtkWidget *widget, GdkColor *tint, gint alpha)
+{
+ GtkStyle *style;
+ int j;
+
+ if (!widget)
+ return;
+
+ style = gtk_widget_get_style(widget);
+
+ for (j = 0; j < 5; j++) {
+ GdkColor color;
+
+ color.red = (style->bg[j].red * (10 - alpha) + tint->red * alpha) / 10;
+ color.green = (style->bg[j].green * (10 - alpha) + tint->green * alpha) / 10;
+ color.blue = (style->bg[j].blue * (10 - alpha) + tint->blue * alpha) / 10;
+ gdk_colormap_alloc_color(gdk_colormap_get_system(), &color, FALSE, TRUE);
+ gtk_widget_modify_bg(widget, j, &color);
+ }
+}
+
+
+static void set_data(GtkBuilder *ui, const gchar *object_name, const gchar *name, const gpointer value)
+{
+ GObject *object;
+ object = gtk_builder_get_object(ui, object_name);
+ if (object)
+ g_object_set_data(object, name, value);
+}
+
+static void set_string_data(GtkBuilder *ui, const gchar *object_name, const gchar *name, const char *value)
+{
+ GObject *object;
+ object = gtk_builder_get_object(ui, object_name);
+ if (object)
+ g_object_set_data(object, name, (gpointer)value); // FIXME: Copy?
+}
+
+static void set_int_data(GtkBuilder *ui, const gchar *object_name, const gchar *name, gint value)
+{
+ set_data(ui, object_name, name, GINT_TO_POINTER(value));
+}
+
+
+void
+ui_load_mode(GCalctoolUI *ui, ModeType mode)
+{
+ GtkBuilder *builder, **builder_ptr;
+ gint i;
+ gchar name[MAXLINE];
+ GdkColor colour_numbers, colour_action, colour_operator, colour_function, colour_memory, colour_trig, colour_group;
+ const gchar *builder_file;
+ gchar *objects[] = { "button_panel", NULL };
+ GtkWidget *widget, **panel;
+
+ colour_numbers.red = 0;
+ colour_numbers.green = 0;
+ colour_numbers.blue = 65535;
+ colour_action.red = 0;
+ colour_action.green = 65535;
+ colour_action.blue = 0;
+ colour_operator.red = 65535;
+ colour_operator.green = 0;
+ colour_operator.blue = 0;
+ colour_function.red = 0;
+ colour_function.green = 65535;
+ colour_function.blue = 65535;
+ colour_memory.red = 65535;
+ colour_memory.green = 0;
+ colour_memory.blue = 65535;
+ colour_trig.red = 65535;
+ colour_trig.green = 65535;
+ colour_trig.blue = 0;
+ colour_group.red = 65535;
+ colour_group.green = 65535;
+ colour_group.blue = 65535;
+
+ // FIXME
+ /* Get labels from popup menus */
+ for (i = 0; registers[i]; i++) {
+ SNPRINTF(name, MAXLINE, "store_menu_item%d", i);
+ widget = GET_WIDGET(ui->ui, name);
+ g_object_set_data(G_OBJECT(widget), "register_id", registers[i]);
+ ui->memory_store_labels[i] = gtk_bin_get_child(GTK_BIN(widget));
+
+ SNPRINTF(name, MAXLINE, "recall_menu_item%d", i);
+ widget = GET_WIDGET(ui->ui, name);
+ g_object_set_data(G_OBJECT(widget), "register_id", registers[i]);
+ ui->memory_recall_labels[i] = gtk_bin_get_child(GTK_BIN(widget));
+ }
+
+ switch (mode) {
+ case BASIC:
+ builder_ptr = &ui->basic_ui;
+ builder_file = UI_BASIC_FILE;
+ panel = &ui->bas_panel;
+ break;
+ case ADVANCED:
+ builder_ptr = &ui->advanced_ui;
+ builder_file = UI_ADVANCED_FILE;
+ panel = &ui->adv_panel;
+ break;
+ case FINANCIAL:
+ builder_ptr = &ui->financial_ui;
+ builder_file = UI_FINANCIAL_FILE;
+ panel = &ui->fin_panel;
+ break;
+ case PROGRAMMING:
+ builder_ptr = &ui->programming_ui;
+ builder_file = UI_PROGRAMMING_FILE;
+ panel = &ui->prog_panel;
+ break;
+ }
+
+ builder = *builder_ptr = gtk_builder_new();
+ // FIXME: Show dialog if failed to load
+ gtk_builder_add_objects_from_file(builder, builder_file, objects, NULL);
+ *panel = GET_WIDGET(builder, "button_panel");
+ gtk_box_pack_end(GTK_BOX(ui->button_vbox), *panel, FALSE, TRUE, 0);
+ gtk_widget_realize(*panel);
+
+ /* Connect text to buttons */
+ for (i = 0; button_data[i].widget_name != NULL; i++) {
+ SNPRINTF(name, MAXLINE, "calc_%s_button", button_data[i].widget_name);
+ set_string_data(builder, name, "calc_text", button_data[i].data);
+ }
+
+ /* Localize buttons */
+ for (i = 0; i < 16; i++) {
+ GtkWidget *button;
+
+ SNPRINTF(name, MAXLINE, "calc_%d_button", i);
+ button = GET_WIDGET(builder, name);
+
+ if (button) {
+ gtk_button_set_label(GTK_BUTTON(button), v->digits[i]);
+ set_string_data(builder, name, "calc_text", v->digits[i]);
+ }
+ }
+ widget = GET_WIDGET(builder, "calc_numeric_point_button");
+ if (widget)
+ gtk_button_set_label(GTK_BUTTON(widget), v->radix);
+
+ /* Connect super and subscript */
+ for (i = 0; i < 10; i++) {
+ SNPRINTF(name, MAXLINE, "calc_%d_button", i);
+ set_string_data(builder, name, "calc_subscript_text", subscript_digits[i]);
+ set_string_data(builder, name, "calc_superscript_text", superscript_digits[i]);
+ set_tint(GET_WIDGET(builder, name), &colour_numbers, 1);
+ }
+
+ widget = GET_WIDGET(builder, "superscript_togglebutton");
+ if (widget) {
+ ui->superscript_toggles = g_list_append(ui->superscript_toggles, widget);
+ if (ui->number_mode == SUPERSCRIPT)
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), TRUE);
+ }
+ widget = GET_WIDGET(builder, "subscript_togglebutton");
+ if (widget) {
+ ui->subscript_toggles = g_list_append(ui->subscript_toggles, widget);
+ if (ui->number_mode == SUBSCRIPT)
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), TRUE);
+ }
+
+ set_tint(GET_WIDGET(builder, "calc_10_button"), &colour_numbers, 1);
+ set_tint(GET_WIDGET(builder, "calc_11_button"), &colour_numbers, 1);
+ set_tint(GET_WIDGET(builder, "calc_12_button"), &colour_numbers, 1);
+ set_tint(GET_WIDGET(builder, "calc_13_button"), &colour_numbers, 1);
+ set_tint(GET_WIDGET(builder, "calc_14_button"), &colour_numbers, 1);
+ set_tint(GET_WIDGET(builder, "calc_15_button"), &colour_numbers, 1);
+ set_tint(GET_WIDGET(builder, "calc_imaginary_button"), &colour_numbers, 1);
+ set_tint(GET_WIDGET(builder, "calc_pi_button"), &colour_numbers, 1);
+ set_tint(GET_WIDGET(builder, "calc_eulers_number_button"), &colour_numbers, 1);
+ set_tint(GET_WIDGET(builder, "calc_numeric_point_button"), &colour_numbers, 1);
+ set_tint(GET_WIDGET(builder, "calc_percentage_button"), &colour_numbers, 2);
+ set_tint(GET_WIDGET(builder, "subscript_togglebutton"), &colour_numbers, 2);
+ set_tint(GET_WIDGET(builder, "superscript_togglebutton"), &colour_numbers, 2);
+ set_tint(GET_WIDGET(builder, "calc_exponential_button"), &colour_numbers, 2);
+ set_tint(GET_WIDGET(builder, "calc_base_2_button"), &colour_numbers, 1);
+ set_tint(GET_WIDGET(builder, "calc_base_8_button"), &colour_numbers, 1);
+ set_tint(GET_WIDGET(builder, "calc_base_16_button"), &colour_numbers, 1);
+
+ set_tint(GET_WIDGET(builder, "calc_result_button"), &colour_action, 2);
+ set_tint(GET_WIDGET(builder, "calc_factor_button"), &colour_action, 2);
+ set_tint(GET_WIDGET(builder, "calc_clear_button"), &colour_action, 1); // Different colour?
+ set_tint(GET_WIDGET(builder, "calc_trunc_button"), &colour_action, 1);
+ set_tint(GET_WIDGET(builder, "calc_shift_left_button"), &colour_action, 1);
+ set_tint(GET_WIDGET(builder, "calc_shift_right_button"), &colour_action, 1);
+
+ set_tint(GET_WIDGET(builder, "calc_add_button"), &colour_operator, 1);
+ set_tint(GET_WIDGET(builder, "calc_subtract_button"), &colour_operator, 1);
+ set_tint(GET_WIDGET(builder, "calc_multiply_button"), &colour_operator, 1);
+ set_tint(GET_WIDGET(builder, "calc_divide_button"), &colour_operator, 1);
+ set_tint(GET_WIDGET(builder, "calc_modulus_divide_button"), &colour_operator, 1);
+ set_tint(GET_WIDGET(builder, "calc_and_button"), &colour_operator, 1);
+ set_tint(GET_WIDGET(builder, "calc_or_button"), &colour_operator, 1);
+ set_tint(GET_WIDGET(builder, "calc_xor_button"), &colour_operator, 1);
+
+ set_tint(GET_WIDGET(builder, "calc_cosine_button"), &colour_trig, 1);
+ set_tint(GET_WIDGET(builder, "calc_sine_button"), &colour_trig, 1);
+ set_tint(GET_WIDGET(builder, "calc_tangent_button"), &colour_trig, 1);
+ set_tint(GET_WIDGET(builder, "calc_hyperbolic_cosine_button"), &colour_trig, 1);
+ set_tint(GET_WIDGET(builder, "calc_hyperbolic_sine_button"), &colour_trig, 1);
+ set_tint(GET_WIDGET(builder, "calc_hyperbolic_tangent_button"), &colour_trig, 1);
+
+ set_tint(GET_WIDGET(builder, "calc_start_group_button"), &colour_group, 1);
+ set_tint(GET_WIDGET(builder, "calc_end_group_button"), &colour_group, 1);
+ set_tint(GET_WIDGET(builder, "calc_store_button"), &colour_memory, 1);
+ set_tint(GET_WIDGET(builder, "calc_recall_button"), &colour_memory, 1);
+ set_tint(GET_WIDGET(builder, "calc_ans_button"), &colour_memory, 1);
+ set_tint(GET_WIDGET(builder, "calc_random_button"), &colour_memory, 1);
+ set_tint(GET_WIDGET(builder, "calc_character_button"), &colour_memory, 1);
+
+ set_tint(GET_WIDGET(builder, "calc_integer_portion_button"), &colour_function, 1);
+ set_tint(GET_WIDGET(builder, "calc_fractional_portion_button"), &colour_function, 1);
+ set_tint(GET_WIDGET(builder, "calc_x_pow_y_button"), &colour_function, 1);
+ set_tint(GET_WIDGET(builder, "calc_factorial_button"), &colour_function, 1);
+ set_tint(GET_WIDGET(builder, "calc_root_button"), &colour_function, 1);
+ set_tint(GET_WIDGET(builder, "calc_abs_button"), &colour_function, 1);
+ set_tint(GET_WIDGET(builder, "calc_inverse_button"), &colour_function, 1);
+ set_tint(GET_WIDGET(builder, "calc_logarithm_button"), &colour_function, 1);
+ set_tint(GET_WIDGET(builder, "calc_natural_logarithm_button"), &colour_function, 1);
+ set_tint(GET_WIDGET(builder, "calc_ones_complement_button"), &colour_function, 1);
+ set_tint(GET_WIDGET(builder, "calc_twos_complement_button"), &colour_function, 1);
+ set_tint(GET_WIDGET(builder, "calc_not_button"), &colour_function, 1);
+// set_tint(GET_WIDGET(builder, "calc__button"), &colour_function, 1);
+
+ /* Set base button data */
+ set_int_data(builder, "calc_base_2_button", "base", 2);
+ set_int_data(builder, "calc_base_8_button", "base", 8);
+ set_int_data(builder, "calc_base_16_button", "base", 16);
+
+ /* Connect menus to popup buttons */
+ set_data(builder, "calc_shift_left_button", "calc_menu", GET_WIDGET(builder, "left_shift_popup"));
+ set_data(builder, "calc_shift_right_button", "calc_menu", GET_WIDGET(builder, "right_shift_popup"));
+ set_data(builder, "calc_store_button", "calc_menu", GET_WIDGET(builder, "memory_store_popup"));
+ set_data(builder, "calc_recall_button", "calc_menu", GET_WIDGET(builder, "memory_recall_popup"));
+
+ /* Load bit panel */
+ if (mode == PROGRAMMING) {
+ for (i = 0; i < MAXBITS; i++) {
+ SNPRINTF(name, MAXLINE, "bit_label_%d", i);
+ ui->bit_labels[i] = GET_WIDGET(builder, name);
+ SNPRINTF(name, MAXLINE, "bit_eventbox_%d", i);
+ set_int_data(builder, name, "bit_index", i);
+ }
+ }
+
+ /* Setup financial functions */
+ if (mode == FINANCIAL) {
+ set_data(builder, "calc_finc_compounding_term_button", "finc_dialog", "ctrm_dialog");
+ set_data(builder, "calc_finc_double_declining_depreciation_button", "finc_dialog", "ddb_dialog");
+ set_data(builder, "calc_finc_future_value_button", "finc_dialog", "fv_dialog");
+ set_data(builder, "calc_finc_gross_profit_margin_button", "finc_dialog", "gpm_dialog");
+ set_data(builder, "calc_finc_periodic_payment_button", "finc_dialog", "pmt_dialog");
+ set_data(builder, "calc_finc_present_value_button", "finc_dialog", "pv_dialog");
+ set_data(builder, "calc_finc_periodic_interest_rate_button", "finc_dialog", "rate_dialog");
+ set_data(builder, "calc_finc_straight_line_depreciation_button", "finc_dialog", "sln_dialog");
+ set_data(builder, "calc_finc_sum_of_the_years_digits_depreciation_button", "finc_dialog", "syd_dialog");
+ set_data(builder, "calc_finc_term_button", "finc_dialog", "term_dialog");
+ }
+
+ gtk_builder_connect_signals(builder, ui);
+}
+
+
+G_MODULE_EXPORT
+void
+base_cb(GtkWidget *widget, GCalctoolUI *ui)
+{
+ ui_set_base(ui, GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "base")));
+}
+
+
+G_MODULE_EXPORT
+void
+exponent_cb(GtkWidget *widget, GCalctoolUI *ui)
+{
+ ui_do_exponent(ui);
+}
+
+
+G_MODULE_EXPORT
+void
+subtract_cb(GtkWidget *widget, GCalctoolUI *ui)
+{
+ ui_do_subtract(ui);
+}
+
+
+G_MODULE_EXPORT
+void
+button_cb(GtkWidget *widget, GCalctoolUI *ui)
+{
+ ui_insert_text(ui, g_object_get_data(G_OBJECT(widget), "calc_text"));
+}
+
+
+G_MODULE_EXPORT
+void
+store_menu_cb(GtkMenuItem *menu, GCalctoolUI *ui)
+{
+ ui_do_button(ui, FN_STORE, g_object_get_data(G_OBJECT(menu), "register_id"));
+}
+
+
+G_MODULE_EXPORT
+void
+recall_menu_cb(GtkMenuItem *menu, GCalctoolUI *ui)
+{
+ ui_do_button(ui, FN_RECALL, g_object_get_data(G_OBJECT(menu), "register_id"));
+}
+
+
+G_MODULE_EXPORT
+void
+solve_cb(GtkWidget *widget, GCalctoolUI *ui)
+{
+ ui_do_button(ui, FN_CALCULATE, NULL);
+}
+
+
+G_MODULE_EXPORT
+void
+clear_cb(GtkWidget *widget, GCalctoolUI *ui)
+{
+ ui_do_button(ui, FN_CLEAR, NULL);
+}
+
+
+G_MODULE_EXPORT
+void
+finc_cb(GtkWidget *widget, GCalctoolUI *ui)
+{
+ gchar *name;
+
+ if (ui->financial == NULL)
+ ui_setup_finc_dialogs(ui);
+ name = g_object_get_data(G_OBJECT(widget), "finc_dialog");
+ gtk_dialog_run(GTK_DIALOG(GET_WIDGET(ui->financial, name)));
+ gtk_widget_hide(GTK_WIDGET(GET_WIDGET(ui->financial, name)));
+}
+
+
+static void
+position_popup(GtkWidget *base, GtkWidget *popup,
+ PopupLocation location_op)
+{
+ int base_x, base_y, base_width, base_height;
+ int popup_x, popup_y, popup_width, popup_height;
+ int screen_width, screen_height;
+ int n;
+
+ gtk_window_get_position(GTK_WINDOW(base), &base_x, &base_y);
+ gtk_window_get_size(GTK_WINDOW(base), &base_width, &base_height);
+ gtk_window_get_position(GTK_WINDOW(popup), &popup_x, &popup_y);
+ gtk_window_get_size(GTK_WINDOW(popup), &popup_width, &popup_height);
+ screen_width = gdk_screen_width();
+ screen_height = gdk_screen_height();
+
+ if (location_op == POPUP_LOR) {
+ if (base_x >= screen_width - base_width - base_x)
+ location_op = POPUP_LEFT;
+ else
+ location_op = POPUP_RIGHT;
+ } else if (location_op == POPUP_AOB) {
+ if (base_y > screen_height - base_height - base_y)
+ location_op = POPUP_ABOVE;
+ else
+ location_op = POPUP_BELOW;
+ }
+
+ switch (location_op) {
+ case POPUP_RIGHT:
+ popup_x = base_x + base_width + WM_WIDTH_FACTOR;
+ popup_y = base_y;
+ break;
+
+ case POPUP_LEFT:
+ popup_x = base_x - popup_width - WM_WIDTH_FACTOR;
+ popup_y = base_y;
+ break;
+
+ case POPUP_ABOVE:
+ popup_x = base_x;
+ popup_y = base_y - popup_height - WM_HEIGHT_FACTOR;
+ break;
+
+ case POPUP_BELOW:
+ popup_x = base_x;
+ popup_y = base_y + base_height + WM_HEIGHT_FACTOR;
+ break;
+
+ case POPUP_CENTERED:
+ default:
+ popup_x = base_x + (base_width - popup_width) / 2;
+ popup_y = base_y + (base_height - popup_height) / 2;
+ break;
+ }
+
+ /* Make sure frame doesn't go off side of screen */
+ n = popup_x + popup_width;
+ if (n > screen_width)
+ popup_x -= (n - screen_width);
+ else if (popup_x < 0)
+ popup_x = 0;
+
+ /* Make sure frame doesn't go off top or bottom */
+ n = popup_y + popup_height;
+ if (n > screen_height)
+ popup_y -= n - screen_height;
+ else if (popup_y < 0)
+ popup_y = 0;
+
+ gtk_window_move(GTK_WINDOW(popup), popup_x, popup_y);
+}
+
+
+G_MODULE_EXPORT
+void
+insert_ascii_cb(GtkWidget *widget, GCalctoolUI *ui)
+{
+ ui_create_dialogs(ui);
+
+ if (!gtk_widget_get_visible(ui->ascii_dialog))
+ position_popup(ui->main_window, ui->ascii_dialog, POPUP_LEFT);
+ gtk_widget_grab_focus(GTK_WIDGET(ui->ascii_entry));
+ gtk_widget_show(ui->ascii_dialog);
+}
+
+
+G_MODULE_EXPORT
+void
+shift_cb(GtkWidget *widget, GCalctoolUI *ui)
+{
+ ui_do_button(ui, FN_SHIFT, g_object_get_data(G_OBJECT(widget), "shiftcount"));
+}
+
+G_MODULE_EXPORT
+void
+factorize_cb(GtkWidget *widget, GCalctoolUI *ui)
+{
+ ui_do_button(ui, FN_FACTORIZE, NULL);
+}
+
+
+G_MODULE_EXPORT
+void
+digit_cb(GtkWidget *widget, GCalctoolUI *ui)
+{
+ if (ui->number_mode == SUPERSCRIPT)
+ ui_insert_text(ui, g_object_get_data(G_OBJECT(widget), "calc_superscript_text"));
+ else if (ui->number_mode == SUBSCRIPT)
+ ui_insert_text(ui, g_object_get_data(G_OBJECT(widget), "calc_subscript_text"));
+ else
+ ui_insert_text(ui, g_object_get_data(G_OBJECT(widget), "calc_text"));
+}
+
+
+static void
+update_memory_menus(GCalctoolUI *ui)
+{
+ int i;
+
+ for (i = 0; registers[i] != NULL; i++) {
+ char value[MAXLINE] = "", mstr[MAXLINE];
+ MPNumber *t;
+
+ t = register_get_value(registers[i]);
+ if (t)
+ display_make_number(&v->display, value, MAXLINE, t);
+ SNPRINTF(mstr, MAXLINE, "<span weight=\"bold\">%s</span> = %s", registers[i], value);
+ gtk_label_set_markup_with_mnemonic(GTK_LABEL(ui->memory_store_labels[i]), mstr);
+ gtk_label_set_markup_with_mnemonic(GTK_LABEL(ui->memory_recall_labels[i]), mstr);
+ }
+}
+
+
+G_MODULE_EXPORT
+void
+popup_cb(GtkWidget *widget, GCalctoolUI *ui)
+{
+ GtkWidget *menu;
+ GdkPoint loc;
+
+ update_memory_menus(ui);
+
+ menu = (GtkWidget *)g_object_get_data(G_OBJECT(widget), "calc_menu");
+ gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
+ 1, 0);
+}
+
+G_MODULE_EXPORT
+void
+ascii_dialog_response_cb(GtkWidget *dialog, gint response_id, GCalctoolUI *ui)
+{
+ const gchar *text;
+
+ text = gtk_entry_get_text(GTK_ENTRY(ui->ascii_entry));
+
+ if (response_id == GTK_RESPONSE_OK)
+ ui_do_button(ui, FN_INSERT_CHARACTER, (gpointer) text);
+
+ gtk_widget_hide(dialog);
+}
+
+
+G_MODULE_EXPORT
+void
+ascii_dialog_activate_cb(GtkWidget *entry, GCalctoolUI *ui)
+{
+ ascii_dialog_response_cb(ui->ascii_dialog, GTK_RESPONSE_OK, ui);
+}
+
+
+G_MODULE_EXPORT
+gboolean
+ascii_dialog_delete_cb(GtkWidget *dialog, GCalctoolUI *ui)
+{
+ ascii_dialog_response_cb(dialog, GTK_RESPONSE_CANCEL, ui);
+ return TRUE;
+}
+
+
+G_MODULE_EXPORT
+gboolean
+bit_toggle_cb(GtkWidget *event_box, GdkEventButton *event, GCalctoolUI *ui)
+{
+ ui_do_button(ui, FN_TOGGLE_BIT,
+ g_object_get_data(G_OBJECT(event_box), "bit_index"));
+ return TRUE;
+}
+
+
+
+G_MODULE_EXPORT
+void
+set_superscript_cb(GtkWidget *widget, GCalctoolUI *ui)
+{
+ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
+ ui->can_super_minus = TRUE;
+ ui_set_number_mode(ui, SUPERSCRIPT);
+ }
+ else {
+ ui->can_super_minus = FALSE;
+ if (ui->number_mode == SUPERSCRIPT)
+ ui_set_number_mode(ui, NORMAL);
+ }
+}
+
+
+G_MODULE_EXPORT
+void
+set_subscript_cb(GtkWidget *widget, GCalctoolUI *ui)
+{
+ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
+ ui_set_number_mode(ui, SUBSCRIPT);
+ else if (ui->number_mode == SUBSCRIPT)
+ ui_set_number_mode(ui, NORMAL);
+}
diff --git a/src/ui-buttons.h b/src/ui-buttons.h
new file mode 100644
index 0000000..c846400
--- /dev/null
+++ b/src/ui-buttons.h
@@ -0,0 +1,24 @@
+/* Copyright (c) 2008-2009 Robert Ancell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef UI_BUTTONS_H
+#define UI_BUTTONS_H
+
+#include "ui.h"
+
+#endif /* UI_BUTTONS_H */
diff --git a/src/ui-display.c b/src/ui-display.c
new file mode 100644
index 0000000..86de091
--- /dev/null
+++ b/src/ui-display.c
@@ -0,0 +1,495 @@
+/* Copyright (c) 2008-2009 Robert Ancell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <gdk/gdkkeysyms.h>
+
+#include "ui-display.h"
+#include "ui-internal.h"
+
+gchar *
+ui_get_display(GCalctoolUI *ui)
+{
+ GtkTextIter start, end;
+ gtk_text_buffer_get_bounds(ui->display_buffer, &start, &end);
+ return gtk_text_buffer_get_text(ui->display_buffer, &start, &end, FALSE);
+}
+
+
+void
+ui_insert_text(GCalctoolUI *ui, const char *text)
+{
+ ui_do_button(ui, FN_TEXT, (gpointer) text);
+}
+
+
+static gboolean
+redo_display(GCalctoolUI *ui)
+{
+ gchar *text;
+ GtkTextIter start, end, cursor;
+ gint cursor_position;
+
+ gtk_text_buffer_get_start_iter(ui->display_buffer, &start);
+ gtk_text_buffer_get_end_iter(ui->display_buffer, &end);
+ text = gtk_text_buffer_get_text(ui->display_buffer, &start, &end, FALSE);
+
+ g_object_get(G_OBJECT(ui->display_buffer), "cursor-position", &cursor_position, NULL);
+
+ gtk_text_buffer_set_text(ui->display_buffer, text, -1);
+ gtk_text_buffer_get_iter_at_offset(ui->display_buffer, &cursor, cursor_position);
+ gtk_text_buffer_place_cursor(ui->display_buffer, &cursor);
+
+ g_free(text);
+
+ return FALSE;
+}
+
+
+void
+ui_set_display(GCalctoolUI *ui, char *str, int cursor)
+{
+ GtkTextIter iter;
+ GtkAdjustment *adj;
+
+ gtk_text_buffer_set_text(ui->display_buffer, str, -1);
+
+ if (cursor < 0)
+ gtk_text_buffer_get_end_iter(ui->display_buffer, &iter);
+ else
+ gtk_text_buffer_get_iter_at_offset(ui->display_buffer, &iter, cursor);
+ gtk_text_buffer_place_cursor(ui->display_buffer, &iter);
+ gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(ui->display_item), &iter, 0.0, TRUE, 1.0, 0.0);
+
+ /* This is a workaround for bug #524602.
+ * Basically the above code can cause the display to disappear when going from
+ * a display that is wider than the widget to one that is thinner. The following
+ * causes the display to be set twice which seems to work the second time.
+ */
+ g_idle_add((GSourceFunc)redo_display, ui);
+
+ /* Align to the right */
+ if (cursor < 0) {
+ adj = gtk_scrolled_window_get_hadjustment(
+ GTK_SCROLLED_WINDOW(ui->scrolledwindow));
+ gtk_adjustment_set_value(adj, gtk_adjustment_get_upper(adj) - gtk_adjustment_get_page_size(adj));
+ }
+}
+
+
+void
+ui_do_button(GCalctoolUI *ui, int function, gpointer arg)
+{
+ GtkTextIter start, end;
+ gint cursor_start, cursor_end;
+
+ /* Can't enter superscript minus after entering digits */
+ if (function == FN_TEXT && strstr("�¹²³������", (char *)arg) != NULL)
+ ui->can_super_minus = FALSE;
+
+ /* Disable super/subscript mode when finished entering */
+ if (function == FN_CALCULATE ||
+ function == FN_CLEAR ||
+ (function == FN_TEXT && strstr("â?»â?°Â¹Â²Â³â?´â?µâ?¶â?·â?¸â?¹â??â??â??â??â??â??â??â??â??â??", (char *)arg) == NULL)) {
+ ui_set_number_mode(ui, NORMAL);
+ }
+
+ if (gtk_text_buffer_get_selection_bounds(ui->display_buffer, &start, &end)) {
+ cursor_start = gtk_text_iter_get_offset(&start);
+ cursor_end = gtk_text_iter_get_offset(&end);
+ }
+ else {
+ g_object_get(G_OBJECT(ui->display_buffer), "cursor-position", &cursor_start, NULL);
+ if (cursor_start == gtk_text_buffer_get_char_count(ui->display_buffer))
+ cursor_start = -1;
+ cursor_end = cursor_start;
+ }
+
+ /* Some keyboards don't have a '^' button so convert two multiplies to one '^' */
+ if (cursor_start == cursor_end &&
+ function == FN_TEXT && ui->last_text != NULL &&
+ strcmp((char *)arg, "Ã?") == 0 && strcmp(ui->last_text, "Ã?") == 0) {
+ ui_do_button(ui, FN_BACKSPACE, NULL);
+ ui_do_button(ui, FN_TEXT, "^");
+ }
+ else {
+ display_do_function(&v->display, function, arg, cursor_start, cursor_end);
+ if (function == FN_TEXT)
+ ui->last_text = (char *)arg;
+ else
+ ui->last_text = NULL;
+ }
+}
+
+
+void
+ui_display_copy(GCalctoolUI *ui)
+{
+ gchar *string = NULL;
+ GtkTextIter start, end;
+
+ if (gtk_text_buffer_get_selection_bounds(ui->display_buffer, &start, &end) == TRUE)
+ string = gtk_text_buffer_get_text(ui->display_buffer, &start, &end, FALSE);
+ else
+ string = ui_get_display(ui);
+
+ if (ui->shelf != NULL)
+ g_free(ui->shelf);
+ ui->shelf = g_locale_from_utf8(string, strlen(string), NULL, NULL, NULL);
+ g_free(string);
+
+ gtk_clipboard_set_text(gtk_clipboard_get(ui->clipboard_atom), ui->shelf, -1);
+}
+
+
+void
+ui_do_exponent(GCalctoolUI *ui)
+{
+ ui_insert_text(ui, "Ã?10");
+ ui_set_number_mode(ui, SUPERSCRIPT);
+}
+
+
+void
+ui_do_subtract(GCalctoolUI *ui)
+{
+ if (ui->can_super_minus) {
+ ui_insert_text(ui, "â?»");
+ ui->can_super_minus = FALSE;
+ }
+ else {
+ ui_insert_text(ui, "â??");
+ ui_set_number_mode(ui, NORMAL);
+ }
+}
+
+
+static gboolean
+check_for_localized_numeric_point(int keyval)
+{
+ gchar outbuf[10]; /* Minumum size 6. */
+ gunichar ch;
+
+ ch = gdk_keyval_to_unicode(keyval);
+ g_return_val_if_fail(g_unichar_validate(ch), FALSE);
+
+ outbuf[g_unichar_to_utf8(ch, outbuf)] = '\0';
+
+ return (strcmp(outbuf, v->radix) == 0);
+}
+
+
+// FIXME: Should be able to replace by making display can_default
+G_MODULE_EXPORT
+gboolean
+main_window_key_press_cb(GtkWidget *widget, GdkEventKey *event, GCalctoolUI *ui)
+{
+ int i, state;
+ const char *conversions[] = {"*", "/", NULL};
+ const char *conversion_values[] = {"�", "÷", NULL };
+
+ /* Only look at the modifiers we use */
+ state = event->state & (GDK_CONTROL_MASK | GDK_MOD1_MASK);
+
+ // FIXME: Convert event to character
+ // FIXME: Or safer to intercept characters as they enter the text input (handles input methods)
+
+ if (check_for_localized_numeric_point(event->keyval) == TRUE) {
+ event->state = 0;
+ event->keyval = GDK_KP_Decimal;
+ }
+
+ /* Shortcuts */
+ if (state == GDK_CONTROL_MASK) {
+ switch(event->keyval)
+ {
+ case GDK_b:
+ ui_set_base(ui, 2);
+ return TRUE;
+ case GDK_d:
+ ui_set_base(ui, 10);
+ return TRUE;
+ case GDK_e:
+ ui_do_exponent(ui);
+ return TRUE;
+ case GDK_f:
+ ui_do_button(ui, FN_FACTORIZE, NULL);
+ return TRUE;
+ case GDK_h:
+ ui_set_base(ui, 16);
+ return TRUE;
+ case GDK_i:
+ ui_insert_text(ui, "�¹");
+ return TRUE;
+ case GDK_o:
+ ui_set_base(ui, 8);
+ return TRUE;
+ case GDK_p:
+ ui_insert_text(ui, "Ï?");
+ return TRUE;
+ case GDK_r:
+ ui_insert_text(ui, "â??");
+ return TRUE;
+ case GDK_u:
+ ui_insert_text(ui, "µ");
+ return TRUE;
+ }
+ }
+ if (state == GDK_CONTROL_MASK || ui->number_mode == SUPERSCRIPT) {
+ switch(event->keyval)
+ {
+ case GDK_0:
+ ui_insert_text(ui, "â?°");
+ return TRUE;
+ case GDK_1:
+ ui_insert_text(ui, "¹");
+ return TRUE;
+ case GDK_2:
+ ui_insert_text(ui, "²");
+ return TRUE;
+ case GDK_3:
+ ui_insert_text(ui, "³");
+ return TRUE;
+ case GDK_4:
+ ui_insert_text(ui, "â?´");
+ return TRUE;
+ case GDK_5:
+ ui_insert_text(ui, "â?µ");
+ return TRUE;
+ case GDK_6:
+ ui_insert_text(ui, "â?¶");
+ return TRUE;
+ case GDK_7:
+ ui_insert_text(ui, "â?·");
+ return TRUE;
+ case GDK_8:
+ ui_insert_text(ui, "â?¸");
+ return TRUE;
+ case GDK_9:
+ ui_insert_text(ui, "â?¹");
+ return TRUE;
+ }
+ }
+ else if (state == GDK_MOD1_MASK || ui->number_mode == SUBSCRIPT) {
+ switch(event->keyval)
+ {
+ case GDK_0:
+ ui_insert_text(ui, "â??");
+ return TRUE;
+ case GDK_1:
+ ui_insert_text(ui, "â??");
+ return TRUE;
+ case GDK_2:
+ ui_insert_text(ui, "â??");
+ return TRUE;
+ case GDK_3:
+ ui_insert_text(ui, "â??");
+ return TRUE;
+ case GDK_4:
+ ui_insert_text(ui, "â??");
+ return TRUE;
+ case GDK_5:
+ ui_insert_text(ui, "â??");
+ return TRUE;
+ case GDK_6:
+ ui_insert_text(ui, "â??");
+ return TRUE;
+ case GDK_7:
+ ui_insert_text(ui, "â??");
+ return TRUE;
+ case GDK_8:
+ ui_insert_text(ui, "â??");
+ return TRUE;
+ case GDK_9:
+ ui_insert_text(ui, "â??");
+ return TRUE;
+ }
+ }
+
+ /* Delete in display */
+ if (event->keyval == GDK_Delete && state == 0 && (event->state & GDK_SHIFT_MASK) == 0) {
+ ui_do_button(ui, FN_DELETE, NULL);
+ return TRUE;
+ }
+ if (event->keyval == GDK_BackSpace && state == 0 && (event->state & GDK_SHIFT_MASK) == 0) {
+ ui_do_button(ui, FN_BACKSPACE, NULL);
+ return TRUE;
+ }
+
+ /* Clear display */
+ if ((event->keyval == GDK_Escape && state == 0) ||
+ (event->keyval == GDK_BackSpace && state == GDK_CONTROL_MASK) ||
+ (event->keyval == GDK_Delete && state == GDK_SHIFT_MASK)) {
+ ui_do_button(ui, FN_CLEAR, NULL);
+ return TRUE;
+ }
+
+ /* Solve */
+ if ((event->keyval == GDK_Return && state == 0) ||
+ (event->keyval == GDK_KP_Enter && state == 0)) {
+ if (gtk_widget_has_focus(ui->display_item)) {
+ ui_do_button(ui, FN_CALCULATE, NULL);
+ return TRUE;
+ }
+ else {
+ return FALSE;
+ }
+ }
+
+ if (state == GDK_CONTROL_MASK && event->keyval == GDK_minus)
+ {
+ ui_insert_text(ui, "â?»");
+ ui->can_super_minus = FALSE;
+ return TRUE;
+ }
+
+ if (state != 0)
+ return FALSE;
+
+ // FIXME: event->string deprecated
+
+ if (strcmp(event->string, "-") == 0 || strcmp(event->string, "â??") == 0) {
+ ui_do_subtract(ui);
+ return TRUE;
+ }
+
+ for (i = 0; conversions[i]; i++) {
+ if (strcmp(event->string, conversions[i]) == 0) {
+ ui_insert_text(ui, conversion_values[i]);
+ return TRUE;
+ }
+ }
+ if (strcmp(event->string, ".") == 0) {
+ ui_insert_text(ui, v->radix);
+ return TRUE;
+ }
+
+ /* Some keyboards use this keyval for '^' (e.g. German) */
+ if (event->keyval == GDK_dead_circumflex) {
+ ui_insert_text(ui, "^");
+ return TRUE;
+ }
+
+ switch(*event->string)
+ {
+ case '\n':
+ ui_do_button(ui, FN_CALCULATE, NULL);
+ return TRUE;
+ }
+
+ /* Don't override space - it is used in UI */
+ if (event->string[0] == ' ' && !gtk_widget_has_focus(ui->display_item))
+ return FALSE;
+
+ if (event->string[0] != '\0') {
+ ui_insert_text(ui, event->string);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+static void
+popup_paste_cb(GtkWidget *menu, GCalctoolUI *ui)
+{
+ ui_display_paste(ui);
+}
+
+
+// FIXME: Kill this
+static void
+for_each_menu(GtkWidget *widget, GCalctoolUI *ui)
+{
+ /* Find the "Paste" entry and activate it (see bug #317786).
+ * It is disabled because the GtkEntry is not marked as editable.
+ */
+ if (strcmp(G_OBJECT_TYPE_NAME(widget), "GtkImageMenuItem") == 0) {
+ GtkWidget *label = gtk_bin_get_child(GTK_BIN(widget));
+
+ if (strcmp(gtk_label_get_text(GTK_LABEL(label)), _("Paste")) == 0) {
+ if (gtk_clipboard_wait_is_text_available(gtk_clipboard_get(ui->clipboard_atom))) {
+ gtk_widget_set_sensitive(GTK_WIDGET(widget), TRUE);
+ g_signal_connect(GTK_OBJECT(widget), "activate",
+ G_CALLBACK(popup_paste_cb), ui);
+ }
+ }
+ }
+}
+
+
+G_MODULE_EXPORT
+void
+buffer_populate_popup_cb(GtkTextView *textview, GtkMenu *menu, GCalctoolUI *ui)
+{
+ gtk_container_foreach(GTK_CONTAINER(menu), (GtkCallback)for_each_menu, ui);
+}
+
+
+static void
+on_paste(GtkClipboard *clipboard, const gchar *text, GCalctoolUI *ui)
+{
+ if (text != NULL)
+ ui_do_button(ui, FN_PASTE, (gpointer) text);
+}
+
+
+void
+ui_display_paste(GCalctoolUI *ui)
+{
+ gtk_clipboard_request_text(gtk_clipboard_get(ui->clipboard_atom),
+ (GtkClipboardTextReceivedFunc)on_paste, ui);
+}
+
+
+G_MODULE_EXPORT
+gboolean
+middle_click_paste_cb(GtkWidget *widget, GdkEventButton *event, GCalctoolUI *ui)
+{
+ if (event->button == 2)
+ ui_display_paste(ui);
+
+ return FALSE;
+}
+
+
+void
+ui_set_base(GCalctoolUI *ui, gint base)
+{
+ /* If has a number already in a base, then solve and convert it */
+ if (!display_is_result(&v->display) && display_is_number_with_base(&v->display))
+ ui_do_button(ui, FN_CALCULATE, NULL);
+
+ if (display_is_result(&v->display)) {
+ if (base == 2)
+ display_convert (&v->display, BIN);
+ else if (base == 8)
+ display_convert (&v->display, OCT);
+ else if (base == 16)
+ display_convert (&v->display, HEX);
+ else
+ display_convert (&v->display, DEC);
+ }
+ else {
+ if (base == 2)
+ ui_insert_text(ui, "â??");
+ else if (base == 8)
+ ui_insert_text(ui, "â??");
+ else if (base == 16)
+ ui_insert_text(ui, "â??â??");
+ }
+}
diff --git a/src/ui-display.h b/src/ui-display.h
new file mode 100644
index 0000000..2222184
--- /dev/null
+++ b/src/ui-display.h
@@ -0,0 +1,31 @@
+/* Copyright (c) 2008-2009 Robert Ancell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef UI_DISPLAY_H
+#define UI_DISPLAY_H
+
+#include "ui.h"
+
+void ui_display_copy(GCalctoolUI *ui);
+void ui_display_paste(GCalctoolUI *ui);
+void ui_insert_text(GCalctoolUI *ui, const char *text);
+void ui_set_base(GCalctoolUI *ui, gint base);
+void ui_do_subtract(GCalctoolUI *ui);
+void ui_do_exponent(GCalctoolUI *ui);
+
+#endif /* UI_DISPLAY_H */
diff --git a/src/ui-financial.c b/src/ui-financial.c
new file mode 100644
index 0000000..d7e766a
--- /dev/null
+++ b/src/ui-financial.c
@@ -0,0 +1,359 @@
+/* Copyright (c) 2008-2009 Robert Ancell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include "ui-financial.h"
+#include "financial.h"
+#include "currency.h"
+
+#define GET_OBJECT(ui, name) \
+ gtk_builder_get_object((ui), (name))
+#define GET_WIDGET(ui, name) \
+ GTK_WIDGET(GET_OBJECT(ui, name))
+
+typedef enum {
+ CURRENCY_TARGET_UPPER,
+ CURRENCY_TARGET_LOWER
+} CurrencyTargetRow;
+
+/* The names of each field in the dialogs for the financial functions */
+static char *finc_dialog_fields[][5] = {
+ {"ctrm_pint", "ctrm_fv", "ctrm_pv", NULL, NULL},
+ {"ddb_cost", "ddb_life", "ddb_period", NULL, NULL},
+ {"fv_pmt", "fv_pint", "fv_n", NULL, NULL},
+ {"gpm_cost", "gpm_margin", NULL, NULL, NULL},
+ {"pmt_prin", "pmt_pint", "pmt_n", NULL, NULL},
+ {"pv_pmt", "pv_pint", "pv_n", NULL, NULL},
+ {"rate_fv", "rate_pv", "rate_n", NULL, NULL},
+ {"sln_cost", "sln_salvage", "sln_life", NULL, NULL},
+ {"syd_cost", "syd_salvage", "syd_life", "syd_period", NULL},
+ {"term_pmt", "term_fv", "term_pint", NULL, NULL},
+ {NULL, NULL, NULL, NULL, NULL}
+};
+
+#define UI_FINC_FILE UI_DIR "/financial.ui"
+
+G_MODULE_EXPORT
+void
+finc_activate_cb(GtkWidget *widget, GCalctoolUI *ui)
+{
+ gint dialog, field;
+
+ dialog = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "finc_dialog"));
+ field = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "finc_field"));
+
+ if (finc_dialog_fields[dialog][field+1] == NULL) {
+ GtkWidget *dialog_widget;
+ dialog_widget = gtk_widget_get_toplevel(widget);
+ if (gtk_widget_is_toplevel (dialog_widget)) {
+ gtk_dialog_response(GTK_DIALOG(dialog_widget),
+ GTK_RESPONSE_OK);
+ return;
+ }
+ }
+ else {
+ GtkWidget *next_widget;
+ next_widget = GET_WIDGET(ui->financial, finc_dialog_fields[dialog][field+1]);
+ gtk_widget_grab_focus(next_widget);
+ }
+}
+
+
+G_MODULE_EXPORT
+void
+finc_response_cb(GtkWidget *widget, gint response_id, GCalctoolUI *ui)
+{
+ int dialog;
+ int i;
+ MPNumber arg[4];
+ GtkWidget *entry;
+
+ if (response_id != GTK_RESPONSE_OK)
+ return;
+
+ dialog = GPOINTER_TO_INT (g_object_get_data(G_OBJECT(widget), "finc_dialog"));
+
+ for (i = 0; i < 4; i++) {
+ if (finc_dialog_fields[dialog][i] == NULL) {
+ continue;
+ }
+ entry = GET_WIDGET(ui->financial, finc_dialog_fields[dialog][i]);
+ // FIXME: Have to delocalize the input
+ mp_set_from_string(gtk_entry_get_text(GTK_ENTRY(entry)), &arg[i]);
+ gtk_entry_set_text(GTK_ENTRY(entry), "0");
+ }
+ gtk_widget_grab_focus(GET_WIDGET(ui->financial, finc_dialog_fields[dialog][0]));
+
+ do_finc_expression(dialog, &arg[0], &arg[1], &arg[2], &arg[3]);
+}
+
+
+static void set_data(GtkBuilder *ui, const gchar *object_name, const gchar *name, const gpointer value)
+{
+ GObject *object;
+ object = gtk_builder_get_object(ui, object_name);
+ if (object)
+ g_object_set_data(object, name, value);
+}
+
+
+static void set_int_data(GtkBuilder *ui, const gchar *object_name, const gchar *name, gint value)
+{
+ set_data(ui, object_name, name, GINT_TO_POINTER(value));
+}
+
+
+void
+ui_setup_finc_dialogs(GCalctoolUI *ui)
+{
+ int i, j;
+ GtkListStore *currency_store;
+ GtkCellRenderer *render;
+ GtkSpinButton *currency_amount_upper;
+ GtkSpinButton *currency_amount_lower;
+ GtkComboBox *currency_type_upper;
+ GtkComboBox *currency_type_lower;
+
+ // FIXME: Handle errors
+ ui->financial = gtk_builder_new();
+ gtk_builder_add_from_file(ui->financial, UI_FINC_FILE, NULL);
+
+ set_int_data(ui->financial, "ctrm_dialog", "finc_dialog", FINC_CTRM_DIALOG);
+ set_int_data(ui->financial, "ddb_dialog", "finc_dialog", FINC_DDB_DIALOG);
+ set_int_data(ui->financial, "fv_dialog", "finc_dialog", FINC_FV_DIALOG);
+ set_int_data(ui->financial, "gpm_dialog", "finc_dialog", FINC_GPM_DIALOG);
+ set_int_data(ui->financial, "pmt_dialog", "finc_dialog", FINC_PMT_DIALOG);
+ set_int_data(ui->financial, "pv_dialog", "finc_dialog", FINC_PV_DIALOG);
+ set_int_data(ui->financial, "rate_dialog", "finc_dialog", FINC_RATE_DIALOG);
+ set_int_data(ui->financial, "sln_dialog", "finc_dialog", FINC_SLN_DIALOG);
+ set_int_data(ui->financial, "syd_dialog", "finc_dialog", FINC_SYD_DIALOG);
+ set_int_data(ui->financial, "term_dialog", "finc_dialog", FINC_TERM_DIALOG);
+
+ for (i = 0; finc_dialog_fields[i][0] != NULL; i++) {
+ for (j = 0; finc_dialog_fields[i][j]; j++) {
+ GObject *o;
+ o = gtk_builder_get_object(ui->financial, finc_dialog_fields[i][j]);
+ g_object_set_data(o, "finc_field", GINT_TO_POINTER(j));
+ g_object_set_data(o, "finc_dialog", GINT_TO_POINTER(i));
+ }
+ }
+
+ currency_amount_upper = GTK_SPIN_BUTTON(gtk_builder_get_object(
+ ui->financial,
+ "currency_amount_upper"));
+ currency_amount_lower = GTK_SPIN_BUTTON(gtk_builder_get_object(
+ ui->financial,
+ "currency_amount_lower"));
+ currency_type_upper = GTK_COMBO_BOX(gtk_builder_get_object(
+ ui->financial,
+ "currency_type_upper"));
+ currency_type_lower = GTK_COMBO_BOX(gtk_builder_get_object(
+ ui->financial,
+ "currency_type_lower"));
+
+ currency_store = gtk_list_store_new(2,
+ G_TYPE_INT,
+ G_TYPE_STRING);
+
+ gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(currency_store),
+ 1,
+ GTK_SORT_ASCENDING);
+
+ gtk_combo_box_set_model(currency_type_upper,
+ GTK_TREE_MODEL(currency_store));
+ gtk_combo_box_set_model(currency_type_lower,
+ GTK_TREE_MODEL(currency_store));
+
+ render = gtk_cell_renderer_text_new();
+
+ gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(currency_type_upper),
+ render,
+ TRUE);
+ gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(currency_type_lower),
+ render,
+ TRUE);
+
+ gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(currency_type_upper),
+ render,
+ "text",
+ 1);
+ gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(currency_type_lower),
+ render,
+ "text",
+ 1);
+
+ set_int_data(ui->financial, "currency_amount_upper", "target", CURRENCY_TARGET_LOWER);
+ set_int_data(ui->financial, "currency_amount_lower", "target", CURRENCY_TARGET_UPPER);
+
+ gtk_builder_connect_signals(ui->financial, ui);
+}
+
+
+static void
+recalculate_currency(GCalctoolUI *ui, CurrencyTargetRow target)
+{
+ int upper_index, lower_index;
+
+ GtkComboBox *combo_upper = GTK_COMBO_BOX(gtk_builder_get_object(
+ ui->financial,
+ "currency_type_upper"));
+ GtkComboBox *combo_lower = GTK_COMBO_BOX(gtk_builder_get_object(
+ ui->financial,
+ "currency_type_lower"));
+ GtkSpinButton *spin_upper = GTK_SPIN_BUTTON(gtk_builder_get_object(
+ ui->financial,
+ "currency_amount_upper"));
+ GtkSpinButton *spin_lower = GTK_SPIN_BUTTON(gtk_builder_get_object(
+ ui->financial,
+ "currency_amount_lower"));
+
+ GtkTreeModel *model = gtk_combo_box_get_model(combo_upper);
+ GtkTreeIter iter;
+
+ if (!gtk_combo_box_get_active_iter(combo_upper, &iter))
+ return;
+ gtk_tree_model_get(model, &iter, 0, &upper_index, -1);
+
+ if (!gtk_combo_box_get_active_iter(combo_lower, &iter))
+ return;
+ gtk_tree_model_get(model, &iter, 0, &lower_index, -1);
+
+ if (target == CURRENCY_TARGET_LOWER) {
+ MPNumber input, output;
+ mp_set_from_double (gtk_spin_button_get_value(spin_upper), &input);
+ currency_convert(&input, upper_index, lower_index, &output);
+ if (!mp_is_zero(&output))
+ gtk_spin_button_set_value(spin_lower, mp_cast_to_double(&output));
+ } else {
+ MPNumber input, output;
+ mp_set_from_double (gtk_spin_button_get_value(spin_lower), &input);
+ currency_convert(&input, lower_index, upper_index, &output);
+ if (!mp_is_zero(&output))
+ gtk_spin_button_set_value(spin_upper, mp_cast_to_double(&output));
+ }
+}
+
+
+G_MODULE_EXPORT
+void
+currency_type_cb(GtkComboBox *combo, gpointer user_data, GCalctoolUI *ui)
+{
+ recalculate_currency(ui, CURRENCY_TARGET_LOWER);
+}
+
+
+G_MODULE_EXPORT
+void
+currency_amount_cb (GtkSpinButton *spinbutton, gpointer user_data, GCalctoolUI *ui)
+{
+ recalculate_currency(ui, GPOINTER_TO_INT(g_object_get_data(G_OBJECT(spinbutton),
+ "target")));
+}
+
+static void
+setup_currency_rates(GCalctoolUI *ui)
+{
+ static int has_run = 0;
+ int i;
+ GtkListStore *currency_store;
+ GObject *currency_type;
+
+ if (has_run)
+ return;
+
+ if (currency_rates_needs_update()) {
+ GtkWidget *dialog = gtk_message_dialog_new(NULL, 0,
+ GTK_MESSAGE_INFO,
+ GTK_BUTTONS_YES_NO,
+ /* Translators: Title of the error dialog when prompting to download currency rates */
+ N_("You don't have any recent currency rates. Should some be downloaded now?"));
+ int response = gtk_dialog_run(GTK_DIALOG(dialog));
+ gtk_widget_destroy(dialog);
+
+ if (response == GTK_RESPONSE_YES) {
+ if (!currency_download_rates()) {
+ dialog = gtk_message_dialog_new(NULL, 0,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ /* Translators: Title of the error dialog when unable to download currency rates */
+ N_("Currency rates could not be downloaded. You may receive inaccurate results, or you may not receive any results at all."));
+ }
+ }
+ }
+ currency_load_rates();
+
+ currency_type = gtk_builder_get_object(ui->financial, "currency_type_upper");
+ currency_store = GTK_LIST_STORE(gtk_combo_box_get_model(
+ GTK_COMBO_BOX(currency_type)));
+
+ for (i = 0; currency_names[i].short_name; i++) {
+ GtkTreeIter iter;
+ int index;
+
+ if ((index = currency_get_index(currency_names[i].short_name)) < 0) {
+ continue;
+ }
+ gtk_list_store_append(currency_store, &iter);
+ gtk_list_store_set(currency_store, &iter,
+ 0, index,
+ 1, gettext(currency_names[i].long_name),
+ -1);
+ }
+
+ has_run = 1;
+}
+
+
+G_MODULE_EXPORT
+void
+currency_cb(GtkWidget *widget, GCalctoolUI *ui)
+{
+ GtkDialog *win;
+ GtkSpinButton *c_amount_upper, *c_amount_lower;
+ MPNumber display_val;
+
+ if (ui->financial == NULL)
+ ui_setup_finc_dialogs(ui);
+
+ setup_currency_rates(ui);
+
+ win = GTK_DIALOG(gtk_builder_get_object(ui->financial, "currency_dialog"));
+ c_amount_upper = GTK_SPIN_BUTTON(gtk_builder_get_object(
+ ui->financial,
+ "currency_amount_upper"));
+ c_amount_lower = GTK_SPIN_BUTTON(gtk_builder_get_object(
+ ui->financial,
+ "currency_amount_lower"));
+ if (display_is_usable_number(&v->display, &display_val)) {
+ double start_val = mp_cast_to_double(&display_val);
+ gtk_spin_button_set_value(c_amount_upper, start_val);
+ }
+ gtk_widget_grab_focus(GTK_WIDGET(c_amount_upper));
+
+ if (gtk_dialog_run(win) == GTK_RESPONSE_OK) {
+ gchar *result;
+
+ result = g_strdup_printf("%.2f",
+ gtk_spin_button_get_value(c_amount_lower));
+ mp_set_from_string(result, &display_val);
+ g_free(result);
+
+ display_set_number(&v->display, &display_val);
+ }
+
+ gtk_widget_hide(GTK_WIDGET(win));
+}
diff --git a/src/ui-financial.h b/src/ui-financial.h
new file mode 100644
index 0000000..8df0c7a
--- /dev/null
+++ b/src/ui-financial.h
@@ -0,0 +1,24 @@
+/* Copyright (c) 2008-2009 Robert Ancell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef UI_FINANCIAL_H
+#define UI_FINANCIAL_H
+
+#include "ui.h"
+
+#endif /* UI_FINANCIAL_H */
diff --git a/src/ui-internal.h b/src/ui-internal.h
new file mode 100644
index 0000000..f3c14d2
--- /dev/null
+++ b/src/ui-internal.h
@@ -0,0 +1,30 @@
+/* Copyright (c) 2008-2009 Robert Ancell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef UI_INTERNAL_H
+#define UI_INTERNAL_H
+
+#include "ui.h"
+
+void ui_load_mode(GCalctoolUI *ui, ModeType mode);
+void ui_do_button(GCalctoolUI *ui, int function, gpointer arg);
+void ui_setup_finc_dialogs(GCalctoolUI *ui);
+void ui_create_dialogs(GCalctoolUI *ui);
+void ui_set_number_mode(GCalctoolUI *ui, NumberMode mode);
+
+#endif /* UI_INTERNAL_H */
diff --git a/src/ui-preferences.c b/src/ui-preferences.c
new file mode 100644
index 0000000..c6fcd1d
--- /dev/null
+++ b/src/ui-preferences.c
@@ -0,0 +1,321 @@
+/* Copyright (c) 2008-2009 Robert Ancell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <gtk/gtk.h>
+
+#include "ui-preferences.h"
+#include "ui-internal.h"
+#include "get.h"
+
+
+#define UI_DIALOGS_FILE UI_DIR "/dialogs.ui"
+
+#define GET_OBJECT(ui, name) \
+ gtk_builder_get_object((ui), (name))
+#define GET_WIDGET(ui, name) \
+ GTK_WIDGET(GET_OBJECT(ui, name))
+
+
+G_MODULE_EXPORT
+void
+preferences_response_cb(GtkWidget *widget, gint id, GCalctoolUI *ui)
+{
+ gtk_widget_hide(ui->preferences_dialog);
+}
+
+
+G_MODULE_EXPORT
+gboolean
+preferences_dialog_delete_cb(GtkWidget *widget, GCalctoolUI *ui)
+{
+ preferences_response_cb(widget, 0, ui);
+ return TRUE;
+}
+
+
+G_MODULE_EXPORT
+void
+angle_unit_combobox_changed_cb(GtkWidget *combo)
+{
+ int i;
+ const gchar *value;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ struct
+ {
+ const gchar *value;
+ MPAngleUnit units;
+ } unit_map[] =
+ {
+ {"degrees", MP_DEGREES},
+ {"radians" , MP_RADIANS},
+ {"gradians", MP_GRADIANS},
+ {NULL, MP_DEGREES}
+ };
+
+ model = gtk_combo_box_get_model(GTK_COMBO_BOX(combo));
+ gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combo), &iter);
+ gtk_tree_model_get(model, &iter, 1, &value, -1);
+ for (i = 0; unit_map[i].value != NULL && strcmp(unit_map[i].value, value) != 0; i++);
+ display_set_angle_unit(&v->display, unit_map[i].units);
+
+ set_resource(R_TRIG, value);
+}
+
+
+G_MODULE_EXPORT
+void
+display_format_combobox_changed_cb(GtkWidget *combo)
+{
+ int i;
+ const gchar *value;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ struct
+ {
+ const gchar *value;
+ DisplayFormat format;
+ } mode_map[] =
+ {
+ {"decimal", DEC},
+ {"binary" , BIN},
+ {"octal", OCT},
+ {"hexadecimal", HEX},
+ {"scientific", SCI},
+ {"engineering", ENG},
+ {NULL, DEC}
+ };
+
+ model = gtk_combo_box_get_model(GTK_COMBO_BOX(combo));
+ gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combo), &iter);
+ gtk_tree_model_get(model, &iter, 1, &value, -1);
+ for (i = 0; mode_map[i].value != NULL && strcmp(mode_map[i].value, value) != 0; i++);
+ display_set_format(&v->display, mode_map[i].format);
+
+ set_resource(R_DISPLAY, value);
+}
+
+
+G_MODULE_EXPORT
+void
+word_size_combobox_changed_cb(GtkWidget *combo)
+{
+ gint value;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+
+ model = gtk_combo_box_get_model(GTK_COMBO_BOX(combo));
+ gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combo), &iter);
+ gtk_tree_model_get(model, &iter, 1, &value, -1);
+ display_set_word_size(&v->display, value);
+
+ set_int_resource(R_WORDLEN, value);
+}
+
+
+G_MODULE_EXPORT
+void
+decimal_places_spin_change_value_cb(GtkWidget *spin)
+{
+ gint value = 0;
+
+ value = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin));
+ display_set_accuracy(&v->display, value);
+
+ set_int_resource(R_ACCURACY, value);
+}
+
+
+G_MODULE_EXPORT
+void
+thousands_separator_check_toggled_cb(GtkWidget *check)
+{
+ gboolean value;
+
+ value = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(check));
+ display_set_show_thousands_separator(&v->display, value);
+ set_boolean_resource(R_TSEP, value);
+}
+
+
+G_MODULE_EXPORT
+void
+trailing_zeroes_check_toggled_cb(GtkWidget *check)
+{
+ gboolean value;
+
+ value = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(check));
+ display_set_show_trailing_zeroes(&v->display, value);
+ set_boolean_resource(R_ZEROES, value);
+}
+
+
+void
+ui_show_preferences(GCalctoolUI *ui)
+{
+ ui_create_dialogs(ui);
+ gtk_window_present(GTK_WINDOW(ui->preferences_dialog));
+}
+
+
+static void
+set_combo_box_from_config(GCalctoolUI *ui, const gchar *name, const gchar *key_name, GType key_type)
+{
+ GtkWidget *combo;
+ GtkTreeModel *model;
+ gchar *str_key_value = NULL;
+ int int_key_value;
+ GtkTreeIter iter;
+ gboolean valid;
+
+ combo = GET_WIDGET(ui->dialog_ui, name);
+ model = gtk_combo_box_get_model(GTK_COMBO_BOX(combo));
+ valid = gtk_tree_model_get_iter_first(model, &iter);
+
+ switch (key_type)
+ {
+ case G_TYPE_STRING:
+ str_key_value = get_resource(key_name);
+ if (!str_key_value)
+ valid = FALSE;
+ break;
+ case G_TYPE_INT:
+ if (!get_int_resource(key_name, &int_key_value))
+ valid = FALSE;
+ break;
+ default:
+ break;
+ }
+
+ while (valid) {
+ gchar *str_value;
+ gint int_value;
+ gboolean matched = FALSE;
+
+ switch (key_type)
+ {
+ case G_TYPE_STRING:
+ gtk_tree_model_get(model, &iter, 1, &str_value, -1);
+ matched = strcmp(str_value, str_key_value) == 0;
+ break;
+ case G_TYPE_INT:
+ gtk_tree_model_get(model, &iter, 1, &int_value, -1);
+ matched = int_value == int_key_value;
+ break;
+ default:
+ break;
+ }
+
+ if (matched)
+ break;
+
+ valid = gtk_tree_model_iter_next(model, &iter);
+ }
+ if (!valid)
+ valid = gtk_tree_model_get_iter_first(model, &iter);
+
+ gtk_combo_box_set_active_iter(GTK_COMBO_BOX(combo), &iter);
+
+ g_free(str_key_value);
+}
+
+
+// FIXME: Take out ascii dialog
+void
+ui_create_dialogs(GCalctoolUI *ui)
+{
+ GtkWidget *widget;
+ GtkCellRenderer *renderer;
+ gchar *string, **tokens;
+ int value;
+
+ if (ui->dialog_ui)
+ return;
+
+ // FIXME: Handle errors
+ ui->dialog_ui = gtk_builder_new();
+ gtk_builder_add_from_file(ui->dialog_ui, UI_DIALOGS_FILE, NULL);
+
+ ui->ascii_dialog = GET_WIDGET(ui->dialog_ui, "ascii_dialog");
+ ui->ascii_entry = GET_WIDGET(ui->dialog_ui, "ascii_entry");
+
+ /* Make dialogs transient of the main window */
+ gtk_window_set_transient_for(GTK_WINDOW(ui->ascii_dialog), GTK_WINDOW(ui->main_window));
+
+ ui->preferences_dialog = GET_WIDGET(ui->dialog_ui, "preferences_dialog");
+
+ /* Configuration dialog */
+
+ widget = GET_WIDGET(ui->dialog_ui, "angle_unit_combobox");
+ renderer = gtk_cell_renderer_text_new();
+ gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(widget), renderer, TRUE);
+ gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(widget), renderer, "text", 0);
+
+ widget = GET_WIDGET(ui->dialog_ui, "display_format_combobox");
+ renderer = gtk_cell_renderer_text_new();
+ gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(widget), renderer, TRUE);
+ gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(widget), renderer, "text", 0);
+
+ widget = GET_WIDGET(ui->dialog_ui, "word_size_combobox");
+ renderer = gtk_cell_renderer_text_new();
+ gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(widget), renderer, TRUE);
+ gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(widget), renderer, "text", 0);
+
+ /* Label used in preferences dialog. The %d is replaced by a spinbutton */
+ string = _("Show %d decimal _places");
+ tokens = g_strsplit(string, "%d", 2);
+ widget = GET_WIDGET(ui->dialog_ui, "decimal_places_label1");
+ if (tokens[0])
+ string = g_strstrip(tokens[0]);
+ else
+ string = "";
+ if (string[0] != '\0')
+ gtk_label_set_text_with_mnemonic(GTK_LABEL(widget), string);
+ else
+ gtk_widget_hide(widget);
+
+ widget = GET_WIDGET(ui->dialog_ui, "decimal_places_label2");
+ if (tokens[0] && tokens[1])
+ string = g_strstrip(tokens[1]);
+ else
+ string = "";
+ if (string[0] != '\0')
+ gtk_label_set_text_with_mnemonic(GTK_LABEL(widget), string);
+ else
+ gtk_widget_hide(widget);
+
+ g_strfreev(tokens);
+
+ set_combo_box_from_config(ui, "angle_unit_combobox", R_TRIG, G_TYPE_STRING);
+ set_combo_box_from_config(ui, "display_format_combobox", R_DISPLAY, G_TYPE_STRING);
+ set_combo_box_from_config(ui, "word_size_combobox", R_WORDLEN, G_TYPE_INT);
+
+ if (!get_int_resource(R_ACCURACY, &value))
+ value = 9;
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(GET_OBJECT(ui->dialog_ui, "decimal_places_spin")), value);
+
+ if (!get_boolean_resource(R_TSEP, &value))
+ value = FALSE;
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(GET_OBJECT(ui->dialog_ui, "thousands_separator_check")), value);
+
+ if (!get_boolean_resource(R_ZEROES, &value))
+ value = FALSE;
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(GET_OBJECT(ui->dialog_ui, "trailing_zeroes_check")), value);
+
+ gtk_builder_connect_signals(ui->dialog_ui, ui);
+}
diff --git a/src/ui-preferences.h b/src/ui-preferences.h
new file mode 100644
index 0000000..724254c
--- /dev/null
+++ b/src/ui-preferences.h
@@ -0,0 +1,26 @@
+/* Copyright (c) 2008-2009 Robert Ancell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef UI_PREFERENCES_H
+#define UI_PREFERENCES_H
+
+#include "ui.h"
+
+void ui_show_preferences(GCalctoolUI *ui);
+
+#endif /* UI_PREFERENCES_H */
diff --git a/src/ui.c b/src/ui.c
new file mode 100644
index 0000000..8e2be59
--- /dev/null
+++ b/src/ui.c
@@ -0,0 +1,393 @@
+/* Copyright (c) 1987-2008 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright (c) 2008-2009 Robert Ancell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include <gtk/gtk.h>
+
+#include <limits.h>
+#include <sys/param.h>
+#include <unistd.h>
+#include <netdb.h>
+
+#include "ui.h"
+#include "ui-internal.h"
+#include "ui-display.h"
+#include "ui-buttons.h"
+#include "ui-preferences.h"
+#include "config.h"
+#include "get.h"
+
+static const char *mode_names[] = { "BASIC", "ADVANCED", "FINANCIAL", "PROGRAMMING", NULL };
+
+#define UI_FILE UI_DIR "/gcalctool.ui"
+#define GET_WIDGET(ui, name) GTK_WIDGET(gtk_builder_get_object(ui, name))
+
+void
+ui_init(int *argc, char ***argv)
+{
+ gtk_init(argc, argv);
+ gtk_window_set_default_icon_name("accessories-calculator");
+}
+
+
+static void
+create_main_window(GCalctoolUI *ui)
+{
+ int i;
+ char name[MAXLINE];
+ GtkWidget *widget;
+ PangoFontDescription *font_desc;
+ GtkCellRenderer *renderer;
+ GError *error = NULL;
+
+ ui->ui = gtk_builder_new();
+ gtk_builder_add_from_file(ui->ui, UI_FILE, &error);
+ if (error) {
+ gchar *contents;
+ contents = g_strdup_printf(/* Description in UI error dialog when unable to load the UI files. %s is replaced with the error message provided by GTK+ */
+ _("A required file is missing or damaged. Please check your installation.\n\n%s"),
+ error->message);
+ ui_critical_error(ui,
+ /* Title of the error dialog when unable to load the UI files */
+ _("Error loading user interface"),
+ contents);
+ }
+ gtk_builder_connect_signals(ui->ui, ui);
+
+ ui->clipboard_atom = gdk_atom_intern("CLIPBOARD", FALSE);
+ ui->primary_atom = gdk_atom_intern("PRIMARY", FALSE);
+
+ ui->main_window = GET_WIDGET(ui->ui, "calc_window");
+ ui->scrolledwindow = GET_WIDGET(ui->ui, "display_scroll"),
+ ui->display_item = GET_WIDGET(ui->ui, "displayitem"),
+ ui->info_buffer = GTK_TEXT_BUFFER(gtk_builder_get_object(ui->ui, "info_buffer"));
+ ui->button_vbox = GET_WIDGET(ui->ui, "button_vbox");
+
+ ui->display_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ui->display_item));
+ gtk_widget_ensure_style(ui->display_item);
+ font_desc = pango_font_description_copy(gtk_widget_get_style(ui->display_item)->font_desc);
+ pango_font_description_set_size(font_desc, 16 * PANGO_SCALE);
+ gtk_widget_modify_font(ui->display_item, font_desc);
+ pango_font_description_free(font_desc);
+ gtk_widget_set_name(ui->display_item, "displayitem");
+ atk_object_set_role(gtk_widget_get_accessible(ui->display_item),
+ ATK_ROLE_EDITBAR);
+
+ gtk_widget_realize(ui->main_window);
+
+ /* Set modes for menu items */
+ for (i = 1; i < 16; i++) {
+ SNPRINTF(name, MAXLINE, "shift_left%d_menu", i);
+ g_object_set_data(gtk_builder_get_object(ui->ui, name), "shiftcount", GINT_TO_POINTER(i));
+ SNPRINTF(name, MAXLINE, "shift_right%d_menu", i);
+ g_object_set_data(gtk_builder_get_object(ui->ui, name), "shiftcount", GINT_TO_POINTER(-i));
+ }
+ g_object_set_data(gtk_builder_get_object(ui->ui, "view_basic_menu"), "calcmode", GINT_TO_POINTER(BASIC));
+ g_object_set_data(gtk_builder_get_object(ui->ui, "view_advanced_menu"), "calcmode", GINT_TO_POINTER(ADVANCED));
+ g_object_set_data(gtk_builder_get_object(ui->ui, "view_financial_menu"), "calcmode", GINT_TO_POINTER(FINANCIAL));
+ g_object_set_data(gtk_builder_get_object(ui->ui, "view_programming_menu"), "calcmode", GINT_TO_POINTER(PROGRAMMING));
+}
+
+
+GCalctoolUI *
+ui_new()
+{
+ gchar *path;
+ int value;
+ GCalctoolUI *ui;
+
+ ui = g_malloc0(sizeof(GCalctoolUI));
+
+ if (get_enumerated_resource(R_MODE, mode_names, &value))
+ ui->mode = (ModeType) value;
+ else
+ ui->mode = BASIC;
+
+ /* Create main gcalctool window. */
+ create_main_window(ui);
+
+ return ui;
+}
+
+
+void
+ui_start(GCalctoolUI *ui)
+{
+ gtk_widget_show(ui->main_window);
+ gtk_main();
+}
+
+
+void
+ui_critical_error(GCalctoolUI *ui, const gchar *title, const gchar *contents)
+{
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new(NULL, 0,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_NONE,
+ "%s", title);
+ gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
+ "%s", contents);
+ gtk_dialog_add_buttons(GTK_DIALOG(dialog), GTK_STOCK_QUIT, GTK_RESPONSE_ACCEPT, NULL);
+
+ gtk_dialog_run(GTK_DIALOG(dialog));
+
+ gtk_main_quit();
+}
+
+
+// FIXME: Watch for changes in programming mode
+void
+ui_set_bitfield(GCalctoolUI *ui, int enabled, guint64 bits)
+{
+ int i;
+ const gchar *label;
+
+ if (!ui->bit_panel)
+ return;
+
+ gtk_widget_set_sensitive(ui->bit_panel, enabled);
+
+ for (i = 0; i < MAXBITS; i++) {
+ if (bits & (1LL << (MAXBITS-i-1)))
+ label = " 1";
+ else
+ label = " 0";
+ gtk_label_set_text(GTK_LABEL(ui->bit_labels[i]), label);
+ }
+}
+
+
+void
+ui_set_number_mode(GCalctoolUI *ui, NumberMode mode)
+{
+ GList *i;
+
+ ui->number_mode = mode;
+ for (i = ui->superscript_toggles; i; i = i->next) {
+ GtkWidget *widget = i->data;
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), mode == SUPERSCRIPT);
+ }
+ for (i = ui->subscript_toggles; i; i = i->next) {
+ GtkWidget *widget = i->data;
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), mode == SUBSCRIPT);
+ }
+}
+
+
+static GtkWidget *
+get_buttons(GCalctoolUI *ui, ModeType mode)
+{
+ switch (mode) {
+ case BASIC:
+ return ui->bas_panel;
+ case ADVANCED:
+ return ui->adv_panel;
+ case FINANCIAL:
+ return ui->fin_panel;
+ case PROGRAMMING:
+ return ui->prog_panel;
+ }
+}
+
+
+static void
+ui_set_mode(GCalctoolUI *ui, ModeType mode)
+{
+ GtkWidget *menu;
+ ModeType old_mode;
+
+ old_mode = ui->mode;
+ ui->mode = mode;
+
+ /* Save mode */
+ set_enumerated_resource(R_MODE, mode_names, (int)mode);
+
+ /* Hide the existing mode */
+ if (get_buttons(ui, old_mode))
+ gtk_widget_hide(get_buttons(ui, old_mode));
+
+ /* Create the new mode if necessary */
+ if (!get_buttons(ui, mode))
+ ui_load_mode(ui, mode);
+ gtk_widget_show(get_buttons(ui, mode));
+
+ /* Update the menu */
+ switch (mode) {
+ case BASIC:
+ menu = GET_WIDGET(ui->ui, "view_basic_menu");
+ break;
+
+ case ADVANCED:
+ menu = GET_WIDGET(ui->ui, "view_advanced_menu");
+ break;
+
+ case FINANCIAL:
+ menu = GET_WIDGET(ui->ui, "view_financial_menu");
+ break;
+
+ case PROGRAMMING:
+ menu = GET_WIDGET(ui->ui, "view_programming_menu");
+ break;
+
+ default:
+ assert(FALSE);
+ return;
+ }
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), TRUE);
+}
+
+
+void
+ui_set_statusbar(GCalctoolUI *ui, const gchar *text)
+{
+ gtk_text_buffer_set_text(ui->info_buffer, text, -1);
+}
+
+
+G_MODULE_EXPORT
+void
+copy_cb(GtkWidget *widget, GCalctoolUI *ui)
+{
+ ui_display_copy(ui);
+}
+
+
+G_MODULE_EXPORT
+void
+paste_cb(GtkWidget *widget, GCalctoolUI *ui)
+{
+ ui_display_paste(ui);
+}
+
+
+G_MODULE_EXPORT
+void
+mode_changed_cb(GtkWidget *menu, GCalctoolUI *ui)
+{
+ int mode;
+
+ if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menu)))
+ return;
+
+ mode = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(menu), "calcmode"));
+ ui_set_mode(ui, mode);
+}
+
+
+G_MODULE_EXPORT
+void
+show_preferences_cb(GtkMenuItem *menu, GCalctoolUI *ui)
+{
+ ui_show_preferences(ui);
+}
+
+
+G_MODULE_EXPORT
+void
+help_cb(GtkWidget *widget, GCalctoolUI *ui)
+{
+ GdkScreen *screen;
+ GError *error = NULL;
+
+ screen = gtk_widget_get_screen (GTK_WIDGET (ui->main_window));
+ gtk_show_uri (screen, "ghelp:gcalctool", gtk_get_current_event_time (), &error);
+
+ if (error != NULL)
+ {
+ GtkWidget *d;
+ /* Translators: Error message displayed when unable to launch help browser */
+ const char *message = _("Unable to open help file");
+
+ d = gtk_message_dialog_new (GTK_WINDOW (ui->main_window),
+ GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
+ "%s", message);
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (d),
+ "%s", error->message);
+ g_signal_connect (d, "response", G_CALLBACK (gtk_widget_destroy), NULL);
+ gtk_window_present (GTK_WINDOW (d));
+
+ g_error_free (error);
+ }
+}
+
+
+G_MODULE_EXPORT
+void
+about_cb(GtkWidget *widget, GCalctoolUI *ui)
+{
+ const gchar *authors[] = {
+ "Rich Burridge <rich burridge sun com>",
+ "Robert Ancell <robert ancell gmail com>",
+ "Klaus Niederkrüger <kniederk umpa ens-lyon fr>",
+ NULL
+ };
+ const gchar *documenters[] = {
+ "Sun Microsystems",
+ NULL
+ };
+
+ /* Translators: The translator credits. Please translate this with your name(s). */
+ const gchar *translator_credits = _("translator-credits");
+
+ /* Translators: The license this software is under (GPL2+) */
+ char *license = _("Gcalctool is free software; you can redistribute it and/or modify\n"
+ "it under the terms of the GNU General Public License as published by\n"
+ "the Free Software Foundation; either version 2 of the License, or\n"
+ "(at your option) any later version.\n"
+ "\n"
+ "Gcalctool is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with Gcalctool; if not, write to the Free Software Foundation, Inc.,\n"
+ "51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA");
+
+ gtk_show_about_dialog(GTK_WINDOW(ui->main_window),
+ /* Translators: Program name in the about dialog */
+ "name", _("Gcalctool"),
+ "version", VERSION,
+ /* Translators: Copyright notice in the about dialog */
+ "copyright", _("\xc2\xa9 1986â??2008 The Gcalctool authors"),
+ "license", license,
+ /* Translators: Short description in the about dialog */
+ "comments", _("Calculator with financial and scientific modes."),
+ "authors", authors,
+ "documenters", documenters,
+ "translator_credits", translator_credits,
+ "logo-icon-name", "accessories-calculator",
+ NULL);
+}
+
+
+G_MODULE_EXPORT
+void
+quit_cb(GtkWidget *widget, GCalctoolUI *ui)
+{
+ gtk_main_quit();
+}
diff --git a/src/ui.h b/src/ui.h
index 68f8ead..57f6c5d 100644
--- a/src/ui.h
+++ b/src/ui.h
@@ -21,19 +21,86 @@
#define UI_H
#include <stdint.h>
+#include <gtk/gtk.h>
+
+typedef struct GCalctoolUI GCalctoolUI;
#include "calctool.h"
-void ui_init(int *argc, char ***argv);
-void ui_load(void);
-void ui_start(void);
+/* Calculator modes. */
+typedef enum {
+ BASIC,
+ ADVANCED,
+ FINANCIAL,
+ PROGRAMMING
+} ModeType;
+
+typedef enum {
+ NORMAL,
+ SUPERSCRIPT,
+ SUBSCRIPT
+} NumberMode;
+
+#define MAXBITS 64 /* Bit panel: number of bit fields. */
+#define MAX_REGISTERS 6
+
+// FIXME: Make opaque
+struct GCalctoolUI {
+ ModeType mode; /* Current calculator mode. */
+ NumberMode number_mode;
+
+ GtkBuilder *ui;
+ GtkBuilder *dialog_ui;
+ GtkBuilder *financial;
+ GtkBuilder *basic_ui, *advanced_ui, *financial_ui, *programming_ui;
+
+ GtkWidget *main_window;
+
+ GtkWidget *bit_panel;
+ GtkWidget *bit_labels[MAXBITS];
+
+ GtkWidget *ascii_dialog;
+ GtkWidget *ascii_entry;
-void ui_set_undo_enabled(gboolean, gboolean);
+ GtkWidget *display_item; /* Calculator display. */
+ GtkTextBuffer *display_buffer; /* Buffer used in display */
+ GtkTextBuffer *info_buffer; /* Buffer used in info messages */
+ GtkWidget *scrolledwindow; /* Scrolled window for display_item. */
+
+ GtkWidget *button_vbox;
+ GtkWidget *bas_panel; /* Panel containing basic mode widgets. */
+ GtkWidget *adv_panel; /* Panel containing advanced mode widgets. */
+ GtkWidget *fin_panel; /* Panel containing financial mode widgets. */
+ GtkWidget *prog_panel; /* Panel containing programming mode widgets. */
+
+ GList *superscript_toggles;
+ GList *subscript_toggles;
+
+ gboolean can_super_minus;
+
+ /* Labels for popup menus */
+ GtkWidget *memory_store_labels[MAX_REGISTERS];
+ GtkWidget *memory_recall_labels[MAX_REGISTERS];
+
+ GtkWidget *preferences_dialog;
+
+ GdkAtom clipboard_atom;
+ GdkAtom primary_atom;
+ char *shelf; /* PUT selection shelf contents. */
+
+ /* Last text entered */
+ char *last_text;
+};
+
+void ui_init(int *argc, char ***argv);
+GCalctoolUI *ui_new(void);
+void ui_critical_error(GCalctoolUI *ui, const gchar *title, const gchar *contents);
+void ui_start(GCalctoolUI *ui);
-void ui_set_display(char *, int);
-void ui_set_bitfield(int enabled, guint64 bits);
-void ui_set_statusbar(const gchar *);
+void ui_set_display(GCalctoolUI *ui, char *, int);
+void ui_set_bitfield(GCalctoolUI *ui, int enabled, guint64 bits);
+void ui_set_statusbar(GCalctoolUI *ui, const gchar *);
-gchar *ui_get_display(void);
+gchar *ui_get_display(GCalctoolUI *ui);
#endif /* UI_H */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]