Make the currency code OO
[gcalctool.git] / src / math-buttons.c
blob4295ff2006729c652b8a0ea031688efe7897071a
1 /* Copyright (c) 2008-2009 Robert Ancell
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2, or (at your option)
6 * any later version.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
16 * 02111-1307, USA.
19 #include <glib/gi18n.h>
21 #include "math-buttons.h"
22 #include "math-converter.h"
23 #include "math-variable-popup.h"
24 #include "financial.h"
25 #include "mp-serializer.h"
27 enum {
28 PROP_0,
29 PROP_EQUATION,
30 PROP_MODE
33 static GType button_mode_type;
35 #define MAXBITS 64 /* Bit panel: number of bit fields. */
37 struct MathButtonsPrivate
39 MathEquation *equation;
41 ButtonMode mode;
42 gint programming_base;
44 MathConverter *converter;
46 GtkBuilder *basic_ui, *advanced_ui, *financial_ui, *programming_ui;
48 GdkColor color_numbers, color_action, color_operator, color_function, color_memory, color_group;
50 GtkWidget *bas_panel, *adv_panel, *fin_panel, *prog_panel;
51 GtkWidget *active_panel;
53 GtkWidget *shift_left_menu, *shift_right_menu;
55 GtkWidget *function_menu;
57 GList *superscript_toggles;
58 GList *subscript_toggles;
60 GtkWidget *base_combo;
61 GtkWidget *base_label;
62 GtkWidget *bit_panel;
63 GtkWidget *bit_labels[MAXBITS];
65 GtkWidget *character_code_dialog;
66 GtkWidget *character_code_entry;
69 G_DEFINE_TYPE (MathButtons, math_buttons, GTK_TYPE_VBOX);
71 #define UI_BASIC_FILE UI_DIR "/buttons-basic.ui"
72 #define UI_ADVANCED_FILE UI_DIR "/buttons-advanced.ui"
73 #define UI_FINANCIAL_FILE UI_DIR "/buttons-financial.ui"
74 #define UI_PROGRAMMING_FILE UI_DIR "/buttons-programming.ui"
76 #define GET_WIDGET(ui, name) \
77 GTK_WIDGET(gtk_builder_get_object((ui), (name)))
79 #define WM_WIDTH_FACTOR 10
80 #define WM_HEIGHT_FACTOR 30
82 typedef enum
84 NUMBER,
85 NUMBER_BOLD,
86 OPERATOR,
87 FUNCTION,
88 MEMORY,
89 GROUP,
90 ACTION
91 } ButtonClass;
93 typedef struct {
94 const char *widget_name;
95 const char *data;
96 ButtonClass class;
97 const char *tooltip;
98 } ButtonData;
100 static ButtonData button_data[] = {
101 {"pi", "π", NUMBER,
102 /* Tooltip for the Pi button */
103 N_("Pi [Ctrl+P]")},
104 {"eulers_number", "e", NUMBER,
105 /* Tooltip for the Euler's Number button */
106 N_("Euler’s Number")},
107 {"imaginary", "i", NUMBER, NULL},
108 {"numeric_point", NULL, NUMBER, NULL},
109 {"subscript", NULL, NUMBER_BOLD,
110 /* Tooltip for the subscript button */
111 N_("Subscript mode [Alt]")},
112 {"superscript", NULL, NUMBER_BOLD,
113 /* Tooltip for the superscript button */
114 N_("Superscript mode [Ctrl]")},
115 {"exponential", NULL, NUMBER_BOLD,
116 /* Tooltip for the scientific exponent button */
117 N_("Scientific exponent [Ctrl+E]")},
118 {"add", "+", OPERATOR,
119 /* Tooltip for the add button */
120 N_("Add [+]")},
121 {"subtract", "−", OPERATOR,
122 /* Tooltip for the subtract button */
123 N_("Subtract [-]")},
124 {"multiply", "×", OPERATOR,
125 /* Tooltip for the multiply button */
126 N_("Multiply [*]")},
127 {"divide", "÷", OPERATOR,
128 /* Tooltip for the divide button */
129 N_("Divide [/]")},
130 {"modulus_divide", " mod ", OPERATOR,
131 /* Tooltip for the modulus divide button */
132 N_("Modulus divide")},
133 {"function", NULL, FUNCTION,
134 /* Tooltip for the additional functions button */
135 N_("Additional Functions")},
136 {"x_pow_y", "^", FUNCTION,
137 /* Tooltip for the exponent button */
138 N_("Exponent [^ or **]")},
139 {"x_squared", "²", FUNCTION,
140 /* Tooltip for the square button */
141 N_("Square [Ctrl+2]")},
142 {"percentage", "%", NUMBER,
143 /* Tooltip for the percentage button */
144 N_("Percentage [%]")},
145 {"factorial", "!", FUNCTION,
146 /* Tooltip for the factorial button */
147 N_("Factorial [!]")},
148 {"abs", "|", FUNCTION,
149 /* Tooltip for the absolute value button */
150 N_("Absolute value [|]")},
151 {"arg", "Arg ", FUNCTION,
152 /* Tooltip for the complex argument component button */
153 N_("Complex argument")},
154 {"conjugate", "conj ", FUNCTION,
155 /* Tooltip for the complex conjugate button */
156 N_("Complex conjugate")},
157 {"root", "√", FUNCTION,
158 /* Tooltip for the root button */
159 N_("Root [Ctrl+R]")},
160 {"square_root", "√", FUNCTION,
161 /* Tooltip for the square root button */
162 N_("Square root [Ctrl+R]")},
163 {"logarithm", "log ", FUNCTION,
164 /* Tooltip for the logarithm button */
165 N_("Logarithm")},
166 {"natural_logarithm", "ln ", FUNCTION,
167 /* Tooltip for the natural logarithm button */
168 N_("Natural Logarithm")},
169 {"sine", "sin ", FUNCTION,
170 /* Tooltip for the sine button */
171 N_("Sine")},
172 {"cosine", "cos ", FUNCTION,
173 /* Tooltip for the cosine button */
174 N_("Cosine")},
175 {"tangent", "tan ", FUNCTION,
176 /* Tooltip for the tangent button */
177 N_("Tangent")},
178 {"hyperbolic_sine", "sinh ", FUNCTION,
179 /* Tooltip for the hyperbolic sine button */
180 N_("Hyperbolic Sine")},
181 {"hyperbolic_cosine", "cosh ", FUNCTION,
182 /* Tooltip for the hyperbolic cosine button */
183 N_("Hyperbolic Cosine")},
184 {"hyperbolic_tangent", "tanh ", FUNCTION,
185 /* Tooltip for the hyperbolic tangent button */
186 N_("Hyperbolic Tangent")},
187 {"inverse", "⁻¹", FUNCTION,
188 /* Tooltip for the inverse button */
189 N_("Inverse [Ctrl+I]")},
190 {"and", "∧", OPERATOR,
191 /* Tooltip for the boolean AND button */
192 N_("Boolean AND")},
193 {"or", "∨", OPERATOR,
194 /* Tooltip for the boolean OR button */
195 N_("Boolean OR")},
196 {"xor", "⊻", OPERATOR,
197 /* Tooltip for the exclusive OR button */
198 N_("Boolean Exclusive OR")},
199 {"not", "¬", FUNCTION,
200 /* Tooltip for the boolean NOT button */
201 N_("Boolean NOT")},
202 {"integer_portion", "int ", FUNCTION,
203 /* Tooltip for the integer component button */
204 N_("Integer Component")},
205 {"fractional_portion", "frac ", FUNCTION,
206 /* Tooltip for the fractional component button */
207 N_("Fractional Component")},
208 {"real_portion", "Re ", FUNCTION,
209 /* Tooltip for the real component button */
210 N_("Real Component")},
211 {"imaginary_portion", "Im ", FUNCTION,
212 /* Tooltip for the imaginary component button */
213 N_("Imaginary Component")},
214 {"ones_complement", "ones ", FUNCTION,
215 /* Tooltip for the ones complement button */
216 N_("Ones Complement")},
217 {"twos_complement", "twos ", FUNCTION,
218 /* Tooltip for the twos complement button */
219 N_("Twos Complement")},
220 {"trunc", "trunc ", FUNCTION,
221 /* Tooltip for the truncate button */
222 N_("Truncate")},
223 {"start_group", "(", GROUP,
224 /* Tooltip for the start group button */
225 N_("Start Group [(]")},
226 {"end_group", ")", GROUP,
227 /* Tooltip for the end group button */
228 N_("End Group [)]")},
229 {"memory", NULL, MEMORY,
230 /* Tooltip for the memory button */
231 N_("Memory")},
232 {"character", NULL, MEMORY,
233 /* Tooltip for the insert character code button */
234 N_("Insert Character Code")},
235 {"result", NULL, ACTION,
236 /* Tooltip for the solve button */
237 N_("Calculate Result")},
238 {"factor", NULL, ACTION,
239 /* Tooltip for the factor button */
240 N_("Factorize [Ctrl+F]")},
241 {"clear", NULL, GROUP,
242 /* Tooltip for the clear button */
243 N_("Clear Display [Escape]")},
244 {"undo", NULL, GROUP,
245 /* Tooltip for the undo button */
246 N_("Undo [Ctrl+Z]")},
247 {"shift_left", NULL, ACTION,
248 /* Tooltip for the shift left button */
249 N_("Shift Left")},
250 {"shift_right", NULL, ACTION,
251 /* Tooltip for the shift right button */
252 N_("Shift Right")},
253 {"finc_compounding_term", NULL, FUNCTION,
254 /* Tooltip for the compounding term button */
255 N_("Compounding Term")},
256 {"finc_double_declining_depreciation", NULL, FUNCTION,
257 /* Tooltip for the double declining depreciation button */
258 N_("Double Declining Depreciation")},
259 {"finc_future_value", NULL, FUNCTION,
260 /* Tooltip for the future value button */
261 N_("Future Value")},
262 {"finc_term", NULL, FUNCTION,
263 /* Tooltip for the financial term button */
264 N_("Financial Term")},
265 {"finc_sum_of_the_years_digits_depreciation", NULL, FUNCTION,
266 /* Tooltip for the sum of the years digits depreciation button */
267 N_("Sum of the Years Digits Depreciation")},
268 {"finc_straight_line_depreciation", NULL, FUNCTION,
269 /* Tooltip for the straight line depreciation button */
270 N_("Straight Line Depreciation")},
271 {"finc_periodic_interest_rate", NULL, FUNCTION,
272 /* Tooltip for the periodic interest rate button */
273 N_("Periodic Interest Rate")},
274 {"finc_present_value", NULL, FUNCTION,
275 /* Tooltip for the present value button */
276 N_("Present Value")},
277 {"finc_periodic_payment", NULL, FUNCTION,
278 /* Tooltip for the periodic payment button */
279 N_("Periodic Payment")},
280 {"finc_gross_profit_margin", NULL, FUNCTION,
281 /* Tooltip for the gross profit margin button */
282 N_("Gross Profit Margin")},
283 {NULL, NULL, 0, NULL}
286 /* The names of each field in the dialogs for the financial functions */
287 static char *finc_dialog_fields[][5] = {
288 {"ctrm_pint", "ctrm_fv", "ctrm_pv", NULL, NULL},
289 {"ddb_cost", "ddb_life", "ddb_period", NULL, NULL},
290 {"fv_pmt", "fv_pint", "fv_n", NULL, NULL},
291 {"gpm_cost", "gpm_margin", NULL, NULL, NULL},
292 {"pmt_prin", "pmt_pint", "pmt_n", NULL, NULL},
293 {"pv_pmt", "pv_pint", "pv_n", NULL, NULL},
294 {"rate_fv", "rate_pv", "rate_n", NULL, NULL},
295 {"sln_cost", "sln_salvage", "sln_life", NULL, NULL},
296 {"syd_cost", "syd_salvage", "syd_life", "syd_period", NULL},
297 {"term_pmt", "term_fv", "term_pint", NULL, NULL},
298 {NULL, NULL, NULL, NULL, NULL}
302 MathButtons *
303 math_buttons_new(MathEquation *equation)
305 return g_object_new(math_buttons_get_type(), "equation", equation, NULL);
309 static void
310 set_tint(GtkWidget *widget, GdkColor *tint, gint alpha)
312 GtkStyle *style;
313 int j;
315 if (!widget)
316 return;
318 gtk_widget_ensure_style(widget);
319 style = gtk_widget_get_style(widget);
321 for (j = 0; j < 5; j++) {
322 GdkColor color;
324 color.red = (style->bg[j].red * (10 - alpha) + tint->red * alpha) / 10;
325 color.green = (style->bg[j].green * (10 - alpha) + tint->green * alpha) / 10;
326 color.blue = (style->bg[j].blue * (10 - alpha) + tint->blue * alpha) / 10;
328 gtk_widget_modify_bg(widget, j, &color);
333 static void
334 set_data(GtkBuilder *ui, const gchar *object_name, const gchar *name, const char *value)
336 GObject *object;
337 object = gtk_builder_get_object(ui, object_name);
338 if (object)
339 g_object_set_data(object, name, GINT_TO_POINTER(value));
343 static void
344 set_int_data(GtkBuilder *ui, const gchar *object_name, const gchar *name, gint value)
346 GObject *object;
347 object = gtk_builder_get_object(ui, object_name);
348 if (object)
349 g_object_set_data(object, name, GINT_TO_POINTER(value));
353 static void
354 load_finc_dialogs(MathButtons *buttons)
356 int i, j;
358 set_int_data(buttons->priv->financial_ui, "ctrm_dialog", "finc_dialog", FINC_CTRM_DIALOG);
359 set_int_data(buttons->priv->financial_ui, "ddb_dialog", "finc_dialog", FINC_DDB_DIALOG);
360 set_int_data(buttons->priv->financial_ui, "fv_dialog", "finc_dialog", FINC_FV_DIALOG);
361 set_int_data(buttons->priv->financial_ui, "gpm_dialog", "finc_dialog", FINC_GPM_DIALOG);
362 set_int_data(buttons->priv->financial_ui, "pmt_dialog", "finc_dialog", FINC_PMT_DIALOG);
363 set_int_data(buttons->priv->financial_ui, "pv_dialog", "finc_dialog", FINC_PV_DIALOG);
364 set_int_data(buttons->priv->financial_ui, "rate_dialog", "finc_dialog", FINC_RATE_DIALOG);
365 set_int_data(buttons->priv->financial_ui, "sln_dialog", "finc_dialog", FINC_SLN_DIALOG);
366 set_int_data(buttons->priv->financial_ui, "syd_dialog", "finc_dialog", FINC_SYD_DIALOG);
367 set_int_data(buttons->priv->financial_ui, "term_dialog", "finc_dialog", FINC_TERM_DIALOG);
369 for (i = 0; finc_dialog_fields[i][0] != NULL; i++) {
370 for (j = 0; finc_dialog_fields[i][j]; j++) {
371 GObject *o;
372 o = gtk_builder_get_object (buttons->priv->financial_ui, finc_dialog_fields[i][j]);
373 g_object_set_data(o, "finc_field", GINT_TO_POINTER(j));
374 g_object_set_data(o, "finc_dialog", GINT_TO_POINTER(i));
380 static void
381 update_bit_panel(MathButtons *buttons)
383 MPNumber x;
384 gboolean enabled;
385 guint64 bits;
386 int i;
387 GString *label;
388 gint base;
390 if (!buttons->priv->bit_panel)
391 return;
393 enabled = math_equation_get_number(buttons->priv->equation, &x);
395 if (enabled) {
396 MPNumber max, fraction;
398 mp_set_from_unsigned_integer(G_MAXUINT64, &max);
399 mp_fractional_part(&x, &fraction);
400 if (mp_is_negative(&x) || mp_is_greater_than(&x, &max) || !mp_is_zero(&fraction))
401 enabled = FALSE;
402 else
403 bits = mp_cast_to_unsigned_int(&x);
406 gtk_widget_set_sensitive(buttons->priv->bit_panel, enabled);
407 gtk_widget_set_sensitive(buttons->priv->base_label, enabled);
409 if (!enabled)
410 return;
412 for (i = 0; i < MAXBITS; i++) {
413 const gchar *label;
415 if (bits & (1LL << (MAXBITS-i-1)))
416 label = " 1";
417 else
418 label = " 0";
419 gtk_label_set_text(GTK_LABEL(buttons->priv->bit_labels[i]), label);
422 base = math_equation_get_base(buttons->priv->equation);
423 label = g_string_new("");
424 if (base != 8) {
425 if (label->len != 0)
426 g_string_append(label, " = ");
427 g_string_append_printf(label, "%" G_GINT64_MODIFIER "o", bits);
428 g_string_append(label, "₈");
430 if (base != 10) {
431 if (label->len != 0)
432 g_string_append(label, " = ");
433 g_string_append_printf(label, "%" G_GINT64_MODIFIER "u", bits);
434 g_string_append(label, "₁₀");
436 if (base != 16) {
437 if (label->len != 0)
438 g_string_append(label, " = ");
439 g_string_append_printf(label, "%" G_GINT64_MODIFIER "X", bits);
440 g_string_append(label, "₁₆");
443 gtk_label_set_text(GTK_LABEL(buttons->priv->base_label), label->str);
444 g_string_free(label, TRUE);
448 static void
449 display_changed_cb(MathEquation *equation, GParamSpec *spec, MathButtons *buttons)
451 update_bit_panel(buttons);
455 static void
456 base_combobox_changed_cb(GtkWidget *combo, MathButtons *buttons)
458 gint value;
459 GtkTreeModel *model;
460 GtkTreeIter iter;
462 model = gtk_combo_box_get_model(GTK_COMBO_BOX(combo));
463 gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combo), &iter);
464 gtk_tree_model_get(model, &iter, 1, &value, -1);
466 math_equation_set_base(buttons->priv->equation, value);
470 static void
471 base_changed_cb(MathEquation *equation, GParamSpec *spec, MathButtons *buttons)
473 GtkTreeModel *model;
474 GtkTreeIter iter;
475 gboolean valid;
477 if (buttons->priv->mode != PROGRAMMING)
478 return;
480 model = gtk_combo_box_get_model(GTK_COMBO_BOX(buttons->priv->base_combo));
481 valid = gtk_tree_model_get_iter_first(model, &iter);
482 buttons->priv->programming_base = math_equation_get_base(buttons->priv->equation);
484 while (valid) {
485 gint v;
487 gtk_tree_model_get(model, &iter, 1, &v, -1);
488 if (v == buttons->priv->programming_base)
489 break;
490 valid = gtk_tree_model_iter_next(model, &iter);
492 if (!valid)
493 valid = gtk_tree_model_get_iter_first(model, &iter);
495 gtk_combo_box_set_active_iter(GTK_COMBO_BOX(buttons->priv->base_combo), &iter);
499 static GtkWidget *
500 load_mode(MathButtons *buttons, ButtonMode mode)
502 GtkBuilder *builder, **builder_ptr;
503 gint i;
504 gchar *name;
505 const gchar *builder_file;
506 static gchar *objects[] = { "button_panel", "character_code_dialog", "currency_dialog",
507 "ctrm_dialog", "ddb_dialog", "fv_dialog", "gpm_dialog",
508 "pmt_dialog", "pv_dialog", "rate_dialog", "sln_dialog",
509 "syd_dialog", "term_dialog", "adjustment1", "adjustment2", NULL };
510 GtkWidget *widget, **panel;
511 GError *error = NULL;
513 switch (mode) {
514 default:
515 case BASIC:
516 builder_ptr = &buttons->priv->basic_ui;
517 builder_file = UI_BASIC_FILE;
518 panel = &buttons->priv->bas_panel;
519 break;
520 case ADVANCED:
521 builder_ptr = &buttons->priv->advanced_ui;
522 builder_file = UI_ADVANCED_FILE;
523 panel = &buttons->priv->adv_panel;
524 break;
525 case FINANCIAL:
526 builder_ptr = &buttons->priv->financial_ui;
527 builder_file = UI_FINANCIAL_FILE;
528 panel = &buttons->priv->fin_panel;
529 break;
530 case PROGRAMMING:
531 builder_ptr = &buttons->priv->programming_ui;
532 builder_file = UI_PROGRAMMING_FILE;
533 panel = &buttons->priv->prog_panel;
534 break;
537 if (*panel)
538 return *panel;
540 builder = *builder_ptr = gtk_builder_new();
541 // FIXME: Show dialog if failed to load
542 gtk_builder_add_objects_from_file(builder, builder_file, objects, &error);
543 if (error) {
544 g_warning("Error loading button UI: %s", error->message);
545 g_clear_error(&error);
547 *panel = GET_WIDGET(builder, "button_panel");
548 gtk_box_pack_end(GTK_BOX(buttons), *panel, TRUE, TRUE, 0);
550 /* Configure buttons */
551 for (i = 0; button_data[i].widget_name != NULL; i++) {
552 GObject *object;
553 GtkWidget *button;
555 name = g_strdup_printf("calc_%s_button", button_data[i].widget_name);
556 object = gtk_builder_get_object(*builder_ptr, name);
557 g_free(name);
559 if (!object)
560 continue;
561 button = GTK_WIDGET(object);
562 if (button_data[i].data)
563 g_object_set_data(object, "calc_text", (gpointer) button_data[i].data);
565 if (button_data[i].tooltip)
566 gtk_widget_set_tooltip_text(button, _(button_data[i].tooltip));
568 atk_object_set_name(gtk_widget_get_accessible(button), button_data[i].widget_name);
570 switch (button_data[i].class) {
571 case NUMBER:
572 set_tint(button, &buttons->priv->color_numbers, 1);
573 break;
574 case NUMBER_BOLD:
575 set_tint(button, &buttons->priv->color_numbers, 2);
576 break;
577 case OPERATOR:
578 set_tint(button, &buttons->priv->color_operator, 1);
579 break;
580 case FUNCTION:
581 set_tint(button, &buttons->priv->color_function, 1);
582 break;
583 case MEMORY:
584 set_tint(button, &buttons->priv->color_memory, 1);
585 break;
586 case GROUP:
587 set_tint(button, &buttons->priv->color_group, 1);
588 break;
589 case ACTION:
590 set_tint(button, &buttons->priv->color_action, 2);
591 break;
595 /* Set special button data */
596 for (i = 0; i < 16; i++) {
597 GtkWidget *button;
599 name = g_strdup_printf("calc_%d_button", i);
600 button = GET_WIDGET(builder, name);
601 if (button) {
602 gchar buffer[7];
603 gint len;
605 g_object_set_data(G_OBJECT(button), "calc_digit", GINT_TO_POINTER(i));
606 set_tint(button, &buttons->priv->color_numbers, 1);
607 len = g_unichar_to_utf8(math_equation_get_digit_text(buttons->priv->equation, i), buffer);
608 buffer[len] = '\0';
609 gtk_button_set_label(GTK_BUTTON(button), buffer);
611 g_free(name);
613 widget = GET_WIDGET(builder, "calc_numeric_point_button");
614 if (widget) {
615 MpSerializer *serializer = math_equation_get_serializer(buttons->priv->equation);
616 gchar buffer[7];
617 gint len;
618 len = g_unichar_to_utf8(mp_serializer_get_radix(serializer), buffer);
619 buffer[len] = '\0';
620 gtk_button_set_label(GTK_BUTTON(widget), buffer);
623 widget = GET_WIDGET(builder, "calc_superscript_button");
624 if (widget) {
625 buttons->priv->superscript_toggles = g_list_append(buttons->priv->superscript_toggles, widget);
626 if (math_equation_get_number_mode(buttons->priv->equation) == SUPERSCRIPT)
627 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), TRUE);
629 widget = GET_WIDGET(builder, "calc_subscript_button");
630 if (widget) {
631 buttons->priv->subscript_toggles = g_list_append(buttons->priv->subscript_toggles, widget);
632 if (math_equation_get_number_mode(buttons->priv->equation) == SUBSCRIPT)
633 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), TRUE);
636 if (mode == PROGRAMMING) {
637 GtkListStore *model;
638 GtkTreeIter iter;
639 GtkCellRenderer *renderer;
641 buttons->priv->base_label = GET_WIDGET(builder, "base_label");
642 buttons->priv->character_code_dialog = GET_WIDGET(builder, "character_code_dialog");
643 buttons->priv->character_code_entry = GET_WIDGET(builder, "character_code_entry");
645 buttons->priv->bit_panel = GET_WIDGET(builder, "bit_table");
646 for (i = 0; i < MAXBITS; i++) {
647 name = g_strdup_printf("bit_label_%d", i);
648 buttons->priv->bit_labels[i] = GET_WIDGET(builder, name);
649 g_free(name);
650 name = g_strdup_printf("bit_eventbox_%d", i);
651 set_int_data(builder, name, "bit_index", i);
654 buttons->priv->base_combo = GET_WIDGET(builder, "base_combo");
655 model = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT);
656 gtk_combo_box_set_model(GTK_COMBO_BOX(buttons->priv->base_combo), GTK_TREE_MODEL(model));
657 gtk_list_store_append(GTK_LIST_STORE(model), &iter);
658 gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0,
659 /* Number display mode combo: Binary, e.g. 10011010010₂ */
660 _("Binary"), 1, 2, -1);
661 gtk_list_store_append(GTK_LIST_STORE(model), &iter);
662 gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0,
663 /* Number display mode combo: Octal, e.g. 2322₈ */
664 _("Octal"), 1, 8, -1);
665 gtk_list_store_append(GTK_LIST_STORE(model), &iter);
666 gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0,
667 /* Number display mode combo: Decimal, e.g. 1234 */
668 _("Decimal"), 1, 10, -1);
669 gtk_list_store_append(GTK_LIST_STORE(model), &iter);
670 gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0,
671 /* Number display mode combo: Hexadecimal, e.g. 4D2₁₆ */
672 _("Hexadecimal"), 1, 16, -1);
673 renderer = gtk_cell_renderer_text_new();
674 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(buttons->priv->base_combo), renderer, TRUE);
675 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(buttons->priv->base_combo), renderer, "text", 0);
677 g_signal_connect(buttons->priv->base_combo, "changed", G_CALLBACK(base_combobox_changed_cb), buttons);
678 g_signal_connect(buttons->priv->equation, "notify::base", G_CALLBACK(base_changed_cb), buttons);
679 base_changed_cb(buttons->priv->equation, NULL, buttons);
682 /* Setup financial functions */
683 if (mode == FINANCIAL) {
684 load_finc_dialogs(buttons);
686 set_data(builder, "calc_finc_compounding_term_button", "finc_dialog", "ctrm_dialog");
687 set_data(builder, "calc_finc_double_declining_depreciation_button", "finc_dialog", "ddb_dialog");
688 set_data(builder, "calc_finc_future_value_button", "finc_dialog", "fv_dialog");
689 set_data(builder, "calc_finc_gross_profit_margin_button", "finc_dialog", "gpm_dialog");
690 set_data(builder, "calc_finc_periodic_payment_button", "finc_dialog", "pmt_dialog");
691 set_data(builder, "calc_finc_present_value_button", "finc_dialog", "pv_dialog");
692 set_data(builder, "calc_finc_periodic_interest_rate_button", "finc_dialog", "rate_dialog");
693 set_data(builder, "calc_finc_straight_line_depreciation_button", "finc_dialog", "sln_dialog");
694 set_data(builder, "calc_finc_sum_of_the_years_digits_depreciation_button", "finc_dialog", "syd_dialog");
695 set_data(builder, "calc_finc_term_button", "finc_dialog", "term_dialog");
698 gtk_builder_connect_signals(builder, buttons);
700 display_changed_cb(buttons->priv->equation, NULL, buttons);
702 return *panel;
706 static void
707 converter_changed_cb(MathConverter *converter, MathButtons *buttons)
709 Unit *from_unit, *to_unit;
711 math_converter_get_conversion(converter, &from_unit, &to_unit);
712 if (buttons->priv->mode == FINANCIAL) {
713 math_equation_set_source_currency(buttons->priv->equation, unit_get_name(from_unit));
714 math_equation_set_target_currency(buttons->priv->equation, unit_get_name(to_unit));
716 else {
717 math_equation_set_source_units(buttons->priv->equation, unit_get_name(from_unit));
718 math_equation_set_target_units(buttons->priv->equation, unit_get_name(to_unit));
721 g_object_unref(from_unit);
722 g_object_unref(to_unit);
726 static void
727 load_buttons(MathButtons *buttons)
729 GtkWidget *panel;
731 if (!gtk_widget_get_visible(GTK_WIDGET(buttons)))
732 return;
734 if (!buttons->priv->converter) {
735 buttons->priv->converter = math_converter_new(buttons->priv->equation);
736 g_signal_connect(buttons->priv->converter, "changed", G_CALLBACK(converter_changed_cb), buttons);
737 gtk_box_pack_start(GTK_BOX(buttons), GTK_WIDGET(buttons->priv->converter), FALSE, TRUE, 0);
740 panel = load_mode(buttons, buttons->priv->mode);
741 if (buttons->priv->active_panel == panel)
742 return;
744 /* Hide old buttons */
745 if (buttons->priv->active_panel)
746 gtk_widget_hide(buttons->priv->active_panel);
748 /* Load and display new buttons */
749 buttons->priv->active_panel = panel;
750 if (panel)
751 gtk_widget_show(panel);
755 void
756 math_buttons_set_mode(MathButtons *buttons, ButtonMode mode)
758 ButtonMode old_mode;
760 if (buttons->priv->mode == mode)
761 return;
763 old_mode = buttons->priv->mode;
764 buttons->priv->mode = mode;
766 if (mode == PROGRAMMING)
767 math_equation_set_base(buttons->priv->equation, buttons->priv->programming_base);
768 else
769 math_equation_set_base(buttons->priv->equation, 10);
771 load_buttons(buttons);
773 gtk_widget_set_visible(GTK_WIDGET(buttons->priv->converter), mode == ADVANCED || mode == FINANCIAL);
774 if (mode == ADVANCED) {
775 math_converter_set_category(buttons->priv->converter, NULL);
776 math_converter_set_conversion(buttons->priv->converter,
777 math_equation_get_source_units(buttons->priv->equation),
778 math_equation_get_target_units(buttons->priv->equation));
780 else if (mode == FINANCIAL) {
781 math_converter_set_category(buttons->priv->converter, "currency");
782 math_converter_set_conversion(buttons->priv->converter,
783 math_equation_get_source_currency(buttons->priv->equation),
784 math_equation_get_target_currency(buttons->priv->equation));
787 g_object_notify(G_OBJECT(buttons), "mode");
791 ButtonMode
792 math_buttons_get_mode(MathButtons *buttons)
794 return buttons->priv->mode;
798 void
799 math_buttons_set_programming_base(MathButtons *buttons, gint base)
801 buttons->priv->programming_base = base;
805 gint
806 math_buttons_get_programming_base(MathButtons *buttons)
808 return buttons->priv->programming_base;
812 void exponent_cb(GtkWidget *widget, MathButtons *buttons);
813 G_MODULE_EXPORT
814 void
815 exponent_cb(GtkWidget *widget, MathButtons *buttons)
817 math_equation_insert_exponent(buttons->priv->equation);
821 void subtract_cb(GtkWidget *widget, MathButtons *buttons);
822 G_MODULE_EXPORT
823 void
824 subtract_cb(GtkWidget *widget, MathButtons *buttons)
826 math_equation_insert_subtract(buttons->priv->equation);
830 void button_cb(GtkWidget *widget, MathButtons *buttons);
831 G_MODULE_EXPORT
832 void
833 button_cb(GtkWidget *widget, MathButtons *buttons)
835 math_equation_insert(buttons->priv->equation, g_object_get_data(G_OBJECT(widget), "calc_text"));
839 void solve_cb(GtkWidget *widget, MathButtons *buttons);
840 G_MODULE_EXPORT
841 void
842 solve_cb(GtkWidget *widget, MathButtons *buttons)
844 math_equation_solve(buttons->priv->equation);
848 void clear_cb(GtkWidget *widget, MathButtons *buttons);
849 G_MODULE_EXPORT
850 void
851 clear_cb(GtkWidget *widget, MathButtons *buttons)
853 math_equation_clear(buttons->priv->equation);
857 void delete_cb(GtkWidget *widget, MathButtons *buttons);
858 G_MODULE_EXPORT
859 void
860 delete_cb(GtkWidget *widget, MathButtons *buttons)
862 math_equation_delete(buttons->priv->equation);
866 void undo_cb(GtkWidget *widget, MathButtons *buttons);
867 G_MODULE_EXPORT
868 void
869 undo_cb(GtkWidget *widget, MathButtons *buttons)
871 math_equation_undo(buttons->priv->equation);
875 static void
876 shift_cb(GtkWidget *widget, MathButtons *buttons)
878 math_equation_shift(buttons->priv->equation, GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "shiftcount")));
882 static void
883 button_menu_position_func(GtkMenu *menu, gint *x, gint *y,
884 gboolean *push_in, gpointer user_data)
886 GtkWidget *button = user_data;
887 GtkAllocation allocation;
888 GdkPoint loc;
889 gint border;
891 gdk_window_get_origin(gtk_widget_get_window(button), &loc.x, &loc.y);
892 border = gtk_container_get_border_width(GTK_CONTAINER(button));
893 gtk_widget_get_allocation(button, &allocation);
894 *x = loc.x + allocation.x + border;
895 *y = loc.y + allocation.y + border;
899 static void
900 popup_button_menu(GtkWidget *widget, GtkMenu *menu)
902 gtk_menu_popup(menu, NULL, NULL,
903 button_menu_position_func, widget, 1, gtk_get_current_event_time());
907 void memory_cb(GtkWidget *widget, MathButtons *buttons);
908 G_MODULE_EXPORT
909 void
910 memory_cb(GtkWidget *widget, MathButtons *buttons)
912 MathVariablePopup *popup;
913 GtkAllocation allocation;
914 gint x, y;
916 popup = math_variable_popup_new(buttons->priv->equation);
917 set_tint(GTK_WIDGET(popup), &buttons->priv->color_memory, 1);
918 gtk_window_set_transient_for(GTK_WINDOW(popup), GTK_WINDOW(gtk_widget_get_toplevel(widget)));
920 gtk_widget_get_allocation(widget, &allocation);
921 gdk_window_get_root_coords(gtk_widget_get_window(widget), allocation.x, allocation.y, &x, &y);
922 gtk_window_move(GTK_WINDOW(popup), x, y);
923 gtk_widget_show(GTK_WIDGET(popup));
927 void shift_left_cb(GtkWidget *widget, MathButtons *buttons);
928 G_MODULE_EXPORT
929 void
930 shift_left_cb(GtkWidget *widget, MathButtons *buttons)
932 if (!buttons->priv->shift_left_menu) {
933 gint i;
934 GtkWidget *menu;
936 menu = buttons->priv->shift_left_menu = gtk_menu_new();
937 gtk_menu_set_reserve_toggle_size(GTK_MENU(menu), FALSE);
938 set_tint(menu, &buttons->priv->color_action, 1);
940 for (i = 1; i < 16; i++) {
941 GtkWidget *item, *label;
942 gchar *format, *text;
944 if (i < 10) {
945 /* Left Shift Popup: Menu item to shift left by n places (n < 10) */
946 format = ngettext("_%d place", "_%d places", i);
948 else {
949 /* Left Shift Popup: Menu item to shift left by n places (n >= 10) */
950 format = ngettext("%d place", "%d places", i);
952 text = g_strdup_printf(format, i);
953 label = gtk_label_new_with_mnemonic(text);
955 item = gtk_menu_item_new();
956 g_object_set_data(G_OBJECT(item), "shiftcount", GINT_TO_POINTER(i));
957 gtk_container_add(GTK_CONTAINER(item), label);
958 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
959 g_signal_connect(item, "activate", G_CALLBACK(shift_cb), buttons);
961 gtk_widget_show(label);
962 gtk_widget_show(item);
963 g_free(text);
967 popup_button_menu(widget, GTK_MENU(buttons->priv->shift_left_menu));
971 void shift_right_cb(GtkWidget *widget, MathButtons *buttons);
972 G_MODULE_EXPORT
973 void
974 shift_right_cb(GtkWidget *widget, MathButtons *buttons)
976 if (!buttons->priv->shift_right_menu) {
977 gint i;
978 GtkWidget *menu;
980 menu = buttons->priv->shift_right_menu = gtk_menu_new();
981 gtk_menu_set_reserve_toggle_size(GTK_MENU(menu), FALSE);
982 set_tint(menu, &buttons->priv->color_action, 1);
984 for (i = 1; i < 16; i++) {
985 GtkWidget *item, *label;
986 gchar *format, *text;
988 if (i < 10) {
989 /* Right Shift Popup: Menu item to shift right by n places (n < 10) */
990 format = ngettext("_%d place", "_%d places", i);
992 else {
993 /* Right Shift Popup: Menu item to shift right by n places (n >= 10) */
994 format = ngettext("%d place", "%d places", i);
996 text = g_strdup_printf(format, i);
997 label = gtk_label_new_with_mnemonic(text);
999 item = gtk_menu_item_new();
1000 g_object_set_data(G_OBJECT(item), "shiftcount", GINT_TO_POINTER(-i));
1001 gtk_container_add(GTK_CONTAINER(item), label);
1002 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1003 g_signal_connect(item, "activate", G_CALLBACK(shift_cb), buttons);
1005 gtk_widget_show(label);
1006 gtk_widget_show(item);
1007 g_free(text);
1011 popup_button_menu(widget, GTK_MENU(buttons->priv->shift_right_menu));
1015 static void
1016 insert_function_cb(GtkWidget *widget, MathButtons *buttons)
1018 math_equation_insert(buttons->priv->equation, g_object_get_data(G_OBJECT(widget), "function"));
1022 void function_cb(GtkWidget *widget, MathButtons *buttons);
1023 G_MODULE_EXPORT
1024 void
1025 function_cb(GtkWidget *widget, MathButtons *buttons)
1027 if (!buttons->priv->function_menu) {
1028 gint i;
1029 GtkWidget *menu;
1030 struct
1032 gchar *name, *function;
1033 } functions[] =
1035 { /* Tooltip for the integer component button */
1036 N_("Integer Component"), "int " },
1037 { /* Tooltip for the fractional component button */
1038 N_("Fractional Component"), "frac " },
1039 { /* Tooltip for the round button */
1040 N_("Round"), "round " },
1041 { /* Tooltip for the floor button */
1042 N_("Floor"), "floor " },
1043 { /* Tooltip for the ceiling button */
1044 N_("Ceiling"), "ceil " },
1045 { /* Tooltip for the ceiling button */
1046 N_("Sign"), "sgn " },
1047 { NULL, NULL }
1050 menu = buttons->priv->function_menu = gtk_menu_new();
1051 gtk_menu_set_reserve_toggle_size(GTK_MENU(menu), FALSE);
1052 set_tint(menu, &buttons->priv->color_function, 1);
1054 for (i = 0; functions[i].name != NULL; i++) {
1055 GtkWidget *item;
1057 item = gtk_menu_item_new_with_label(_(functions[i].name));
1058 g_object_set_data(G_OBJECT(item), "function", g_strdup(functions[i].function));
1059 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1060 g_signal_connect(item, "activate", G_CALLBACK(insert_function_cb), buttons);
1061 gtk_widget_show(item);
1065 popup_button_menu(widget, GTK_MENU(buttons->priv->function_menu));
1069 void factorize_cb(GtkWidget *widget, MathButtons *buttons);
1070 G_MODULE_EXPORT
1071 void
1072 factorize_cb(GtkWidget *widget, MathButtons *buttons)
1074 math_equation_factorize(buttons->priv->equation);
1078 void digit_cb(GtkWidget *widget, MathButtons *buttons);
1079 G_MODULE_EXPORT
1080 void
1081 digit_cb(GtkWidget *widget, MathButtons *buttons)
1083 math_equation_insert_digit(buttons->priv->equation, GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "calc_digit")));
1087 void numeric_point_cb(GtkWidget *widget, MathButtons *buttons);
1088 G_MODULE_EXPORT
1089 void
1090 numeric_point_cb(GtkWidget *widget, MathButtons *buttons)
1092 math_equation_insert_numeric_point(buttons->priv->equation);
1097 void finc_cb(GtkWidget *widget, MathButtons *buttons);
1098 G_MODULE_EXPORT
1099 void
1100 finc_cb(GtkWidget *widget, MathButtons *buttons)
1102 gchar *name;
1104 name = g_object_get_data(G_OBJECT(widget), "finc_dialog");
1105 gtk_dialog_run(GTK_DIALOG(GET_WIDGET(buttons->priv->financial_ui, name)));
1106 gtk_widget_hide(GTK_WIDGET(GET_WIDGET(buttons->priv->financial_ui, name)));
1110 void insert_character_code_cb(GtkWidget *widget, MathButtons *buttons);
1111 G_MODULE_EXPORT
1112 void
1113 insert_character_code_cb(GtkWidget *widget, MathButtons *buttons)
1115 gtk_window_present(GTK_WINDOW(buttons->priv->character_code_dialog));
1119 void finc_activate_cb(GtkWidget *widget, MathButtons *buttons);
1120 G_MODULE_EXPORT
1121 void
1122 finc_activate_cb(GtkWidget *widget, MathButtons *buttons)
1124 gint dialog, field;
1126 dialog = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "finc_dialog"));
1127 field = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "finc_field"));
1129 if (finc_dialog_fields[dialog][field+1] == NULL) {
1130 GtkWidget *dialog_widget;
1131 dialog_widget = gtk_widget_get_toplevel(widget);
1132 if (gtk_widget_is_toplevel(dialog_widget)) {
1133 gtk_dialog_response(GTK_DIALOG(dialog_widget),
1134 GTK_RESPONSE_OK);
1135 return;
1138 else {
1139 GtkWidget *next_widget;
1140 next_widget = GET_WIDGET(buttons->priv->financial_ui, finc_dialog_fields[dialog][field+1]);
1141 gtk_widget_grab_focus(next_widget);
1146 void finc_response_cb(GtkWidget *widget, gint response_id, MathButtons *buttons);
1147 G_MODULE_EXPORT
1148 void
1149 finc_response_cb(GtkWidget *widget, gint response_id, MathButtons *buttons)
1151 int dialog;
1152 int i;
1153 MPNumber arg[4];
1154 GtkWidget *entry;
1156 if (response_id != GTK_RESPONSE_OK)
1157 return;
1159 dialog = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "finc_dialog"));
1161 for (i = 0; i < 4; i++) {
1162 if (finc_dialog_fields[dialog][i] == NULL) {
1163 continue;
1165 entry = GET_WIDGET(buttons->priv->financial_ui, finc_dialog_fields[dialog][i]);
1166 mp_set_from_string(gtk_entry_get_text(GTK_ENTRY(entry)), 10, &arg[i]);
1167 gtk_entry_set_text(GTK_ENTRY(entry), "0");
1169 gtk_widget_grab_focus(GET_WIDGET(buttons->priv->financial_ui, finc_dialog_fields[dialog][0]));
1171 do_finc_expression(buttons->priv->equation, dialog, &arg[0], &arg[1], &arg[2], &arg[3]);
1175 void character_code_dialog_response_cb(GtkWidget *dialog, gint response_id, MathButtons *buttons);
1176 G_MODULE_EXPORT
1177 void
1178 character_code_dialog_response_cb(GtkWidget *dialog, gint response_id, MathButtons *buttons)
1180 const gchar *text;
1182 text = gtk_entry_get_text(GTK_ENTRY(buttons->priv->character_code_entry));
1184 if (response_id == GTK_RESPONSE_OK) {
1185 MPNumber x;
1186 int i = 0;
1188 mp_set_from_integer(0, &x);
1189 while (TRUE) {
1190 mp_add_integer(&x, text[i], &x);
1191 if (text[i+1]) {
1192 mp_shift(&x, 8, &x);
1193 i++;
1195 else
1196 break;
1199 math_equation_insert_number(buttons->priv->equation, &x);
1202 gtk_widget_hide(dialog);
1206 void character_code_dialog_activate_cb(GtkWidget *entry, MathButtons *buttons);
1207 G_MODULE_EXPORT
1208 void
1209 character_code_dialog_activate_cb(GtkWidget *entry, MathButtons *buttons)
1211 character_code_dialog_response_cb(buttons->priv->character_code_dialog, GTK_RESPONSE_OK, buttons);
1215 gboolean character_code_dialog_delete_cb(GtkWidget *dialog, GdkEvent *event, MathButtons *buttons);
1216 G_MODULE_EXPORT
1217 gboolean
1218 character_code_dialog_delete_cb(GtkWidget *dialog, GdkEvent *event, MathButtons *buttons)
1220 character_code_dialog_response_cb(dialog, GTK_RESPONSE_CANCEL, buttons);
1221 return TRUE;
1225 gboolean bit_toggle_cb(GtkWidget *event_box, GdkEventButton *event, MathButtons *buttons);
1226 G_MODULE_EXPORT
1227 gboolean
1228 bit_toggle_cb(GtkWidget *event_box, GdkEventButton *event, MathButtons *buttons)
1230 math_equation_toggle_bit(buttons->priv->equation, GPOINTER_TO_INT(g_object_get_data(G_OBJECT(event_box), "bit_index")));
1231 return TRUE;
1235 static void
1236 remove_trailing_spaces(MathButtons *buttons)
1238 GtkTextMark *insert_mark;
1239 GtkTextIter start, end;
1240 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER(buttons->priv->equation));
1241 gtk_text_buffer_get_iter_at_mark(GTK_TEXT_BUFFER(buttons->priv->equation), &end, insert_mark);
1242 start = end;
1243 while (gtk_text_iter_backward_char(&start)) {
1244 if (!g_unichar_isspace(gtk_text_iter_get_char(&start)))
1245 break;
1246 gtk_text_buffer_delete(GTK_TEXT_BUFFER(buttons->priv->equation), &start, &end);
1251 void set_superscript_cb(GtkWidget *widget, MathButtons *buttons);
1252 G_MODULE_EXPORT
1253 void
1254 set_superscript_cb(GtkWidget *widget, MathButtons *buttons)
1256 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
1257 math_equation_set_number_mode(buttons->priv->equation, SUPERSCRIPT);
1258 if (!gtk_text_buffer_get_has_selection(GTK_TEXT_BUFFER(buttons->priv->equation))) {
1259 remove_trailing_spaces(buttons);
1262 else if (math_equation_get_number_mode(buttons->priv->equation) == SUPERSCRIPT)
1263 math_equation_set_number_mode(buttons->priv->equation, NORMAL);
1267 void set_subscript_cb(GtkWidget *widget, MathButtons *buttons);
1268 G_MODULE_EXPORT
1269 void
1270 set_subscript_cb(GtkWidget *widget, MathButtons *buttons)
1272 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
1273 math_equation_set_number_mode(buttons->priv->equation, SUBSCRIPT);
1274 if (!gtk_text_buffer_get_has_selection(GTK_TEXT_BUFFER(buttons->priv->equation))) {
1275 remove_trailing_spaces(buttons);
1278 else if (math_equation_get_number_mode(buttons->priv->equation) == SUBSCRIPT)
1279 math_equation_set_number_mode(buttons->priv->equation, NORMAL);
1283 static void
1284 number_mode_changed_cb(MathEquation *equation, GParamSpec *spec, MathButtons *buttons)
1286 GList *i;
1287 NumberMode mode;
1289 mode = math_equation_get_number_mode(equation);
1291 for (i = buttons->priv->superscript_toggles; i; i = i->next) {
1292 GtkWidget *widget = i->data;
1293 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), mode == SUPERSCRIPT);
1295 for (i = buttons->priv->subscript_toggles; i; i = i->next) {
1296 GtkWidget *widget = i->data;
1297 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), mode == SUBSCRIPT);
1302 static void
1303 math_buttons_set_property(GObject *object,
1304 guint prop_id,
1305 const GValue *value,
1306 GParamSpec *pspec)
1308 MathButtons *self;
1310 self = MATH_BUTTONS(object);
1312 switch (prop_id) {
1313 case PROP_EQUATION:
1314 self->priv->equation = g_value_get_object(value);
1315 math_buttons_set_mode(self, self->priv->mode);
1316 g_signal_connect(self->priv->equation, "notify::display", G_CALLBACK(display_changed_cb), self);
1317 g_signal_connect(self->priv->equation, "notify::number-mode", G_CALLBACK(number_mode_changed_cb), self);
1318 g_signal_connect(self->priv->equation, "notify::angle-units", G_CALLBACK(display_changed_cb), self);
1319 g_signal_connect(self->priv->equation, "notify::number-format", G_CALLBACK(display_changed_cb), self);
1320 number_mode_changed_cb(self->priv->equation, NULL, self);
1321 display_changed_cb(self->priv->equation, NULL, self);
1322 break;
1323 case PROP_MODE:
1324 math_buttons_set_mode(self, g_value_get_int(value));
1325 break;
1326 default:
1327 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
1328 break;
1333 static void
1334 math_buttons_get_property(GObject *object,
1335 guint prop_id,
1336 GValue *value,
1337 GParamSpec *pspec)
1339 MathButtons *self;
1341 self = MATH_BUTTONS(object);
1343 switch (prop_id) {
1344 case PROP_EQUATION:
1345 g_value_set_object(value, self->priv->equation);
1346 break;
1347 case PROP_MODE:
1348 g_value_set_int(value, self->priv->mode);
1349 break;
1350 default:
1351 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
1352 break;
1357 static void
1358 math_buttons_class_init(MathButtonsClass *klass)
1360 static GEnumValue button_mode_values[] =
1362 {BASIC, "basic", "basic"},
1363 {ADVANCED, "advanced", "advanced"},
1364 {FINANCIAL, "financial", "financial"},
1365 {PROGRAMMING, "programming", "programming"},
1366 {0, NULL, NULL}
1368 GObjectClass *object_class = G_OBJECT_CLASS(klass);
1370 object_class->get_property = math_buttons_get_property;
1371 object_class->set_property = math_buttons_set_property;
1373 g_type_class_add_private(klass, sizeof(MathButtonsPrivate));
1375 button_mode_type = g_enum_register_static("ButtonMode", button_mode_values);
1377 g_object_class_install_property(object_class,
1378 PROP_EQUATION,
1379 g_param_spec_object("equation",
1380 "equation",
1381 "Equation being controlled",
1382 math_equation_get_type(),
1383 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
1384 g_object_class_install_property(object_class,
1385 PROP_MODE,
1386 g_param_spec_enum("mode",
1387 "mode",
1388 "Button mode",
1389 button_mode_type,
1390 BASIC,
1391 G_PARAM_READWRITE));
1395 static void
1396 math_buttons_init(MathButtons *buttons)
1398 buttons->priv = G_TYPE_INSTANCE_GET_PRIVATE(buttons, math_buttons_get_type(), MathButtonsPrivate);
1399 gtk_box_set_spacing(GTK_BOX(buttons), 6);
1400 buttons->priv->programming_base = 10;
1401 gdk_color_parse("#0000FF", &buttons->priv->color_numbers);
1402 gdk_color_parse("#00FF00", &buttons->priv->color_action);
1403 gdk_color_parse("#FF0000", &buttons->priv->color_operator);
1404 gdk_color_parse("#00FFFF", &buttons->priv->color_function);
1405 gdk_color_parse("#FF00FF", &buttons->priv->color_memory);
1406 gdk_color_parse("#FFFFFF", &buttons->priv->color_group);
1407 g_signal_connect(G_OBJECT(buttons), "show", G_CALLBACK(load_buttons), NULL);