Change 'undo' and 'clear' buttons to use symbolic icons
[gcalctool.git] / src / math-buttons.c
blob58fbab34846de2db57c3f1ebe17944b8b53533c4
1 /*
2 * Copyright (C) 2008-2011 Robert Ancell
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU General Public License as published by the Free Software
6 * Foundation, either version 2 of the License, or (at your option) any later
7 * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
8 * license.
9 */
11 #include <glib/gi18n.h>
13 #include "math-buttons.h"
14 #include "math-converter.h"
15 #include "math-variable-popup.h"
16 #include "financial.h"
17 #include "mp-serializer.h"
19 enum {
20 PROP_0,
21 PROP_EQUATION,
22 PROP_MODE,
23 PROP_PROGRAMMING_BASE
26 static GType button_mode_type;
28 #define MAXBITS 64 /* Bit panel: number of bit fields. */
30 struct MathButtonsPrivate
32 MathEquation *equation;
34 ButtonMode mode;
35 gint programming_base;
37 MathConverter *converter;
39 GtkBuilder *basic_ui, *advanced_ui, *financial_ui, *programming_ui;
41 GdkColor color_numbers, color_action, color_operator, color_function, color_memory, color_group;
43 GtkWidget *bas_panel, *adv_panel, *fin_panel, *prog_panel;
44 GtkWidget *active_panel;
46 GtkWidget *shift_left_menu, *shift_right_menu;
48 GtkWidget *function_menu;
50 GList *superscript_toggles;
51 GList *subscript_toggles;
53 GtkWidget *base_combo;
54 GtkWidget *base_label;
55 GtkWidget *bit_panel;
56 GtkWidget *bit_labels[MAXBITS];
58 GtkWidget *character_code_dialog;
59 GtkWidget *character_code_entry;
62 G_DEFINE_TYPE (MathButtons, math_buttons, GTK_TYPE_VBOX);
64 #define UI_BASIC_FILE UI_DIR "/buttons-basic.ui"
65 #define UI_ADVANCED_FILE UI_DIR "/buttons-advanced.ui"
66 #define UI_FINANCIAL_FILE UI_DIR "/buttons-financial.ui"
67 #define UI_PROGRAMMING_FILE UI_DIR "/buttons-programming.ui"
69 #define GET_WIDGET(ui, name) \
70 GTK_WIDGET(gtk_builder_get_object((ui), (name)))
72 #define WM_WIDTH_FACTOR 10
73 #define WM_HEIGHT_FACTOR 30
75 typedef enum
77 NUMBER,
78 NUMBER_BOLD,
79 OPERATOR,
80 FUNCTION,
81 MEMORY,
82 GROUP,
83 ACTION
84 } ButtonClass;
86 typedef struct {
87 const char *widget_name;
88 const char *data;
89 ButtonClass class;
90 const char *tooltip;
91 } ButtonData;
93 static ButtonData button_data[] = {
94 {"pi", "π", NUMBER,
95 /* Tooltip for the Pi button */
96 N_("Pi [Ctrl+P]")},
97 {"eulers_number", "e", NUMBER,
98 /* Tooltip for the Euler's Number button */
99 N_("Euler’s Number")},
100 {"imaginary", "i", NUMBER, NULL},
101 {"numeric_point", NULL, NUMBER, NULL},
102 {"subscript", NULL, NUMBER_BOLD,
103 /* Tooltip for the subscript button */
104 N_("Subscript mode [Alt]")},
105 {"superscript", NULL, NUMBER_BOLD,
106 /* Tooltip for the superscript button */
107 N_("Superscript mode [Ctrl]")},
108 {"exponential", NULL, NUMBER_BOLD,
109 /* Tooltip for the scientific exponent button */
110 N_("Scientific exponent [Ctrl+E]")},
111 {"add", "+", OPERATOR,
112 /* Tooltip for the add button */
113 N_("Add [+]")},
114 {"subtract", "−", OPERATOR,
115 /* Tooltip for the subtract button */
116 N_("Subtract [-]")},
117 {"multiply", "×", OPERATOR,
118 /* Tooltip for the multiply button */
119 N_("Multiply [*]")},
120 {"divide", "÷", OPERATOR,
121 /* Tooltip for the divide button */
122 N_("Divide [/]")},
123 {"modulus_divide", " mod ", OPERATOR,
124 /* Tooltip for the modulus divide button */
125 N_("Modulus divide")},
126 {"function", NULL, FUNCTION,
127 /* Tooltip for the additional functions button */
128 N_("Additional Functions")},
129 {"x_pow_y", "^", FUNCTION,
130 /* Tooltip for the exponent button */
131 N_("Exponent [^ or **]")},
132 {"x_squared", "²", FUNCTION,
133 /* Tooltip for the square button */
134 N_("Square [Ctrl+2]")},
135 {"percentage", "%", NUMBER,
136 /* Tooltip for the percentage button */
137 N_("Percentage [%]")},
138 {"factorial", "!", FUNCTION,
139 /* Tooltip for the factorial button */
140 N_("Factorial [!]")},
141 {"abs", "|", FUNCTION,
142 /* Tooltip for the absolute value button */
143 N_("Absolute value [|]")},
144 {"arg", "Arg ", FUNCTION,
145 /* Tooltip for the complex argument component button */
146 N_("Complex argument")},
147 {"conjugate", "conj ", FUNCTION,
148 /* Tooltip for the complex conjugate button */
149 N_("Complex conjugate")},
150 {"root", "√", FUNCTION,
151 /* Tooltip for the root button */
152 N_("Root [Ctrl+R]")},
153 {"square_root", "√", FUNCTION,
154 /* Tooltip for the square root button */
155 N_("Square root [Ctrl+R]")},
156 {"logarithm", "log ", FUNCTION,
157 /* Tooltip for the logarithm button */
158 N_("Logarithm")},
159 {"natural_logarithm", "ln ", FUNCTION,
160 /* Tooltip for the natural logarithm button */
161 N_("Natural Logarithm")},
162 {"sine", "sin ", FUNCTION,
163 /* Tooltip for the sine button */
164 N_("Sine")},
165 {"cosine", "cos ", FUNCTION,
166 /* Tooltip for the cosine button */
167 N_("Cosine")},
168 {"tangent", "tan ", FUNCTION,
169 /* Tooltip for the tangent button */
170 N_("Tangent")},
171 {"hyperbolic_sine", "sinh ", FUNCTION,
172 /* Tooltip for the hyperbolic sine button */
173 N_("Hyperbolic Sine")},
174 {"hyperbolic_cosine", "cosh ", FUNCTION,
175 /* Tooltip for the hyperbolic cosine button */
176 N_("Hyperbolic Cosine")},
177 {"hyperbolic_tangent", "tanh ", FUNCTION,
178 /* Tooltip for the hyperbolic tangent button */
179 N_("Hyperbolic Tangent")},
180 {"inverse", "⁻¹", FUNCTION,
181 /* Tooltip for the inverse button */
182 N_("Inverse [Ctrl+I]")},
183 {"and", "∧", OPERATOR,
184 /* Tooltip for the boolean AND button */
185 N_("Boolean AND")},
186 {"or", "∨", OPERATOR,
187 /* Tooltip for the boolean OR button */
188 N_("Boolean OR")},
189 {"xor", "⊻", OPERATOR,
190 /* Tooltip for the exclusive OR button */
191 N_("Boolean Exclusive OR")},
192 {"not", "¬", FUNCTION,
193 /* Tooltip for the boolean NOT button */
194 N_("Boolean NOT")},
195 {"integer_portion", "int ", FUNCTION,
196 /* Tooltip for the integer component button */
197 N_("Integer Component")},
198 {"fractional_portion", "frac ", FUNCTION,
199 /* Tooltip for the fractional component button */
200 N_("Fractional Component")},
201 {"real_portion", "Re ", FUNCTION,
202 /* Tooltip for the real component button */
203 N_("Real Component")},
204 {"imaginary_portion", "Im ", FUNCTION,
205 /* Tooltip for the imaginary component button */
206 N_("Imaginary Component")},
207 {"ones_complement", "ones ", FUNCTION,
208 /* Tooltip for the ones' complement button */
209 N_("Ones' Complement")},
210 {"twos_complement", "twos ", FUNCTION,
211 /* Tooltip for the two's complement button */
212 N_("Two's Complement")},
213 {"trunc", "trunc ", FUNCTION,
214 /* Tooltip for the truncate button */
215 N_("Truncate")},
216 {"start_group", "(", GROUP,
217 /* Tooltip for the start group button */
218 N_("Start Group [(]")},
219 {"end_group", ")", GROUP,
220 /* Tooltip for the end group button */
221 N_("End Group [)]")},
222 {"memory", NULL, MEMORY,
223 /* Tooltip for the memory button */
224 N_("Memory")},
225 {"character", NULL, MEMORY,
226 /* Tooltip for the insert character code button */
227 N_("Insert Character Code")},
228 {"result", NULL, ACTION,
229 /* Tooltip for the solve button */
230 N_("Calculate Result")},
231 {"factor", NULL, ACTION,
232 /* Tooltip for the factor button */
233 N_("Factorize [Ctrl+F]")},
234 {"clear", NULL, GROUP,
235 /* Tooltip for the clear button */
236 N_("Clear Display [Escape]")},
237 {"undo", NULL, GROUP,
238 /* Tooltip for the undo button */
239 N_("Undo [Ctrl+Z]")},
240 {"shift_left", NULL, ACTION,
241 /* Tooltip for the shift left button */
242 N_("Shift Left")},
243 {"shift_right", NULL, ACTION,
244 /* Tooltip for the shift right button */
245 N_("Shift Right")},
246 {"finc_compounding_term", NULL, FUNCTION,
247 /* Tooltip for the compounding term button */
248 N_("Compounding Term")},
249 {"finc_double_declining_depreciation", NULL, FUNCTION,
250 /* Tooltip for the double declining depreciation button */
251 N_("Double Declining Depreciation")},
252 {"finc_future_value", NULL, FUNCTION,
253 /* Tooltip for the future value button */
254 N_("Future Value")},
255 {"finc_term", NULL, FUNCTION,
256 /* Tooltip for the financial term button */
257 N_("Financial Term")},
258 {"finc_sum_of_the_years_digits_depreciation", NULL, FUNCTION,
259 /* Tooltip for the sum of the years digits depreciation button */
260 N_("Sum of the Years Digits Depreciation")},
261 {"finc_straight_line_depreciation", NULL, FUNCTION,
262 /* Tooltip for the straight line depreciation button */
263 N_("Straight Line Depreciation")},
264 {"finc_periodic_interest_rate", NULL, FUNCTION,
265 /* Tooltip for the periodic interest rate button */
266 N_("Periodic Interest Rate")},
267 {"finc_present_value", NULL, FUNCTION,
268 /* Tooltip for the present value button */
269 N_("Present Value")},
270 {"finc_periodic_payment", NULL, FUNCTION,
271 /* Tooltip for the periodic payment button */
272 N_("Periodic Payment")},
273 {"finc_gross_profit_margin", NULL, FUNCTION,
274 /* Tooltip for the gross profit margin button */
275 N_("Gross Profit Margin")},
276 {NULL, NULL, 0, NULL}
279 /* The names of each field in the dialogs for the financial functions */
280 static char *finc_dialog_fields[][5] = {
281 {"ctrm_pint", "ctrm_fv", "ctrm_pv", NULL, NULL},
282 {"ddb_cost", "ddb_life", "ddb_period", NULL, NULL},
283 {"fv_pmt", "fv_pint", "fv_n", NULL, NULL},
284 {"gpm_cost", "gpm_margin", NULL, NULL, NULL},
285 {"pmt_prin", "pmt_pint", "pmt_n", NULL, NULL},
286 {"pv_pmt", "pv_pint", "pv_n", NULL, NULL},
287 {"rate_fv", "rate_pv", "rate_n", NULL, NULL},
288 {"sln_cost", "sln_salvage", "sln_life", NULL, NULL},
289 {"syd_cost", "syd_salvage", "syd_life", "syd_period", NULL},
290 {"term_pmt", "term_fv", "term_pint", NULL, NULL},
291 {NULL, NULL, NULL, NULL, NULL}
295 MathButtons *
296 math_buttons_new(MathEquation *equation)
298 return g_object_new(math_buttons_get_type(), "equation", equation, NULL);
302 static void
303 set_tint(GtkWidget *widget, GdkColor *tint, gint alpha)
305 GtkStyle *style;
306 int j;
308 if (!widget)
309 return;
311 gtk_widget_ensure_style(widget);
312 style = gtk_widget_get_style(widget);
314 for (j = 0; j < 5; j++) {
315 GdkColor color;
317 color.red = (style->bg[j].red * (10 - alpha) + tint->red * alpha) / 10;
318 color.green = (style->bg[j].green * (10 - alpha) + tint->green * alpha) / 10;
319 color.blue = (style->bg[j].blue * (10 - alpha) + tint->blue * alpha) / 10;
321 gtk_widget_modify_bg(widget, j, &color);
326 static void
327 set_data(GtkBuilder *ui, const gchar *object_name, const gchar *name, const char *value)
329 GObject *object;
330 object = gtk_builder_get_object(ui, object_name);
331 if (object)
332 g_object_set_data(object, name, GINT_TO_POINTER(value));
336 static void
337 set_int_data(GtkBuilder *ui, const gchar *object_name, const gchar *name, gint value)
339 GObject *object;
340 object = gtk_builder_get_object(ui, object_name);
341 if (object)
342 g_object_set_data(object, name, GINT_TO_POINTER(value));
346 static void
347 load_finc_dialogs(MathButtons *buttons)
349 int i, j;
351 set_int_data(buttons->priv->financial_ui, "ctrm_dialog", "finc_dialog", FINC_CTRM_DIALOG);
352 set_int_data(buttons->priv->financial_ui, "ddb_dialog", "finc_dialog", FINC_DDB_DIALOG);
353 set_int_data(buttons->priv->financial_ui, "fv_dialog", "finc_dialog", FINC_FV_DIALOG);
354 set_int_data(buttons->priv->financial_ui, "gpm_dialog", "finc_dialog", FINC_GPM_DIALOG);
355 set_int_data(buttons->priv->financial_ui, "pmt_dialog", "finc_dialog", FINC_PMT_DIALOG);
356 set_int_data(buttons->priv->financial_ui, "pv_dialog", "finc_dialog", FINC_PV_DIALOG);
357 set_int_data(buttons->priv->financial_ui, "rate_dialog", "finc_dialog", FINC_RATE_DIALOG);
358 set_int_data(buttons->priv->financial_ui, "sln_dialog", "finc_dialog", FINC_SLN_DIALOG);
359 set_int_data(buttons->priv->financial_ui, "syd_dialog", "finc_dialog", FINC_SYD_DIALOG);
360 set_int_data(buttons->priv->financial_ui, "term_dialog", "finc_dialog", FINC_TERM_DIALOG);
362 for (i = 0; finc_dialog_fields[i][0] != NULL; i++) {
363 for (j = 0; finc_dialog_fields[i][j]; j++) {
364 GObject *o;
365 o = gtk_builder_get_object (buttons->priv->financial_ui, finc_dialog_fields[i][j]);
366 g_object_set_data(o, "finc_field", GINT_TO_POINTER(j));
367 g_object_set_data(o, "finc_dialog", GINT_TO_POINTER(i));
373 static void
374 update_bit_panel(MathButtons *buttons)
376 MPNumber x;
377 gboolean enabled;
378 guint64 bits;
379 int i;
380 GString *label;
381 gint base;
383 if (!buttons->priv->bit_panel)
384 return;
386 enabled = math_equation_get_number(buttons->priv->equation, &x);
388 if (enabled) {
389 MPNumber max, fraction;
391 mp_set_from_unsigned_integer(G_MAXUINT64, &max);
392 mp_fractional_part(&x, &fraction);
393 if (mp_is_negative(&x) || mp_is_greater_than(&x, &max) || !mp_is_zero(&fraction))
394 enabled = FALSE;
395 else
396 bits = mp_cast_to_unsigned_int(&x);
399 gtk_widget_set_sensitive(buttons->priv->bit_panel, enabled);
400 gtk_widget_set_sensitive(buttons->priv->base_label, enabled);
402 if (!enabled)
403 return;
405 for (i = 0; i < MAXBITS; i++) {
406 const gchar *label;
408 if (bits & (1LL << (MAXBITS-i-1)))
409 label = " 1";
410 else
411 label = " 0";
412 gtk_label_set_text(GTK_LABEL(buttons->priv->bit_labels[i]), label);
415 base = math_equation_get_base(buttons->priv->equation);
416 label = g_string_new("");
417 if (base != 8) {
418 if (label->len != 0)
419 g_string_append(label, " = ");
420 g_string_append_printf(label, "%" G_GINT64_MODIFIER "o", bits);
421 g_string_append(label, "₈");
423 if (base != 10) {
424 if (label->len != 0)
425 g_string_append(label, " = ");
426 g_string_append_printf(label, "%" G_GINT64_MODIFIER "u", bits);
427 g_string_append(label, "₁₀");
429 if (base != 16) {
430 if (label->len != 0)
431 g_string_append(label, " = ");
432 g_string_append_printf(label, "%" G_GINT64_MODIFIER "X", bits);
433 g_string_append(label, "₁₆");
436 gtk_label_set_text(GTK_LABEL(buttons->priv->base_label), label->str);
437 g_string_free(label, TRUE);
441 static void
442 display_changed_cb(MathEquation *equation, GParamSpec *spec, MathButtons *buttons)
444 update_bit_panel(buttons);
448 static void
449 base_combobox_changed_cb(GtkWidget *combo, MathButtons *buttons)
451 gint value;
452 GtkTreeModel *model;
453 GtkTreeIter iter;
455 model = gtk_combo_box_get_model(GTK_COMBO_BOX(combo));
456 gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combo), &iter);
457 gtk_tree_model_get(model, &iter, 1, &value, -1);
459 math_buttons_set_programming_base(buttons, value);
463 static void
464 base_changed_cb(MathEquation *equation, GParamSpec *spec, MathButtons *buttons)
466 GtkTreeModel *model;
467 GtkTreeIter iter;
468 gboolean valid;
470 if (buttons->priv->mode != PROGRAMMING)
471 return;
473 model = gtk_combo_box_get_model(GTK_COMBO_BOX(buttons->priv->base_combo));
474 valid = gtk_tree_model_get_iter_first(model, &iter);
475 buttons->priv->programming_base = math_equation_get_base(buttons->priv->equation);
477 while (valid) {
478 gint v;
480 gtk_tree_model_get(model, &iter, 1, &v, -1);
481 if (v == buttons->priv->programming_base)
482 break;
483 valid = gtk_tree_model_iter_next(model, &iter);
485 if (!valid)
486 valid = gtk_tree_model_get_iter_first(model, &iter);
488 gtk_combo_box_set_active_iter(GTK_COMBO_BOX(buttons->priv->base_combo), &iter);
492 static GtkWidget *
493 load_mode(MathButtons *buttons, ButtonMode mode)
495 GtkBuilder *builder, **builder_ptr;
496 gint i;
497 gchar *name;
498 const gchar *builder_file;
499 static gchar *objects[] = { "button_panel", "character_code_dialog", "currency_dialog",
500 "ctrm_dialog", "ddb_dialog", "fv_dialog", "gpm_dialog",
501 "pmt_dialog", "pv_dialog", "rate_dialog", "sln_dialog",
502 "syd_dialog", "term_dialog", "adjustment1", "adjustment2", NULL };
503 GtkWidget *widget, **panel;
504 GError *error = NULL;
506 switch (mode) {
507 default:
508 case BASIC:
509 builder_ptr = &buttons->priv->basic_ui;
510 builder_file = UI_BASIC_FILE;
511 panel = &buttons->priv->bas_panel;
512 break;
513 case ADVANCED:
514 builder_ptr = &buttons->priv->advanced_ui;
515 builder_file = UI_ADVANCED_FILE;
516 panel = &buttons->priv->adv_panel;
517 break;
518 case FINANCIAL:
519 builder_ptr = &buttons->priv->financial_ui;
520 builder_file = UI_FINANCIAL_FILE;
521 panel = &buttons->priv->fin_panel;
522 break;
523 case PROGRAMMING:
524 builder_ptr = &buttons->priv->programming_ui;
525 builder_file = UI_PROGRAMMING_FILE;
526 panel = &buttons->priv->prog_panel;
527 break;
530 if (*panel)
531 return *panel;
533 builder = *builder_ptr = gtk_builder_new();
534 // FIXME: Show dialog if failed to load
535 gtk_builder_add_objects_from_file(builder, builder_file, objects, &error);
536 if (error) {
537 g_warning("Error loading button UI: %s", error->message);
538 g_clear_error(&error);
540 *panel = GET_WIDGET(builder, "button_panel");
541 gtk_box_pack_end(GTK_BOX(buttons), *panel, TRUE, TRUE, 0);
543 /* Configure buttons */
544 for (i = 0; button_data[i].widget_name != NULL; i++) {
545 GObject *object;
546 GtkWidget *button;
548 name = g_strdup_printf("calc_%s_button", button_data[i].widget_name);
549 object = gtk_builder_get_object(*builder_ptr, name);
550 g_free(name);
552 if (!object)
553 continue;
554 button = GTK_WIDGET(object);
555 if (button_data[i].data)
556 g_object_set_data(object, "calc_text", (gpointer) button_data[i].data);
558 if (button_data[i].tooltip)
559 gtk_widget_set_tooltip_text(button, _(button_data[i].tooltip));
561 atk_object_set_name(gtk_widget_get_accessible(button), button_data[i].widget_name);
563 switch (button_data[i].class) {
564 case NUMBER:
565 set_tint(button, &buttons->priv->color_numbers, 1);
566 break;
567 case NUMBER_BOLD:
568 set_tint(button, &buttons->priv->color_numbers, 2);
569 break;
570 case OPERATOR:
571 set_tint(button, &buttons->priv->color_operator, 1);
572 break;
573 case FUNCTION:
574 set_tint(button, &buttons->priv->color_function, 1);
575 break;
576 case MEMORY:
577 set_tint(button, &buttons->priv->color_memory, 1);
578 break;
579 case GROUP:
580 set_tint(button, &buttons->priv->color_group, 1);
581 break;
582 case ACTION:
583 set_tint(button, &buttons->priv->color_action, 2);
584 break;
588 /* Set special button data */
589 for (i = 0; i < 16; i++) {
590 GtkWidget *button;
592 name = g_strdup_printf("calc_%d_button", i);
593 button = GET_WIDGET(builder, name);
594 if (button) {
595 gchar buffer[7];
596 gint len;
598 g_object_set_data(G_OBJECT(button), "calc_digit", GINT_TO_POINTER(i));
599 set_tint(button, &buttons->priv->color_numbers, 1);
600 len = g_unichar_to_utf8(math_equation_get_digit_text(buttons->priv->equation, i), buffer);
601 buffer[len] = '\0';
602 gtk_button_set_label(GTK_BUTTON(button), buffer);
604 g_free(name);
606 widget = GET_WIDGET(builder, "calc_numeric_point_button");
607 if (widget) {
608 MpSerializer *serializer = math_equation_get_serializer(buttons->priv->equation);
609 gchar buffer[7];
610 gint len;
611 len = g_unichar_to_utf8(mp_serializer_get_radix(serializer), buffer);
612 buffer[len] = '\0';
613 gtk_button_set_label(GTK_BUTTON(widget), buffer);
616 widget = GET_WIDGET(builder, "calc_superscript_button");
617 if (widget) {
618 buttons->priv->superscript_toggles = g_list_append(buttons->priv->superscript_toggles, widget);
619 if (math_equation_get_number_mode(buttons->priv->equation) == SUPERSCRIPT)
620 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), TRUE);
622 widget = GET_WIDGET(builder, "calc_subscript_button");
623 if (widget) {
624 buttons->priv->subscript_toggles = g_list_append(buttons->priv->subscript_toggles, widget);
625 if (math_equation_get_number_mode(buttons->priv->equation) == SUBSCRIPT)
626 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), TRUE);
629 if (mode == PROGRAMMING) {
630 GtkListStore *model;
631 GtkTreeIter iter;
632 GtkCellRenderer *renderer;
634 buttons->priv->base_label = GET_WIDGET(builder, "base_label");
635 buttons->priv->character_code_dialog = GET_WIDGET(builder, "character_code_dialog");
636 buttons->priv->character_code_entry = GET_WIDGET(builder, "character_code_entry");
638 buttons->priv->bit_panel = GET_WIDGET(builder, "bit_table");
639 for (i = 0; i < MAXBITS; i++) {
640 name = g_strdup_printf("bit_label_%d", i);
641 buttons->priv->bit_labels[i] = GET_WIDGET(builder, name);
642 g_free(name);
643 name = g_strdup_printf("bit_eventbox_%d", i);
644 set_int_data(builder, name, "bit_index", i);
647 buttons->priv->base_combo = GET_WIDGET(builder, "base_combo");
648 model = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT);
649 gtk_combo_box_set_model(GTK_COMBO_BOX(buttons->priv->base_combo), GTK_TREE_MODEL(model));
650 gtk_list_store_append(GTK_LIST_STORE(model), &iter);
651 gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0,
652 /* Number display mode combo: Binary, e.g. 10011010010₂ */
653 _("Binary"), 1, 2, -1);
654 gtk_list_store_append(GTK_LIST_STORE(model), &iter);
655 gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0,
656 /* Number display mode combo: Octal, e.g. 2322₈ */
657 _("Octal"), 1, 8, -1);
658 gtk_list_store_append(GTK_LIST_STORE(model), &iter);
659 gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0,
660 /* Number display mode combo: Decimal, e.g. 1234 */
661 _("Decimal"), 1, 10, -1);
662 gtk_list_store_append(GTK_LIST_STORE(model), &iter);
663 gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0,
664 /* Number display mode combo: Hexadecimal, e.g. 4D2₁₆ */
665 _("Hexadecimal"), 1, 16, -1);
666 renderer = gtk_cell_renderer_text_new();
667 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(buttons->priv->base_combo), renderer, TRUE);
668 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(buttons->priv->base_combo), renderer, "text", 0);
670 g_signal_connect(buttons->priv->base_combo, "changed", G_CALLBACK(base_combobox_changed_cb), buttons);
671 g_signal_connect(buttons->priv->equation, "notify::base", G_CALLBACK(base_changed_cb), buttons);
672 base_changed_cb(buttons->priv->equation, NULL, buttons);
675 /* Setup financial functions */
676 if (mode == FINANCIAL) {
677 load_finc_dialogs(buttons);
679 set_data(builder, "calc_finc_compounding_term_button", "finc_dialog", "ctrm_dialog");
680 set_data(builder, "calc_finc_double_declining_depreciation_button", "finc_dialog", "ddb_dialog");
681 set_data(builder, "calc_finc_future_value_button", "finc_dialog", "fv_dialog");
682 set_data(builder, "calc_finc_gross_profit_margin_button", "finc_dialog", "gpm_dialog");
683 set_data(builder, "calc_finc_periodic_payment_button", "finc_dialog", "pmt_dialog");
684 set_data(builder, "calc_finc_present_value_button", "finc_dialog", "pv_dialog");
685 set_data(builder, "calc_finc_periodic_interest_rate_button", "finc_dialog", "rate_dialog");
686 set_data(builder, "calc_finc_straight_line_depreciation_button", "finc_dialog", "sln_dialog");
687 set_data(builder, "calc_finc_sum_of_the_years_digits_depreciation_button", "finc_dialog", "syd_dialog");
688 set_data(builder, "calc_finc_term_button", "finc_dialog", "term_dialog");
691 gtk_builder_connect_signals(builder, buttons);
693 display_changed_cb(buttons->priv->equation, NULL, buttons);
695 return *panel;
699 static void
700 converter_changed_cb(MathConverter *converter, MathButtons *buttons)
702 Unit *from_unit, *to_unit;
704 math_converter_get_conversion(converter, &from_unit, &to_unit);
705 if (buttons->priv->mode == FINANCIAL) {
706 math_equation_set_source_currency(buttons->priv->equation, unit_get_name(from_unit));
707 math_equation_set_target_currency(buttons->priv->equation, unit_get_name(to_unit));
709 else {
710 math_equation_set_source_units(buttons->priv->equation, unit_get_name(from_unit));
711 math_equation_set_target_units(buttons->priv->equation, unit_get_name(to_unit));
714 g_object_unref(from_unit);
715 g_object_unref(to_unit);
719 static void
720 load_buttons(MathButtons *buttons)
722 GtkWidget *panel;
724 if (!gtk_widget_get_visible(GTK_WIDGET(buttons)))
725 return;
727 if (!buttons->priv->converter) {
728 buttons->priv->converter = math_converter_new(buttons->priv->equation);
729 g_signal_connect(buttons->priv->converter, "changed", G_CALLBACK(converter_changed_cb), buttons);
730 gtk_box_pack_start(GTK_BOX(buttons), GTK_WIDGET(buttons->priv->converter), FALSE, TRUE, 0);
733 panel = load_mode(buttons, buttons->priv->mode);
734 if (buttons->priv->active_panel == panel)
735 return;
737 /* Hide old buttons */
738 if (buttons->priv->active_panel)
739 gtk_widget_hide(buttons->priv->active_panel);
741 /* Load and display new buttons */
742 buttons->priv->active_panel = panel;
743 if (panel)
744 gtk_widget_show(panel);
748 void
749 math_buttons_set_mode(MathButtons *buttons, ButtonMode mode)
751 g_return_if_fail(buttons != NULL);
753 if (buttons->priv->mode == mode)
754 return;
756 buttons->priv->mode = mode;
758 if (mode == PROGRAMMING)
759 math_equation_set_base(buttons->priv->equation, buttons->priv->programming_base);
760 else
761 math_equation_set_base(buttons->priv->equation, 10);
763 load_buttons(buttons);
765 gtk_widget_set_visible(GTK_WIDGET(buttons->priv->converter), mode == ADVANCED || mode == FINANCIAL);
766 if (mode == ADVANCED) {
767 math_converter_set_category(buttons->priv->converter, NULL);
768 math_converter_set_conversion(buttons->priv->converter,
769 math_equation_get_source_units(buttons->priv->equation),
770 math_equation_get_target_units(buttons->priv->equation));
772 else if (mode == FINANCIAL) {
773 math_converter_set_category(buttons->priv->converter, "currency");
774 math_converter_set_conversion(buttons->priv->converter,
775 math_equation_get_source_currency(buttons->priv->equation),
776 math_equation_get_target_currency(buttons->priv->equation));
779 g_object_notify(G_OBJECT(buttons), "mode");
783 ButtonMode
784 math_buttons_get_mode(MathButtons *buttons)
786 return buttons->priv->mode;
790 void
791 math_buttons_set_programming_base(MathButtons *buttons, gint base)
793 g_return_if_fail(buttons != NULL);
795 if (base == buttons->priv->programming_base)
796 return;
798 buttons->priv->programming_base = base;
799 g_object_notify(G_OBJECT(buttons), "programming-base");
801 if (buttons->priv->mode == PROGRAMMING)
802 math_equation_set_base(buttons->priv->equation, base);
806 gint
807 math_buttons_get_programming_base(MathButtons *buttons)
809 g_return_val_if_fail(buttons != NULL, 10);
810 return buttons->priv->programming_base;
814 void exponent_cb(GtkWidget *widget, MathButtons *buttons);
815 G_MODULE_EXPORT
816 void
817 exponent_cb(GtkWidget *widget, MathButtons *buttons)
819 math_equation_insert_exponent(buttons->priv->equation);
823 void subtract_cb(GtkWidget *widget, MathButtons *buttons);
824 G_MODULE_EXPORT
825 void
826 subtract_cb(GtkWidget *widget, MathButtons *buttons)
828 math_equation_insert_subtract(buttons->priv->equation);
832 void button_cb(GtkWidget *widget, MathButtons *buttons);
833 G_MODULE_EXPORT
834 void
835 button_cb(GtkWidget *widget, MathButtons *buttons)
837 math_equation_insert(buttons->priv->equation, g_object_get_data(G_OBJECT(widget), "calc_text"));
841 void solve_cb(GtkWidget *widget, MathButtons *buttons);
842 G_MODULE_EXPORT
843 void
844 solve_cb(GtkWidget *widget, MathButtons *buttons)
846 math_equation_solve(buttons->priv->equation);
850 void clear_cb(GtkWidget *widget, MathButtons *buttons);
851 G_MODULE_EXPORT
852 void
853 clear_cb(GtkWidget *widget, MathButtons *buttons)
855 math_equation_clear(buttons->priv->equation);
859 void delete_cb(GtkWidget *widget, MathButtons *buttons);
860 G_MODULE_EXPORT
861 void
862 delete_cb(GtkWidget *widget, MathButtons *buttons)
864 math_equation_delete(buttons->priv->equation);
868 void undo_cb(GtkWidget *widget, MathButtons *buttons);
869 G_MODULE_EXPORT
870 void
871 undo_cb(GtkWidget *widget, MathButtons *buttons)
873 math_equation_undo(buttons->priv->equation);
877 static void
878 shift_cb(GtkWidget *widget, MathButtons *buttons)
880 math_equation_shift(buttons->priv->equation, GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "shiftcount")));
884 static void
885 button_menu_position_func(GtkMenu *menu, gint *x, gint *y,
886 gboolean *push_in, gpointer user_data)
888 GtkWidget *button = user_data;
889 GtkAllocation allocation;
890 GdkPoint loc;
891 gint border;
893 gdk_window_get_origin(gtk_widget_get_window(button), &loc.x, &loc.y);
894 border = gtk_container_get_border_width(GTK_CONTAINER(button));
895 gtk_widget_get_allocation(button, &allocation);
896 *x = loc.x + allocation.x + border;
897 *y = loc.y + allocation.y + border;
901 static void
902 popup_button_menu(GtkWidget *widget, GtkMenu *menu)
904 gtk_menu_popup(menu, NULL, NULL,
905 button_menu_position_func, widget, 1, gtk_get_current_event_time());
909 void memory_cb(GtkWidget *widget, MathButtons *buttons);
910 G_MODULE_EXPORT
911 void
912 memory_cb(GtkWidget *widget, MathButtons *buttons)
914 MathVariablePopup *popup;
915 GtkAllocation allocation;
916 gint x, y;
918 popup = math_variable_popup_new(buttons->priv->equation);
919 set_tint(GTK_WIDGET(popup), &buttons->priv->color_memory, 1);
920 gtk_window_set_transient_for(GTK_WINDOW(popup), GTK_WINDOW(gtk_widget_get_toplevel(widget)));
922 gtk_widget_get_allocation(widget, &allocation);
923 gdk_window_get_root_coords(gtk_widget_get_window(widget), allocation.x, allocation.y, &x, &y);
924 gtk_window_move(GTK_WINDOW(popup), x, y);
925 gtk_widget_show(GTK_WIDGET(popup));
929 void shift_left_cb(GtkWidget *widget, MathButtons *buttons);
930 G_MODULE_EXPORT
931 void
932 shift_left_cb(GtkWidget *widget, MathButtons *buttons)
934 if (!buttons->priv->shift_left_menu) {
935 gint i;
936 GtkWidget *menu;
938 menu = buttons->priv->shift_left_menu = gtk_menu_new();
939 gtk_menu_set_reserve_toggle_size(GTK_MENU(menu), FALSE);
940 set_tint(menu, &buttons->priv->color_action, 1);
942 for (i = 1; i < 16; i++) {
943 GtkWidget *item, *label;
944 gchar *format, *text;
946 if (i < 10) {
947 /* Left Shift Popup: Menu item to shift left by n places (n < 10) */
948 format = ngettext("_%d place", "_%d places", i);
950 else {
951 /* Left Shift Popup: Menu item to shift left by n places (n >= 10) */
952 format = ngettext("%d place", "%d places", i);
954 text = g_strdup_printf(format, i);
955 label = gtk_label_new_with_mnemonic(text);
957 item = gtk_menu_item_new();
958 g_object_set_data(G_OBJECT(item), "shiftcount", GINT_TO_POINTER(i));
959 gtk_container_add(GTK_CONTAINER(item), label);
960 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
961 g_signal_connect(item, "activate", G_CALLBACK(shift_cb), buttons);
963 gtk_widget_show(label);
964 gtk_widget_show(item);
965 g_free(text);
969 popup_button_menu(widget, GTK_MENU(buttons->priv->shift_left_menu));
973 void shift_right_cb(GtkWidget *widget, MathButtons *buttons);
974 G_MODULE_EXPORT
975 void
976 shift_right_cb(GtkWidget *widget, MathButtons *buttons)
978 if (!buttons->priv->shift_right_menu) {
979 gint i;
980 GtkWidget *menu;
982 menu = buttons->priv->shift_right_menu = gtk_menu_new();
983 gtk_menu_set_reserve_toggle_size(GTK_MENU(menu), FALSE);
984 set_tint(menu, &buttons->priv->color_action, 1);
986 for (i = 1; i < 16; i++) {
987 GtkWidget *item, *label;
988 gchar *format, *text;
990 if (i < 10) {
991 /* Right Shift Popup: Menu item to shift right by n places (n < 10) */
992 format = ngettext("_%d place", "_%d places", i);
994 else {
995 /* Right Shift Popup: Menu item to shift right by n places (n >= 10) */
996 format = ngettext("%d place", "%d places", i);
998 text = g_strdup_printf(format, i);
999 label = gtk_label_new_with_mnemonic(text);
1001 item = gtk_menu_item_new();
1002 g_object_set_data(G_OBJECT(item), "shiftcount", GINT_TO_POINTER(-i));
1003 gtk_container_add(GTK_CONTAINER(item), label);
1004 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1005 g_signal_connect(item, "activate", G_CALLBACK(shift_cb), buttons);
1007 gtk_widget_show(label);
1008 gtk_widget_show(item);
1009 g_free(text);
1013 popup_button_menu(widget, GTK_MENU(buttons->priv->shift_right_menu));
1017 static void
1018 insert_function_cb(GtkWidget *widget, MathButtons *buttons)
1020 math_equation_insert(buttons->priv->equation, g_object_get_data(G_OBJECT(widget), "function"));
1024 void function_cb(GtkWidget *widget, MathButtons *buttons);
1025 G_MODULE_EXPORT
1026 void
1027 function_cb(GtkWidget *widget, MathButtons *buttons)
1029 if (!buttons->priv->function_menu) {
1030 gint i;
1031 GtkWidget *menu;
1032 struct
1034 gchar *name, *function;
1035 } functions[] =
1037 { /* Tooltip for the integer component button */
1038 N_("Integer Component"), "int " },
1039 { /* Tooltip for the fractional component button */
1040 N_("Fractional Component"), "frac " },
1041 { /* Tooltip for the round button */
1042 N_("Round"), "round " },
1043 { /* Tooltip for the floor button */
1044 N_("Floor"), "floor " },
1045 { /* Tooltip for the ceiling button */
1046 N_("Ceiling"), "ceil " },
1047 { /* Tooltip for the ceiling button */
1048 N_("Sign"), "sgn " },
1049 { NULL, NULL }
1052 menu = buttons->priv->function_menu = gtk_menu_new();
1053 gtk_menu_set_reserve_toggle_size(GTK_MENU(menu), FALSE);
1054 set_tint(menu, &buttons->priv->color_function, 1);
1056 for (i = 0; functions[i].name != NULL; i++) {
1057 GtkWidget *item;
1059 item = gtk_menu_item_new_with_label(_(functions[i].name));
1060 g_object_set_data(G_OBJECT(item), "function", g_strdup(functions[i].function));
1061 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1062 g_signal_connect(item, "activate", G_CALLBACK(insert_function_cb), buttons);
1063 gtk_widget_show(item);
1067 popup_button_menu(widget, GTK_MENU(buttons->priv->function_menu));
1071 void factorize_cb(GtkWidget *widget, MathButtons *buttons);
1072 G_MODULE_EXPORT
1073 void
1074 factorize_cb(GtkWidget *widget, MathButtons *buttons)
1076 math_equation_factorize(buttons->priv->equation);
1080 void digit_cb(GtkWidget *widget, MathButtons *buttons);
1081 G_MODULE_EXPORT
1082 void
1083 digit_cb(GtkWidget *widget, MathButtons *buttons)
1085 math_equation_insert_digit(buttons->priv->equation, GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "calc_digit")));
1089 void numeric_point_cb(GtkWidget *widget, MathButtons *buttons);
1090 G_MODULE_EXPORT
1091 void
1092 numeric_point_cb(GtkWidget *widget, MathButtons *buttons)
1094 math_equation_insert_numeric_point(buttons->priv->equation);
1099 void finc_cb(GtkWidget *widget, MathButtons *buttons);
1100 G_MODULE_EXPORT
1101 void
1102 finc_cb(GtkWidget *widget, MathButtons *buttons)
1104 gchar *name;
1106 name = g_object_get_data(G_OBJECT(widget), "finc_dialog");
1107 gtk_dialog_run(GTK_DIALOG(GET_WIDGET(buttons->priv->financial_ui, name)));
1108 gtk_widget_hide(GTK_WIDGET(GET_WIDGET(buttons->priv->financial_ui, name)));
1112 void insert_character_code_cb(GtkWidget *widget, MathButtons *buttons);
1113 G_MODULE_EXPORT
1114 void
1115 insert_character_code_cb(GtkWidget *widget, MathButtons *buttons)
1117 gtk_window_present(GTK_WINDOW(buttons->priv->character_code_dialog));
1121 void finc_activate_cb(GtkWidget *widget, MathButtons *buttons);
1122 G_MODULE_EXPORT
1123 void
1124 finc_activate_cb(GtkWidget *widget, MathButtons *buttons)
1126 gint dialog, field;
1128 dialog = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "finc_dialog"));
1129 field = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "finc_field"));
1131 if (finc_dialog_fields[dialog][field+1] == NULL) {
1132 GtkWidget *dialog_widget;
1133 dialog_widget = gtk_widget_get_toplevel(widget);
1134 if (gtk_widget_is_toplevel(dialog_widget)) {
1135 gtk_dialog_response(GTK_DIALOG(dialog_widget),
1136 GTK_RESPONSE_OK);
1137 return;
1140 else {
1141 GtkWidget *next_widget;
1142 next_widget = GET_WIDGET(buttons->priv->financial_ui, finc_dialog_fields[dialog][field+1]);
1143 gtk_widget_grab_focus(next_widget);
1148 void finc_response_cb(GtkWidget *widget, gint response_id, MathButtons *buttons);
1149 G_MODULE_EXPORT
1150 void
1151 finc_response_cb(GtkWidget *widget, gint response_id, MathButtons *buttons)
1153 int dialog;
1154 int i;
1155 MPNumber arg[4];
1156 GtkWidget *entry;
1158 if (response_id != GTK_RESPONSE_OK)
1159 return;
1161 dialog = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "finc_dialog"));
1163 for (i = 0; i < 4; i++) {
1164 if (finc_dialog_fields[dialog][i] == NULL) {
1165 continue;
1167 entry = GET_WIDGET(buttons->priv->financial_ui, finc_dialog_fields[dialog][i]);
1168 mp_set_from_string(gtk_entry_get_text(GTK_ENTRY(entry)), 10, &arg[i]);
1169 gtk_entry_set_text(GTK_ENTRY(entry), "0");
1171 gtk_widget_grab_focus(GET_WIDGET(buttons->priv->financial_ui, finc_dialog_fields[dialog][0]));
1173 do_finc_expression(buttons->priv->equation, dialog, &arg[0], &arg[1], &arg[2], &arg[3]);
1177 void character_code_dialog_response_cb(GtkWidget *dialog, gint response_id, MathButtons *buttons);
1178 G_MODULE_EXPORT
1179 void
1180 character_code_dialog_response_cb(GtkWidget *dialog, gint response_id, MathButtons *buttons)
1182 const gchar *text;
1184 text = gtk_entry_get_text(GTK_ENTRY(buttons->priv->character_code_entry));
1186 if (response_id == GTK_RESPONSE_OK) {
1187 MPNumber x;
1188 int i = 0;
1190 mp_set_from_integer(0, &x);
1191 while (TRUE) {
1192 mp_add_integer(&x, text[i], &x);
1193 if (text[i+1]) {
1194 mp_shift(&x, 8, &x);
1195 i++;
1197 else
1198 break;
1201 math_equation_insert_number(buttons->priv->equation, &x);
1204 gtk_widget_hide(dialog);
1208 void character_code_dialog_activate_cb(GtkWidget *entry, MathButtons *buttons);
1209 G_MODULE_EXPORT
1210 void
1211 character_code_dialog_activate_cb(GtkWidget *entry, MathButtons *buttons)
1213 character_code_dialog_response_cb(buttons->priv->character_code_dialog, GTK_RESPONSE_OK, buttons);
1217 gboolean character_code_dialog_delete_cb(GtkWidget *dialog, GdkEvent *event, MathButtons *buttons);
1218 G_MODULE_EXPORT
1219 gboolean
1220 character_code_dialog_delete_cb(GtkWidget *dialog, GdkEvent *event, MathButtons *buttons)
1222 character_code_dialog_response_cb(dialog, GTK_RESPONSE_CANCEL, buttons);
1223 return TRUE;
1227 gboolean bit_toggle_cb(GtkWidget *event_box, GdkEventButton *event, MathButtons *buttons);
1228 G_MODULE_EXPORT
1229 gboolean
1230 bit_toggle_cb(GtkWidget *event_box, GdkEventButton *event, MathButtons *buttons)
1232 math_equation_toggle_bit(buttons->priv->equation, GPOINTER_TO_INT(g_object_get_data(G_OBJECT(event_box), "bit_index")));
1233 return TRUE;
1237 static void
1238 remove_trailing_spaces(MathButtons *buttons)
1240 GtkTextMark *insert_mark;
1241 GtkTextIter start, end;
1242 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER(buttons->priv->equation));
1243 gtk_text_buffer_get_iter_at_mark(GTK_TEXT_BUFFER(buttons->priv->equation), &end, insert_mark);
1244 start = end;
1245 while (gtk_text_iter_backward_char(&start)) {
1246 if (!g_unichar_isspace(gtk_text_iter_get_char(&start)))
1247 break;
1248 gtk_text_buffer_delete(GTK_TEXT_BUFFER(buttons->priv->equation), &start, &end);
1253 void set_superscript_cb(GtkWidget *widget, MathButtons *buttons);
1254 G_MODULE_EXPORT
1255 void
1256 set_superscript_cb(GtkWidget *widget, MathButtons *buttons)
1258 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
1259 math_equation_set_number_mode(buttons->priv->equation, SUPERSCRIPT);
1260 if (!gtk_text_buffer_get_has_selection(GTK_TEXT_BUFFER(buttons->priv->equation))) {
1261 remove_trailing_spaces(buttons);
1264 else if (math_equation_get_number_mode(buttons->priv->equation) == SUPERSCRIPT)
1265 math_equation_set_number_mode(buttons->priv->equation, NORMAL);
1269 void set_subscript_cb(GtkWidget *widget, MathButtons *buttons);
1270 G_MODULE_EXPORT
1271 void
1272 set_subscript_cb(GtkWidget *widget, MathButtons *buttons)
1274 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
1275 math_equation_set_number_mode(buttons->priv->equation, SUBSCRIPT);
1276 if (!gtk_text_buffer_get_has_selection(GTK_TEXT_BUFFER(buttons->priv->equation))) {
1277 remove_trailing_spaces(buttons);
1280 else if (math_equation_get_number_mode(buttons->priv->equation) == SUBSCRIPT)
1281 math_equation_set_number_mode(buttons->priv->equation, NORMAL);
1285 static void
1286 number_mode_changed_cb(MathEquation *equation, GParamSpec *spec, MathButtons *buttons)
1288 GList *i;
1289 NumberMode mode;
1291 mode = math_equation_get_number_mode(equation);
1293 for (i = buttons->priv->superscript_toggles; i; i = i->next) {
1294 GtkWidget *widget = i->data;
1295 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), mode == SUPERSCRIPT);
1297 for (i = buttons->priv->subscript_toggles; i; i = i->next) {
1298 GtkWidget *widget = i->data;
1299 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), mode == SUBSCRIPT);
1304 static void
1305 math_buttons_set_property(GObject *object,
1306 guint prop_id,
1307 const GValue *value,
1308 GParamSpec *pspec)
1310 MathButtons *self;
1312 self = MATH_BUTTONS(object);
1314 switch (prop_id) {
1315 case PROP_EQUATION:
1316 self->priv->equation = g_value_get_object(value);
1317 math_buttons_set_mode(self, self->priv->mode);
1318 g_signal_connect(self->priv->equation, "notify::display", G_CALLBACK(display_changed_cb), self);
1319 g_signal_connect(self->priv->equation, "notify::number-mode", G_CALLBACK(number_mode_changed_cb), self);
1320 g_signal_connect(self->priv->equation, "notify::angle-units", G_CALLBACK(display_changed_cb), self);
1321 g_signal_connect(self->priv->equation, "notify::number-format", G_CALLBACK(display_changed_cb), self);
1322 number_mode_changed_cb(self->priv->equation, NULL, self);
1323 display_changed_cb(self->priv->equation, NULL, self);
1324 break;
1325 case PROP_MODE:
1326 math_buttons_set_mode(self, g_value_get_int(value));
1327 break;
1328 case PROP_PROGRAMMING_BASE:
1329 math_buttons_set_programming_base(self, g_value_get_int(value));
1330 break;
1331 default:
1332 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
1333 break;
1338 static void
1339 math_buttons_get_property(GObject *object,
1340 guint prop_id,
1341 GValue *value,
1342 GParamSpec *pspec)
1344 MathButtons *self;
1346 self = MATH_BUTTONS(object);
1348 switch (prop_id) {
1349 case PROP_EQUATION:
1350 g_value_set_object(value, self->priv->equation);
1351 break;
1352 case PROP_MODE:
1353 g_value_set_int(value, self->priv->mode);
1354 break;
1355 case PROP_PROGRAMMING_BASE:
1356 g_value_set_int(value, math_buttons_get_programming_base(self));
1357 break;
1358 default:
1359 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
1360 break;
1365 static void
1366 math_buttons_class_init(MathButtonsClass *klass)
1368 static GEnumValue button_mode_values[] =
1370 {BASIC, "basic", "basic"},
1371 {ADVANCED, "advanced", "advanced"},
1372 {FINANCIAL, "financial", "financial"},
1373 {PROGRAMMING, "programming", "programming"},
1374 {0, NULL, NULL}
1376 GObjectClass *object_class = G_OBJECT_CLASS(klass);
1378 object_class->get_property = math_buttons_get_property;
1379 object_class->set_property = math_buttons_set_property;
1381 g_type_class_add_private(klass, sizeof(MathButtonsPrivate));
1383 button_mode_type = g_enum_register_static("ButtonMode", button_mode_values);
1385 g_object_class_install_property(object_class,
1386 PROP_EQUATION,
1387 g_param_spec_object("equation",
1388 "equation",
1389 "Equation being controlled",
1390 math_equation_get_type(),
1391 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
1392 g_object_class_install_property(object_class,
1393 PROP_MODE,
1394 g_param_spec_enum("mode",
1395 "mode",
1396 "Button mode",
1397 button_mode_type,
1398 BASIC,
1399 G_PARAM_READWRITE));
1400 g_object_class_install_property(object_class,
1401 PROP_PROGRAMMING_BASE,
1402 g_param_spec_int("programming-base",
1403 "programming-base",
1404 "Base to use in programming mode",
1405 2, 16, 10,
1406 G_PARAM_READWRITE));
1410 static void
1411 math_buttons_init(MathButtons *buttons)
1413 buttons->priv = G_TYPE_INSTANCE_GET_PRIVATE(buttons, math_buttons_get_type(), MathButtonsPrivate);
1414 gtk_box_set_spacing(GTK_BOX(buttons), 6);
1415 buttons->priv->programming_base = 10;
1416 gdk_color_parse("#0000FF", &buttons->priv->color_numbers);
1417 gdk_color_parse("#00FF00", &buttons->priv->color_action);
1418 gdk_color_parse("#FF0000", &buttons->priv->color_operator);
1419 gdk_color_parse("#00FFFF", &buttons->priv->color_function);
1420 gdk_color_parse("#FF00FF", &buttons->priv->color_memory);
1421 gdk_color_parse("#FFFFFF", &buttons->priv->color_group);
1422 g_signal_connect(G_OBJECT(buttons), "show", G_CALLBACK(load_buttons), NULL);