Fix 0^n generating error for fractional n
[gcalctool.git] / src / math-buttons.c
blob86f7c1eb67f17cac1f5bc4486ff28665f10e473a
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 ButtonMode old_mode;
753 g_return_if_fail(buttons != NULL);
755 if (buttons->priv->mode == mode)
756 return;
758 old_mode = buttons->priv->mode;
759 buttons->priv->mode = mode;
761 if (mode == PROGRAMMING)
762 math_equation_set_base(buttons->priv->equation, buttons->priv->programming_base);
763 else
764 math_equation_set_base(buttons->priv->equation, 10);
766 load_buttons(buttons);
768 gtk_widget_set_visible(GTK_WIDGET(buttons->priv->converter), mode == ADVANCED || mode == FINANCIAL);
769 if (mode == ADVANCED) {
770 math_converter_set_category(buttons->priv->converter, NULL);
771 math_converter_set_conversion(buttons->priv->converter,
772 math_equation_get_source_units(buttons->priv->equation),
773 math_equation_get_target_units(buttons->priv->equation));
775 else if (mode == FINANCIAL) {
776 math_converter_set_category(buttons->priv->converter, "currency");
777 math_converter_set_conversion(buttons->priv->converter,
778 math_equation_get_source_currency(buttons->priv->equation),
779 math_equation_get_target_currency(buttons->priv->equation));
782 g_object_notify(G_OBJECT(buttons), "mode");
786 ButtonMode
787 math_buttons_get_mode(MathButtons *buttons)
789 return buttons->priv->mode;
793 void
794 math_buttons_set_programming_base(MathButtons *buttons, gint base)
796 g_return_if_fail(buttons != NULL);
798 if (base == buttons->priv->programming_base)
799 return;
801 buttons->priv->programming_base = base;
802 g_object_notify(G_OBJECT(buttons), "programming-base");
804 if (buttons->priv->mode == PROGRAMMING)
805 math_equation_set_base(buttons->priv->equation, base);
809 gint
810 math_buttons_get_programming_base(MathButtons *buttons)
812 g_return_val_if_fail(buttons != NULL, 10);
813 return buttons->priv->programming_base;
817 void exponent_cb(GtkWidget *widget, MathButtons *buttons);
818 G_MODULE_EXPORT
819 void
820 exponent_cb(GtkWidget *widget, MathButtons *buttons)
822 math_equation_insert_exponent(buttons->priv->equation);
826 void subtract_cb(GtkWidget *widget, MathButtons *buttons);
827 G_MODULE_EXPORT
828 void
829 subtract_cb(GtkWidget *widget, MathButtons *buttons)
831 math_equation_insert_subtract(buttons->priv->equation);
835 void button_cb(GtkWidget *widget, MathButtons *buttons);
836 G_MODULE_EXPORT
837 void
838 button_cb(GtkWidget *widget, MathButtons *buttons)
840 math_equation_insert(buttons->priv->equation, g_object_get_data(G_OBJECT(widget), "calc_text"));
844 void solve_cb(GtkWidget *widget, MathButtons *buttons);
845 G_MODULE_EXPORT
846 void
847 solve_cb(GtkWidget *widget, MathButtons *buttons)
849 math_equation_solve(buttons->priv->equation);
853 void clear_cb(GtkWidget *widget, MathButtons *buttons);
854 G_MODULE_EXPORT
855 void
856 clear_cb(GtkWidget *widget, MathButtons *buttons)
858 math_equation_clear(buttons->priv->equation);
862 void delete_cb(GtkWidget *widget, MathButtons *buttons);
863 G_MODULE_EXPORT
864 void
865 delete_cb(GtkWidget *widget, MathButtons *buttons)
867 math_equation_delete(buttons->priv->equation);
871 void undo_cb(GtkWidget *widget, MathButtons *buttons);
872 G_MODULE_EXPORT
873 void
874 undo_cb(GtkWidget *widget, MathButtons *buttons)
876 math_equation_undo(buttons->priv->equation);
880 static void
881 shift_cb(GtkWidget *widget, MathButtons *buttons)
883 math_equation_shift(buttons->priv->equation, GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "shiftcount")));
887 static void
888 button_menu_position_func(GtkMenu *menu, gint *x, gint *y,
889 gboolean *push_in, gpointer user_data)
891 GtkWidget *button = user_data;
892 GtkAllocation allocation;
893 GdkPoint loc;
894 gint border;
896 gdk_window_get_origin(gtk_widget_get_window(button), &loc.x, &loc.y);
897 border = gtk_container_get_border_width(GTK_CONTAINER(button));
898 gtk_widget_get_allocation(button, &allocation);
899 *x = loc.x + allocation.x + border;
900 *y = loc.y + allocation.y + border;
904 static void
905 popup_button_menu(GtkWidget *widget, GtkMenu *menu)
907 gtk_menu_popup(menu, NULL, NULL,
908 button_menu_position_func, widget, 1, gtk_get_current_event_time());
912 void memory_cb(GtkWidget *widget, MathButtons *buttons);
913 G_MODULE_EXPORT
914 void
915 memory_cb(GtkWidget *widget, MathButtons *buttons)
917 MathVariablePopup *popup;
918 GtkAllocation allocation;
919 gint x, y;
921 popup = math_variable_popup_new(buttons->priv->equation);
922 set_tint(GTK_WIDGET(popup), &buttons->priv->color_memory, 1);
923 gtk_window_set_transient_for(GTK_WINDOW(popup), GTK_WINDOW(gtk_widget_get_toplevel(widget)));
925 gtk_widget_get_allocation(widget, &allocation);
926 gdk_window_get_root_coords(gtk_widget_get_window(widget), allocation.x, allocation.y, &x, &y);
927 gtk_window_move(GTK_WINDOW(popup), x, y);
928 gtk_widget_show(GTK_WIDGET(popup));
932 void shift_left_cb(GtkWidget *widget, MathButtons *buttons);
933 G_MODULE_EXPORT
934 void
935 shift_left_cb(GtkWidget *widget, MathButtons *buttons)
937 if (!buttons->priv->shift_left_menu) {
938 gint i;
939 GtkWidget *menu;
941 menu = buttons->priv->shift_left_menu = gtk_menu_new();
942 gtk_menu_set_reserve_toggle_size(GTK_MENU(menu), FALSE);
943 set_tint(menu, &buttons->priv->color_action, 1);
945 for (i = 1; i < 16; i++) {
946 GtkWidget *item, *label;
947 gchar *format, *text;
949 if (i < 10) {
950 /* Left Shift Popup: Menu item to shift left by n places (n < 10) */
951 format = ngettext("_%d place", "_%d places", i);
953 else {
954 /* Left Shift Popup: Menu item to shift left by n places (n >= 10) */
955 format = ngettext("%d place", "%d places", i);
957 text = g_strdup_printf(format, i);
958 label = gtk_label_new_with_mnemonic(text);
960 item = gtk_menu_item_new();
961 g_object_set_data(G_OBJECT(item), "shiftcount", GINT_TO_POINTER(i));
962 gtk_container_add(GTK_CONTAINER(item), label);
963 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
964 g_signal_connect(item, "activate", G_CALLBACK(shift_cb), buttons);
966 gtk_widget_show(label);
967 gtk_widget_show(item);
968 g_free(text);
972 popup_button_menu(widget, GTK_MENU(buttons->priv->shift_left_menu));
976 void shift_right_cb(GtkWidget *widget, MathButtons *buttons);
977 G_MODULE_EXPORT
978 void
979 shift_right_cb(GtkWidget *widget, MathButtons *buttons)
981 if (!buttons->priv->shift_right_menu) {
982 gint i;
983 GtkWidget *menu;
985 menu = buttons->priv->shift_right_menu = gtk_menu_new();
986 gtk_menu_set_reserve_toggle_size(GTK_MENU(menu), FALSE);
987 set_tint(menu, &buttons->priv->color_action, 1);
989 for (i = 1; i < 16; i++) {
990 GtkWidget *item, *label;
991 gchar *format, *text;
993 if (i < 10) {
994 /* Right Shift Popup: Menu item to shift right by n places (n < 10) */
995 format = ngettext("_%d place", "_%d places", i);
997 else {
998 /* Right Shift Popup: Menu item to shift right by n places (n >= 10) */
999 format = ngettext("%d place", "%d places", i);
1001 text = g_strdup_printf(format, i);
1002 label = gtk_label_new_with_mnemonic(text);
1004 item = gtk_menu_item_new();
1005 g_object_set_data(G_OBJECT(item), "shiftcount", GINT_TO_POINTER(-i));
1006 gtk_container_add(GTK_CONTAINER(item), label);
1007 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1008 g_signal_connect(item, "activate", G_CALLBACK(shift_cb), buttons);
1010 gtk_widget_show(label);
1011 gtk_widget_show(item);
1012 g_free(text);
1016 popup_button_menu(widget, GTK_MENU(buttons->priv->shift_right_menu));
1020 static void
1021 insert_function_cb(GtkWidget *widget, MathButtons *buttons)
1023 math_equation_insert(buttons->priv->equation, g_object_get_data(G_OBJECT(widget), "function"));
1027 void function_cb(GtkWidget *widget, MathButtons *buttons);
1028 G_MODULE_EXPORT
1029 void
1030 function_cb(GtkWidget *widget, MathButtons *buttons)
1032 if (!buttons->priv->function_menu) {
1033 gint i;
1034 GtkWidget *menu;
1035 struct
1037 gchar *name, *function;
1038 } functions[] =
1040 { /* Tooltip for the integer component button */
1041 N_("Integer Component"), "int " },
1042 { /* Tooltip for the fractional component button */
1043 N_("Fractional Component"), "frac " },
1044 { /* Tooltip for the round button */
1045 N_("Round"), "round " },
1046 { /* Tooltip for the floor button */
1047 N_("Floor"), "floor " },
1048 { /* Tooltip for the ceiling button */
1049 N_("Ceiling"), "ceil " },
1050 { /* Tooltip for the ceiling button */
1051 N_("Sign"), "sgn " },
1052 { NULL, NULL }
1055 menu = buttons->priv->function_menu = gtk_menu_new();
1056 gtk_menu_set_reserve_toggle_size(GTK_MENU(menu), FALSE);
1057 set_tint(menu, &buttons->priv->color_function, 1);
1059 for (i = 0; functions[i].name != NULL; i++) {
1060 GtkWidget *item;
1062 item = gtk_menu_item_new_with_label(_(functions[i].name));
1063 g_object_set_data(G_OBJECT(item), "function", g_strdup(functions[i].function));
1064 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1065 g_signal_connect(item, "activate", G_CALLBACK(insert_function_cb), buttons);
1066 gtk_widget_show(item);
1070 popup_button_menu(widget, GTK_MENU(buttons->priv->function_menu));
1074 void factorize_cb(GtkWidget *widget, MathButtons *buttons);
1075 G_MODULE_EXPORT
1076 void
1077 factorize_cb(GtkWidget *widget, MathButtons *buttons)
1079 math_equation_factorize(buttons->priv->equation);
1083 void digit_cb(GtkWidget *widget, MathButtons *buttons);
1084 G_MODULE_EXPORT
1085 void
1086 digit_cb(GtkWidget *widget, MathButtons *buttons)
1088 math_equation_insert_digit(buttons->priv->equation, GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "calc_digit")));
1092 void numeric_point_cb(GtkWidget *widget, MathButtons *buttons);
1093 G_MODULE_EXPORT
1094 void
1095 numeric_point_cb(GtkWidget *widget, MathButtons *buttons)
1097 math_equation_insert_numeric_point(buttons->priv->equation);
1102 void finc_cb(GtkWidget *widget, MathButtons *buttons);
1103 G_MODULE_EXPORT
1104 void
1105 finc_cb(GtkWidget *widget, MathButtons *buttons)
1107 gchar *name;
1109 name = g_object_get_data(G_OBJECT(widget), "finc_dialog");
1110 gtk_dialog_run(GTK_DIALOG(GET_WIDGET(buttons->priv->financial_ui, name)));
1111 gtk_widget_hide(GTK_WIDGET(GET_WIDGET(buttons->priv->financial_ui, name)));
1115 void insert_character_code_cb(GtkWidget *widget, MathButtons *buttons);
1116 G_MODULE_EXPORT
1117 void
1118 insert_character_code_cb(GtkWidget *widget, MathButtons *buttons)
1120 gtk_window_present(GTK_WINDOW(buttons->priv->character_code_dialog));
1124 void finc_activate_cb(GtkWidget *widget, MathButtons *buttons);
1125 G_MODULE_EXPORT
1126 void
1127 finc_activate_cb(GtkWidget *widget, MathButtons *buttons)
1129 gint dialog, field;
1131 dialog = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "finc_dialog"));
1132 field = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "finc_field"));
1134 if (finc_dialog_fields[dialog][field+1] == NULL) {
1135 GtkWidget *dialog_widget;
1136 dialog_widget = gtk_widget_get_toplevel(widget);
1137 if (gtk_widget_is_toplevel(dialog_widget)) {
1138 gtk_dialog_response(GTK_DIALOG(dialog_widget),
1139 GTK_RESPONSE_OK);
1140 return;
1143 else {
1144 GtkWidget *next_widget;
1145 next_widget = GET_WIDGET(buttons->priv->financial_ui, finc_dialog_fields[dialog][field+1]);
1146 gtk_widget_grab_focus(next_widget);
1151 void finc_response_cb(GtkWidget *widget, gint response_id, MathButtons *buttons);
1152 G_MODULE_EXPORT
1153 void
1154 finc_response_cb(GtkWidget *widget, gint response_id, MathButtons *buttons)
1156 int dialog;
1157 int i;
1158 MPNumber arg[4];
1159 GtkWidget *entry;
1161 if (response_id != GTK_RESPONSE_OK)
1162 return;
1164 dialog = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "finc_dialog"));
1166 for (i = 0; i < 4; i++) {
1167 if (finc_dialog_fields[dialog][i] == NULL) {
1168 continue;
1170 entry = GET_WIDGET(buttons->priv->financial_ui, finc_dialog_fields[dialog][i]);
1171 mp_set_from_string(gtk_entry_get_text(GTK_ENTRY(entry)), 10, &arg[i]);
1172 gtk_entry_set_text(GTK_ENTRY(entry), "0");
1174 gtk_widget_grab_focus(GET_WIDGET(buttons->priv->financial_ui, finc_dialog_fields[dialog][0]));
1176 do_finc_expression(buttons->priv->equation, dialog, &arg[0], &arg[1], &arg[2], &arg[3]);
1180 void character_code_dialog_response_cb(GtkWidget *dialog, gint response_id, MathButtons *buttons);
1181 G_MODULE_EXPORT
1182 void
1183 character_code_dialog_response_cb(GtkWidget *dialog, gint response_id, MathButtons *buttons)
1185 const gchar *text;
1187 text = gtk_entry_get_text(GTK_ENTRY(buttons->priv->character_code_entry));
1189 if (response_id == GTK_RESPONSE_OK) {
1190 MPNumber x;
1191 int i = 0;
1193 mp_set_from_integer(0, &x);
1194 while (TRUE) {
1195 mp_add_integer(&x, text[i], &x);
1196 if (text[i+1]) {
1197 mp_shift(&x, 8, &x);
1198 i++;
1200 else
1201 break;
1204 math_equation_insert_number(buttons->priv->equation, &x);
1207 gtk_widget_hide(dialog);
1211 void character_code_dialog_activate_cb(GtkWidget *entry, MathButtons *buttons);
1212 G_MODULE_EXPORT
1213 void
1214 character_code_dialog_activate_cb(GtkWidget *entry, MathButtons *buttons)
1216 character_code_dialog_response_cb(buttons->priv->character_code_dialog, GTK_RESPONSE_OK, buttons);
1220 gboolean character_code_dialog_delete_cb(GtkWidget *dialog, GdkEvent *event, MathButtons *buttons);
1221 G_MODULE_EXPORT
1222 gboolean
1223 character_code_dialog_delete_cb(GtkWidget *dialog, GdkEvent *event, MathButtons *buttons)
1225 character_code_dialog_response_cb(dialog, GTK_RESPONSE_CANCEL, buttons);
1226 return TRUE;
1230 gboolean bit_toggle_cb(GtkWidget *event_box, GdkEventButton *event, MathButtons *buttons);
1231 G_MODULE_EXPORT
1232 gboolean
1233 bit_toggle_cb(GtkWidget *event_box, GdkEventButton *event, MathButtons *buttons)
1235 math_equation_toggle_bit(buttons->priv->equation, GPOINTER_TO_INT(g_object_get_data(G_OBJECT(event_box), "bit_index")));
1236 return TRUE;
1240 static void
1241 remove_trailing_spaces(MathButtons *buttons)
1243 GtkTextMark *insert_mark;
1244 GtkTextIter start, end;
1245 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER(buttons->priv->equation));
1246 gtk_text_buffer_get_iter_at_mark(GTK_TEXT_BUFFER(buttons->priv->equation), &end, insert_mark);
1247 start = end;
1248 while (gtk_text_iter_backward_char(&start)) {
1249 if (!g_unichar_isspace(gtk_text_iter_get_char(&start)))
1250 break;
1251 gtk_text_buffer_delete(GTK_TEXT_BUFFER(buttons->priv->equation), &start, &end);
1256 void set_superscript_cb(GtkWidget *widget, MathButtons *buttons);
1257 G_MODULE_EXPORT
1258 void
1259 set_superscript_cb(GtkWidget *widget, MathButtons *buttons)
1261 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
1262 math_equation_set_number_mode(buttons->priv->equation, SUPERSCRIPT);
1263 if (!gtk_text_buffer_get_has_selection(GTK_TEXT_BUFFER(buttons->priv->equation))) {
1264 remove_trailing_spaces(buttons);
1267 else if (math_equation_get_number_mode(buttons->priv->equation) == SUPERSCRIPT)
1268 math_equation_set_number_mode(buttons->priv->equation, NORMAL);
1272 void set_subscript_cb(GtkWidget *widget, MathButtons *buttons);
1273 G_MODULE_EXPORT
1274 void
1275 set_subscript_cb(GtkWidget *widget, MathButtons *buttons)
1277 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
1278 math_equation_set_number_mode(buttons->priv->equation, SUBSCRIPT);
1279 if (!gtk_text_buffer_get_has_selection(GTK_TEXT_BUFFER(buttons->priv->equation))) {
1280 remove_trailing_spaces(buttons);
1283 else if (math_equation_get_number_mode(buttons->priv->equation) == SUBSCRIPT)
1284 math_equation_set_number_mode(buttons->priv->equation, NORMAL);
1288 static void
1289 number_mode_changed_cb(MathEquation *equation, GParamSpec *spec, MathButtons *buttons)
1291 GList *i;
1292 NumberMode mode;
1294 mode = math_equation_get_number_mode(equation);
1296 for (i = buttons->priv->superscript_toggles; i; i = i->next) {
1297 GtkWidget *widget = i->data;
1298 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), mode == SUPERSCRIPT);
1300 for (i = buttons->priv->subscript_toggles; i; i = i->next) {
1301 GtkWidget *widget = i->data;
1302 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), mode == SUBSCRIPT);
1307 static void
1308 math_buttons_set_property(GObject *object,
1309 guint prop_id,
1310 const GValue *value,
1311 GParamSpec *pspec)
1313 MathButtons *self;
1315 self = MATH_BUTTONS(object);
1317 switch (prop_id) {
1318 case PROP_EQUATION:
1319 self->priv->equation = g_value_get_object(value);
1320 math_buttons_set_mode(self, self->priv->mode);
1321 g_signal_connect(self->priv->equation, "notify::display", G_CALLBACK(display_changed_cb), self);
1322 g_signal_connect(self->priv->equation, "notify::number-mode", G_CALLBACK(number_mode_changed_cb), self);
1323 g_signal_connect(self->priv->equation, "notify::angle-units", G_CALLBACK(display_changed_cb), self);
1324 g_signal_connect(self->priv->equation, "notify::number-format", G_CALLBACK(display_changed_cb), self);
1325 number_mode_changed_cb(self->priv->equation, NULL, self);
1326 display_changed_cb(self->priv->equation, NULL, self);
1327 break;
1328 case PROP_MODE:
1329 math_buttons_set_mode(self, g_value_get_int(value));
1330 break;
1331 case PROP_PROGRAMMING_BASE:
1332 math_buttons_set_programming_base(self, g_value_get_int(value));
1333 break;
1334 default:
1335 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
1336 break;
1341 static void
1342 math_buttons_get_property(GObject *object,
1343 guint prop_id,
1344 GValue *value,
1345 GParamSpec *pspec)
1347 MathButtons *self;
1349 self = MATH_BUTTONS(object);
1351 switch (prop_id) {
1352 case PROP_EQUATION:
1353 g_value_set_object(value, self->priv->equation);
1354 break;
1355 case PROP_MODE:
1356 g_value_set_int(value, self->priv->mode);
1357 break;
1358 case PROP_PROGRAMMING_BASE:
1359 g_value_set_int(value, math_buttons_get_programming_base(self));
1360 break;
1361 default:
1362 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
1363 break;
1368 static void
1369 math_buttons_class_init(MathButtonsClass *klass)
1371 static GEnumValue button_mode_values[] =
1373 {BASIC, "basic", "basic"},
1374 {ADVANCED, "advanced", "advanced"},
1375 {FINANCIAL, "financial", "financial"},
1376 {PROGRAMMING, "programming", "programming"},
1377 {0, NULL, NULL}
1379 GObjectClass *object_class = G_OBJECT_CLASS(klass);
1381 object_class->get_property = math_buttons_get_property;
1382 object_class->set_property = math_buttons_set_property;
1384 g_type_class_add_private(klass, sizeof(MathButtonsPrivate));
1386 button_mode_type = g_enum_register_static("ButtonMode", button_mode_values);
1388 g_object_class_install_property(object_class,
1389 PROP_EQUATION,
1390 g_param_spec_object("equation",
1391 "equation",
1392 "Equation being controlled",
1393 math_equation_get_type(),
1394 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
1395 g_object_class_install_property(object_class,
1396 PROP_MODE,
1397 g_param_spec_enum("mode",
1398 "mode",
1399 "Button mode",
1400 button_mode_type,
1401 BASIC,
1402 G_PARAM_READWRITE));
1403 g_object_class_install_property(object_class,
1404 PROP_PROGRAMMING_BASE,
1405 g_param_spec_int("programming-base",
1406 "programming-base",
1407 "Base to use in programming mode",
1408 2, 16, 10,
1409 G_PARAM_READWRITE));
1413 static void
1414 math_buttons_init(MathButtons *buttons)
1416 buttons->priv = G_TYPE_INSTANCE_GET_PRIVATE(buttons, math_buttons_get_type(), MathButtonsPrivate);
1417 gtk_box_set_spacing(GTK_BOX(buttons), 6);
1418 buttons->priv->programming_base = 10;
1419 gdk_color_parse("#0000FF", &buttons->priv->color_numbers);
1420 gdk_color_parse("#00FF00", &buttons->priv->color_action);
1421 gdk_color_parse("#FF0000", &buttons->priv->color_operator);
1422 gdk_color_parse("#00FFFF", &buttons->priv->color_function);
1423 gdk_color_parse("#FF00FF", &buttons->priv->color_memory);
1424 gdk_color_parse("#FFFFFF", &buttons->priv->color_group);
1425 g_signal_connect(G_OBJECT(buttons), "show", G_CALLBACK(load_buttons), NULL);