Disable menu items not valid in current mode (Bug #499625). Clean up bitcalculating...
[gcalctool.git] / gcalctool / gtk.c
blob75ea5837f520ca6d1771a09f95e8e53888b0b665
2 /* $Header$
4 * Copyright (c) 1987-2007 Sun Microsystems, Inc. All Rights Reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 * 02111-1307, USA.
22 #include <stdio.h>
23 #include <string.h>
24 #include <ctype.h>
25 #include <limits.h>
26 #include <sys/param.h>
27 #include <sys/stat.h>
28 #include <netdb.h>
29 #include <gtk/gtk.h>
30 #include <gdk/gdkx.h>
31 #include <gdk/gdkkeysyms.h>
32 #include <glade/glade.h>
34 #include "ui.h"
36 #include "config.h"
37 #include "dsdefs.h"
38 #include "functions.h"
39 #include "lr_parser.h"
40 #include "ce_parser.h"
41 #include "mpmath.h"
42 #include "display.h"
43 #include "get.h"
45 #define MAX_ACCELERATORS 8
46 struct button_widget {
47 int key;
48 char *widget_name;
49 guint accelerator_mods[MAX_ACCELERATORS];
50 guint accelerator_keys[MAX_ACCELERATORS];
53 /* Window titles dependant on mode */
54 static char *titles[] = {
55 N_("Calculator"), N_("Calculator - Advanced"), N_("Calculator - Financial"),
56 N_("Calculator - Scientific")
59 /* Window titles dependant on mode and hostname */
60 static char *hostname_titles[] = {
61 N_("Calculator [%s]"), N_("Calculator [%s] - Advanced"), N_("Calculator [%s] - Financial"),
62 N_("Calculator [%s] - Scientific")
65 /* FIXME: Config value for boolean bitcalculating mode is a string... */
66 static char *Rcstr[MAXBITCALC] = { "NO_BITCALCULATING_MODE", "BITCALCULATING_MODE" };
68 /* This table shows the keyboard values that are currently being used:
70 * | a b c d e f g h i j k l m n o p q r s t u v w x y z
71 *-----------+-----------------------------------------------------
72 * Lower: | a b c d e f i l m n p r s t u v x
73 * Upper: | A C D E F G J K L M N P R S T X Y
74 * Numeric: | 0 1 2 3 4 5 6 7 8 9
75 * Other: | @ . + - * / = % ( ) # < > [ ] { } | & ~ ^ ? ! :
76 * | BackSpace Delete Return
77 *-----------+-----------------------------------------------------
80 static struct button_widget button_widgets[] = {
81 {KEY_0, "0",
82 { 0, GDK_SHIFT_MASK, 0, 0, 0 },
83 { GDK_0, GDK_0, GDK_KP_0, GDK_KP_Insert, 0 }},
85 {KEY_1, "1",
86 { 0, GDK_SHIFT_MASK, 0, 0, 0, 0 },
87 { GDK_1, GDK_1, GDK_KP_1, GDK_KP_End, GDK_R13, 0 }},
89 {KEY_2, "2",
90 { 0, GDK_SHIFT_MASK, 0, 0, 0 },
91 { GDK_2, GDK_2, GDK_KP_2, GDK_KP_Down, 0 }},
93 {KEY_3, "3",
94 { 0, GDK_SHIFT_MASK, 0, 0, 0, 0 },
95 { GDK_3, GDK_3, GDK_KP_3, GDK_KP_Page_Down, GDK_R15, 0 }},
97 {KEY_4, "4",
98 { 0, GDK_SHIFT_MASK, 0, 0, 0 },
99 { GDK_4, GDK_4, GDK_KP_4, GDK_KP_Left, 0 }},
101 {KEY_5, "5",
102 { 0, GDK_SHIFT_MASK, 0, 0, 0, 0 },
103 { GDK_5, GDK_5, GDK_KP_5, GDK_KP_Begin, GDK_R11, 0 }},
105 {KEY_6, "6",
106 { 0, GDK_SHIFT_MASK, 0, 0, 0 },
107 { GDK_6, GDK_6, GDK_KP_6, GDK_KP_Right, 0 }},
109 {KEY_7, "7",
110 { 0, GDK_SHIFT_MASK, 0, 0, 0, 0 },
111 { GDK_7, GDK_7, GDK_KP_7, GDK_KP_Home, GDK_R7, 0 }},
113 {KEY_8, "8",
114 { 0, GDK_SHIFT_MASK, 0, 0, 0 },
115 { GDK_8, GDK_8, GDK_KP_8, GDK_KP_Up, 0 }},
117 {KEY_9, "9",
118 { 0, GDK_SHIFT_MASK, 0, 0, 0, 0 },
119 { GDK_9, GDK_9, GDK_KP_9, GDK_KP_Page_Up, GDK_R9, 0 }},
121 {KEY_A, "a",
122 { 0, 0 },
123 { GDK_a, 0 }},
125 {KEY_B, "b",
126 { 0, 0 },
127 { GDK_b, 0 }},
129 {KEY_C, "c",
130 { 0, 0 },
131 { GDK_c, 0 }},
133 {KEY_D, "d",
134 { 0, 0 },
135 { GDK_d, 0 }},
137 {KEY_E, "e",
138 { 0, 0 },
139 { GDK_e, 0 }},
141 {KEY_F, "f",
142 { 0, 0 },
143 { GDK_f, 0 }},
145 {KEY_CLEAR, "clear_simple",
146 { 0, 0 },
147 { GDK_Delete, 0 }},
149 {KEY_CLEAR, "clear_advanced",
150 { 0, 0 },
151 { GDK_Delete, 0 }},
153 {KEY_SHIFT, "shift_left",
154 { GDK_SHIFT_MASK, 0 },
155 { GDK_less, 0 }},
157 {KEY_SHIFT, "shift_right",
158 { GDK_SHIFT_MASK, 0 },
159 { GDK_greater, 0 }},
161 {KEY_SET_ACCURACY, "accuracy",
162 { GDK_SHIFT_MASK, 0 },
163 { GDK_A, 0 }},
165 {KEY_CONSTANT, "constants",
166 { GDK_SHIFT_MASK, 0, 0 },
167 { GDK_numbersign, GDK_numbersign, 0 }},
169 {KEY_FUNCTION, "functions",
170 { GDK_SHIFT_MASK, 0 },
171 { GDK_F, 0 }},
173 {KEY_STORE, "store",
174 { GDK_SHIFT_MASK, 0 },
175 { GDK_S, 0 }},
177 {KEY_RECALL, "recall",
178 { GDK_SHIFT_MASK, 0 },
179 { GDK_R, 0 }},
181 {KEY_EXCHANGE, "exchange",
182 { GDK_SHIFT_MASK, 0 },
183 { GDK_X, 0 }},
185 {KEY_CLEAR_ENTRY, "clear_entry_simple",
186 { GDK_CONTROL_MASK, 0, 0 },
187 { GDK_BackSpace, GDK_Escape, 0 }},
189 {KEY_CLEAR_ENTRY, "clear_entry_advanced",
190 { GDK_CONTROL_MASK, 0, 0 },
191 { GDK_BackSpace, GDK_Escape, 0 }},
193 {KEY_BACKSPACE, "backspace_simple",
194 { 0, 0 },
195 { GDK_BackSpace, 0 }},
197 {KEY_BACKSPACE, "backspace_advanced",
198 { 0, 0 },
199 { GDK_BackSpace, 0 }},
201 {KEY_NUMERIC_POINT, "numeric_point",
202 { 0, 0, 0, 0 },
203 { GDK_period, GDK_KP_Decimal, GDK_KP_Delete, GDK_KP_Separator, 0 }},
205 {KEY_CALCULATE, "result",
206 { 0, 0, 0, GDK_SHIFT_MASK, 0 },
207 { GDK_equal, GDK_KP_Enter, GDK_Return, GDK_equal, 0 }},
209 {KEY_START_BLOCK, "start_group",
210 { GDK_SHIFT_MASK, 0 },
211 { GDK_parenleft, 0 }},
213 {KEY_END_BLOCK, "end_group",
214 { GDK_SHIFT_MASK, 0 },
215 { GDK_parenright, 0 }},
217 {KEY_ADD, "add",
218 { GDK_SHIFT_MASK, 0, 0, 0 },
219 { GDK_plus, GDK_plus, GDK_KP_Add, 0 }},
221 {KEY_SUBTRACT, "subtract",
222 { 0, 0, 0, 0 },
223 { GDK_minus, GDK_KP_Subtract, GDK_R4, 0 }},
225 {KEY_MULTIPLY, "multiply",
226 { GDK_SHIFT_MASK, 0, 0, 0, 0 },
227 { GDK_asterisk, GDK_KP_Multiply, GDK_x, GDK_R6, 0 }},
229 {KEY_DIVIDE, "divide",
230 { 0, GDK_SHIFT_MASK, 0, 0, GDK_SHIFT_MASK, 0 },
231 { GDK_slash, GDK_slash, GDK_KP_Divide, GDK_R5, GDK_slash, 0 }},
233 {KEY_CHANGE_SIGN, "change_sign_simple",
234 { GDK_SHIFT_MASK, 0 },
235 { GDK_C, 0 }},
237 {KEY_CHANGE_SIGN, "change_sign_advanced",
238 { GDK_SHIFT_MASK, 0 },
239 { GDK_C, 0 }},
241 {KEY_INTEGER, "integer_portion",
242 { 0, 0 },
243 { GDK_i, 0 }},
245 {KEY_FRACTION, "fractional_portion",
246 { GDK_SHIFT_MASK, 0 },
247 { GDK_colon, 0 }},
249 {KEY_PERCENTAGE, "percentage",
250 { GDK_SHIFT_MASK, 0 },
251 { GDK_percent, 0 }},
253 {KEY_SQUARE, "square",
254 { GDK_SHIFT_MASK, 0 },
255 { GDK_at, 0 }},
257 {KEY_SQUARE_ROOT, "sqrt",
258 { 0, 0 },
259 { GDK_s, 0 }},
261 {KEY_RECIPROCAL, "reciprocal",
262 { 0, 0 },
263 { GDK_r, 0 }},
265 {KEY_ABSOLUTE_VALUE, "abs",
266 { 0, 0 },
267 { GDK_u, 0 }},
269 {KEY_MASK_16, "mask_16",
270 { 0, 0 },
271 { GDK_bracketright, 0 }},
273 {KEY_MASK_32, "mask_32",
274 { 0, 0 },
275 { GDK_bracketleft, 0 }},
277 {KEY_MODULUS_DIVIDE, "modulus_divide",
278 { GDK_SHIFT_MASK, 0 },
279 { GDK_M, 0 }},
281 {KEY_EXPONENTIAL, "exponential",
282 { GDK_SHIFT_MASK, 0 },
283 { GDK_E, 0 }},
285 {KEY_E_POW_X, "pow_e",
286 { GDK_SHIFT_MASK, 0 },
287 { GDK_braceleft, 0 }},
289 {KEY_10_POW_X, "pow_10",
290 { GDK_SHIFT_MASK, 0 },
291 { GDK_braceright, 0 }},
293 {KEY_X_POW_Y, "x_pow_y",
294 { GDK_SHIFT_MASK, GDK_SHIFT_MASK, 0 },
295 { GDK_caret, GDK_asciicircum, 0 }},
297 {KEY_NATURAL_LOGARITHM, "natural_logarithm",
298 { GDK_SHIFT_MASK, 0 },
299 { GDK_N, 0 }},
301 {KEY_LOGARITHM, "logarithm",
302 { GDK_SHIFT_MASK, 0 },
303 { GDK_G, 0 }},
305 {KEY_FACTORIAL, "factorial",
306 { GDK_SHIFT_MASK, 0 },
307 { GDK_exclam, 0 }},
309 {KEY_RANDOM, "random",
310 { GDK_SHIFT_MASK, 0 },
311 { GDK_question, 0 }},
313 {KEY_SIN, "sine",
314 { GDK_SHIFT_MASK, 0 },
315 { GDK_K, 0 }},
317 {KEY_COS, "cosine",
318 { GDK_SHIFT_MASK, 0 },
319 { GDK_J, 0 }},
321 {KEY_TAN, "tangent",
322 { GDK_SHIFT_MASK, 0 },
323 { GDK_L, 0 }},
325 {KEY_NOT, "not",
326 { GDK_SHIFT_MASK, 0 },
327 { GDK_asciitilde, 0 }},
329 {KEY_OR, "or",
330 { GDK_SHIFT_MASK, 0 },
331 { GDK_bar, 0 }},
333 {KEY_AND, "and",
334 { GDK_SHIFT_MASK, 0 },
335 { GDK_ampersand, 0 }},
337 {KEY_XOR, "xor",
338 { 0 },
339 { 0 }},
341 {KEY_XNOR, "xnor",
342 { 0, 0 },
343 { GDK_n, 0 }},
345 {KEY_FINC_CTRM, "finc_compounding_term",
346 { 0, 0 },
347 { GDK_m, 0 }},
349 {KEY_FINC_DDB, "finc_double_declining_depreciation",
350 { GDK_SHIFT_MASK, 0 },
351 { GDK_D, 0 }},
353 {KEY_FINC_FV, "finc_future_value",
354 { 0, 0 },
355 { GDK_v, 0 }},
357 {KEY_FINC_PMT, "finc_periodic_payment",
358 { GDK_SHIFT_MASK, 0 },
359 { GDK_P, 0 }},
361 {KEY_FINC_PV, "finc_present_value",
362 { 0, 0 },
363 { GDK_p, 0 }},
365 {KEY_FINC_RATE, "finc_periodic_interest_rate",
366 { GDK_SHIFT_MASK, 0 },
367 { GDK_T, 0 }},
369 {KEY_FINC_SLN, "finc_straight_line_depreciation",
370 { 0, 0 },
371 { GDK_l, 0 }},
373 {KEY_FINC_SYD, "finc_sum_of_the_years_digits_depreciation",
374 { 0, 0 },
375 { GDK_Y, 0 }},
377 {KEY_FINC_TERM, "finc_term",
378 { 0, 0 },
379 { GDK_T, 0 }},
381 #define NBUTTONS (sizeof(button_widgets) / sizeof(struct button_widget))
383 #define UI_FILE PACKAGE_GLADE_DIR "/gcalctool.glade"
385 #define MAXBITS 64 /* Bit panel: number of bit fields. */
387 #define GET_WIDGET(name) \
388 glade_xml_get_widget(X->ui, (name))
390 #define SET_MENUBAR_ITEM_STATE(name, state) \
391 g_object_set_data(G_OBJECT(GET_WIDGET(name)), "sensitive", \
392 GINT_TO_POINTER(state));
394 #define CONNECT_SIGNAL(name) glade_xml_signal_connect(X->ui, #name, \
395 G_CALLBACK(name))
397 struct Xobject { /* Gtk+/Xlib graphics object. */
398 GdkAtom clipboard_atom;
399 GdkAtom primary_atom;
401 GladeXML *ui;
403 GtkWidget *kframe; /* Main window. */
405 GtkTreeModel *constants_model;
406 GtkWidget *con_dialog; /* Edit constants dialog. */
408 GtkTreeModel *functions_model;
409 GtkWidget *fun_dialog; /* Edit functions dialog. */
410 GtkWidget *menubar; // FIXME: Why is this needed?
412 GtkWidget *bit_panel;
413 GtkWidget *bits[MAXBITS]; /* The 0/1 labels in the bit panel. */
415 GtkWidget *status_image; /* Statusbar image */
416 GtkWidget *statusbar;
418 GtkWidget *aframe; /* ASCII window. */
419 GtkWidget *aframe_ch;
421 GtkWidget *display_item; /* Calculator display. */
422 GtkTextBuffer *display_buffer; /* Buffer used in display */
423 GtkWidget *scrolledwindow; /* Scrolled window for display_item. */
425 GtkWidget *rframe; /* Register window. */
426 GtkWidget *regs[MAX_REGISTERS]; /* Memory registers. */
428 GtkWidget *spframe; /* Set Precision window. */
429 GtkWidget *precision_spin;
431 GtkWidget *buttons[NBUTTONS];
432 GtkWidget *digit_buttons[16];
433 GtkWidget *clear_buttons[2];
435 GtkWidget *bas_panel; /* Panel containing basic mode widgets. */
436 GtkWidget *adv_panel; /* Panel containing advanced mode widgets. */
437 GtkWidget *fin_panel; /* Panel containing financial mode widgets. */
438 GtkWidget *sci_panel; /* Panel containing scientific mode widgets. */
439 GtkWidget *mode_panel; /* Panel containing scientific mode widgets. */
441 /* Labels for popup menus */
442 GtkWidget *constant_menu_labels[MAX_CONSTANTS];
443 GtkWidget *function_menu_labels[MAX_FUNCTIONS];
444 GtkWidget *memory_store_labels[MAX_REGISTERS];
445 GtkWidget *memory_recall_labels[MAX_REGISTERS];
446 GtkWidget *memory_exchange_labels[MAX_REGISTERS];
448 /* Scientific mode widgets */
449 GtkWidget *hyperbolic_toggle; /* Hyperbolic mode. */
450 GtkWidget *inverse_toggle; /* Inverse mode. */
451 GtkWidget *base[MAXBASES]; /* Numeric base radio buttons. */
452 GtkWidget *disp[MAXDISPMODES]; /* Numeric display mode. */
453 GtkWidget *trig[MAXTRIGMODES]; /* Trigonometric mode. */
455 char *lnp; /* Localized numerical point (UTF8 format) */
457 gboolean warn_change_mode; /* Should we warn user when changing modes? */
458 gboolean bitcalculating_mode;
461 typedef struct Xobject *XVars;
463 enum {
464 COLUMN_NUMBER,
465 COLUMN_VALUE,
466 COLUMN_DESCRIPTION,
467 COLUMN_EDITABLE,
468 NUM_COLUMNS
471 static XVars X;
474 /* FIXME: Move this into display.c (reset_display) */
475 static void
476 reset_display(void)
478 struct exprm_state *e;
480 switch (v->syntax) {
481 case NPA:
482 v->noparens = 0;
483 MPstr_to_num("0", DEC, v->MPdisp_val);
484 show_display(v->MPdisp_val);
485 clear_undo_history();
486 break;
488 case EXPRS:
489 e = get_state();
490 MPstr_to_num("0", DEC, e->ans);
491 exp_del();
492 show_display(e->ans);
493 break;
495 default:
496 assert(0);
500 void
501 ui_set_syntax_mode(enum syntax mode)
503 GtkWidget *widget;
505 v->syntax = mode;
507 reset_display();
509 if (mode == NPA) {
510 ui_set_statusbar(_("Activated no operator precedence mode"), "");
511 } else {
512 ui_set_statusbar(
513 _("Activated expression mode with operator precedence"), "");
516 /* Save the syntax mode */
517 set_resource(R_SYNTAX, Rsstr[v->syntax]);
519 /* ??? */
520 ui_set_mode(v->modetype);
522 /* Update menu */
523 if (v->syntax == EXPRS) {
524 widget = GET_WIDGET("arithmetic_precedence_menu");
525 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget), TRUE);
526 } else {
527 widget = GET_WIDGET("ltr_precedence_menu");
528 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget), TRUE);
533 void
534 ui_set_accuracy(int accuracy)
536 GtkWidget *widget;
537 char text[MAXLINE];
538 char *desc, *current, *tooltip;
540 v->accuracy = accuracy;
542 SNPRINTF(text, MAXLINE, _("Other (%d) ..."), accuracy);
543 widget = gtk_bin_get_child(GTK_BIN(GET_WIDGET("acc_item_other")));
544 gtk_label_set_text(GTK_LABEL(widget), text);
546 desc = g_strdup_printf(ngettext("Set accuracy from 0 to %d numeric places.",
547 "Set accuracy from 0 to %d numeric places.",
548 MAXACC),
549 MAXACC);
551 /* Translator: This refers to the current accuracy setting */
552 current = g_strdup_printf(ngettext("Currently set to %d places.",
553 "Currently set to %d places.",
554 accuracy),
555 accuracy);
556 tooltip = g_strdup_printf ("%s %s [A]", desc, current);
557 gtk_widget_set_tooltip_text (GET_WIDGET("calc_accuracy_button"), tooltip);
558 g_free(desc);
559 g_free(current);
560 g_free(tooltip);
562 if (accuracy >= 0 && accuracy <= 9) {
563 SNPRINTF(text, MAXLINE, "acc_item%d", accuracy);
564 widget = GET_WIDGET(text);
565 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget), TRUE);
568 gtk_spin_button_set_value(GTK_SPIN_BUTTON(X->precision_spin),
569 (double)accuracy);
571 set_int_resource(R_ACCURACY, accuracy);
573 ui_make_registers();
574 refresh_display(-1);
576 /* Hide the manual dialog */
577 gtk_widget_hide(X->spframe);
581 static void
582 ui_update_trig_mode()
584 static char *sine_labels[] = {N_("Sin"), N_("Sinh"),
585 N_("Sin<sup>-1</sup>"),
586 N_("Sinh<sup>-1</sup>")};
587 static int sine_functions[] = {KEY_SIN, KEY_SINH, KEY_ASIN, KEY_ASINH};
588 static char *cosine_labels[] = {N_("Cos"), N_("Cosh"),
589 N_("Cos<sup>-1</sup>"),
590 N_("Cosh<sup>-1</sup>")};
591 static int cosine_functions[] = {KEY_COS, KEY_COSH, KEY_ACOS, KEY_ACOSH};
592 static char *tangent_labels[] = {N_("Tan"), N_("Tanh"),
593 N_("Tan<sup>-1</sup>"),
594 N_("Tanh<sup>-1</sup>")};
595 static int tangent_functions[] = {KEY_TAN, KEY_TANH, KEY_ATAN, KEY_ATANH};
596 int index = 0;
598 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(X->hyperbolic_toggle))) {
599 index |= 0x1;
601 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(X->inverse_toggle))) {
602 index |= 0x2;
605 gtk_label_set_markup(GTK_LABEL(GET_WIDGET("sine_label")),
606 sine_labels[index]);
607 g_object_set_data(G_OBJECT(GET_WIDGET("calc_sine_button")), "calc_function",
608 GINT_TO_POINTER(sine_functions[index]));
610 gtk_label_set_markup(GTK_LABEL(GET_WIDGET("cosine_label")),
611 cosine_labels[index]);
612 g_object_set_data(G_OBJECT(GET_WIDGET("calc_cosine_button")), "calc_function",
613 GINT_TO_POINTER(cosine_functions[index]));
615 gtk_label_set_markup(GTK_LABEL(GET_WIDGET("tangent_label")),
616 tangent_labels[index]);
617 g_object_set_data(G_OBJECT(GET_WIDGET("calc_tangent_button")), "calc_function",
618 GINT_TO_POINTER(tangent_functions[index]));
622 void
623 ui_set_hyperbolic_state(gboolean state)
625 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(X->hyperbolic_toggle), state);
626 ui_update_trig_mode();
630 void
631 ui_set_inverse_state(gboolean state)
633 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(X->inverse_toggle), state);
634 ui_update_trig_mode();
638 void
639 ui_set_trigonometric_mode(enum trig_type mode)
641 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(X->trig[mode]), 1);
645 void
646 ui_set_numeric_mode(enum base_type mode)
648 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(X->disp[mode]), 1);
652 void
653 ui_set_show_thousands_seperator(gboolean visible)
655 GtkWidget *menu;
657 v->show_tsep = visible;
658 set_boolean_resource(R_TSEP, v->show_tsep);
660 menu = GET_WIDGET("show_thousands_separator_menu");
661 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), visible);
663 syntaxdep_show_display();
664 ui_make_registers();
668 void
669 ui_set_show_bitcalculating(gboolean visible)
671 GtkWidget *menu;
673 X->bitcalculating_mode = visible;
674 ui_set_mode(v->modetype);
675 set_resource(R_BITCALC, Rcstr[visible ? 1 : 0]);
677 menu = GET_WIDGET("show_bitcalculating_menu");
678 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), visible);
682 void
683 ui_set_show_trailing_zeroes(gboolean visible)
685 GtkWidget *menu;
687 v->show_zeroes = visible;
688 set_boolean_resource(R_ZEROES, visible);
690 syntaxdep_show_display();
691 ui_make_registers();
693 menu = GET_WIDGET("show_trailing_zeroes_menu");
694 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), visible);
695 menu = GET_WIDGET("acc_trailing_zeroes_item");
696 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), visible);
700 void
701 ui_set_undo_enabled(gboolean undo, gboolean redo)
703 gtk_widget_set_sensitive(GET_WIDGET("undo_menu"), undo);
704 gtk_widget_set_sensitive(GET_WIDGET("redo_menu"), redo);
708 static char *
709 make_hostname()
711 Display *dpy = GDK_DISPLAY();
712 char client_hostname[MAXHOSTNAMELEN + 4];
713 char hostname[MAXHOSTNAMELEN];
714 char *display = DisplayString(dpy);
715 char *scanner = display;
717 GETHOSTNAME(hostname, MAXHOSTNAMELEN);
719 while (*scanner) {
720 scanner++;
723 while (*scanner != ':') {
724 scanner--;
727 *scanner = '\0';
729 if (strcmp(display, hostname) &&
730 strcmp(display, "localhost") &&
731 strcmp(display, "unix") &&
732 strcmp(display, "")) {
733 SPRINTF(client_hostname, " [%s] ", hostname);
734 } else {
735 STRCPY(client_hostname, "");
738 *scanner = ':';
740 if (client_hostname[0] == '\0')
741 return (NULL);
742 else
743 return (strdup(client_hostname));
747 void
748 ui_set_mode(enum mode_type mode)
750 GtkRequisition *r;
751 gint w, h;
752 char *hostname, title[MAXLINE];
753 GtkWidget *menu;
755 refresh_display(-1);
756 ui_make_registers();
758 /* Save mode */
759 set_resource(R_MODE, Rmstr[(int) v->modetype]);
761 /* Show/enable the widgets used in this mode */
762 g_object_set(G_OBJECT(X->bas_panel), "visible", mode == BASIC, NULL);
763 g_object_set(G_OBJECT(X->adv_panel), "visible", mode != BASIC, NULL);
764 g_object_set(G_OBJECT(X->fin_panel), "visible", mode == FINANCIAL, NULL);
765 g_object_set(G_OBJECT(X->mode_panel), "visible", mode == SCIENTIFIC, NULL);
766 g_object_set(G_OBJECT(X->sci_panel), "visible", mode == SCIENTIFIC, NULL);
767 g_object_set(G_OBJECT(X->bit_panel), "visible",
768 mode == SCIENTIFIC && X->bitcalculating_mode, NULL);
769 gtk_widget_set_sensitive(GET_WIDGET("show_bitcalculating_menu"),
770 mode == SCIENTIFIC);
771 gtk_widget_set_sensitive(GET_WIDGET("show_trailing_zeroes_menu"),
772 mode == SCIENTIFIC);
773 gtk_widget_set_sensitive(GET_WIDGET("show_registers_menu"),
774 mode != BASIC);
776 /* HACK: Some horrible hack down below to keep the buttons the same size.
777 * There must be a safer way of doing this... */
778 r = g_new0(GtkRequisition, 1);
779 gtk_widget_size_request(X->menubar, r);
780 w = r->width;
781 h = r->height;
782 gtk_widget_size_request(X->display_item, r);
783 w = MAX(w, r->width);
784 h += r->height;
786 if (GTK_WIDGET_VISIBLE(X->fin_panel)) {
787 gtk_widget_size_request(X->fin_panel, r);
788 w = MAX(w, r->width);
789 h += r->height;
792 if (GTK_WIDGET_VISIBLE(X->mode_panel)) {
793 gtk_widget_size_request(X->mode_panel, r);
794 w = MAX(w, r->width);
795 h += r->height;
798 if (GTK_WIDGET_VISIBLE(X->sci_panel)) {
799 gtk_widget_size_request(X->sci_panel, r);
800 w = MAX(w, r->width);
801 h += r->height;
803 g_free(r);
805 /* For initial display. */
806 gtk_window_set_default_size(GTK_WINDOW(X->kframe), w, h);
807 gtk_window_resize(GTK_WINDOW(X->kframe), w, h);
809 /* Set the title */
810 if((hostname = make_hostname())) {
811 SNPRINTF(title, MAXLINE, hostname_titles[mode], hostname);
812 g_free(hostname);
813 } else {
814 SNPRINTF(title, MAXLINE, titles[mode]);
816 gtk_window_set_title(GTK_WINDOW(X->kframe), title);
818 /* Update the menu */
819 switch (mode) {
820 case BASIC:
821 menu = GET_WIDGET("view_basic_menu");
822 break;
824 case ADVANCED:
825 menu = GET_WIDGET("view_advanced_menu");
826 break;
828 case FINANCIAL:
829 menu = GET_WIDGET("view_financial_menu");
830 break;
832 case SCIENTIFIC:
833 menu = GET_WIDGET("view_scientific_menu");
834 break;
836 default:
837 assert(FALSE);
838 return;
840 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), TRUE);
844 void
845 ui_set_statusbar(gchar *text, const gchar *imagename)
847 GtkImage *image = GTK_IMAGE(X->status_image);
849 assert(text);
850 assert(imagename);
851 assert(image);
853 gtk_image_set_from_stock(image, imagename, GTK_ICON_SIZE_BUTTON);
854 gtk_statusbar_pop(GTK_STATUSBAR(X->statusbar), 0);
855 gtk_statusbar_push(GTK_STATUSBAR(X->statusbar), 0, text);
859 static void
860 bin_str(int MP_value[MP_SIZE], char *str, int maxbits)
862 int i, MP0[MP_SIZE], MP1[MP_SIZE], MP2[MP_SIZE], MP3[MP_SIZE];
863 int neg = 0;
865 MPstr_to_num("0", DEC, MP0);
866 MPstr_to_num("1", DEC, MP1);
867 MPstr_to_num("2", DEC, MP2);
869 if (mplt(MP_value, MP0)) {
870 mpcmim(MP_value, MP0);
871 mpadd(MP0, MP1, MP0);
872 neg = 1;
873 } else {
874 mpcmim(MP_value, MP0);
877 for (i = 0; i < maxbits; i++) {
878 double lsb; /* Least significant bit. */
879 calc_and(MP3, MP0, MP1);
880 mpcmd(MP3, &lsb);
882 if (lsb == 0) {
883 str[maxbits - i -1] = (neg) ? '1' : '0';
884 } else {
885 str[maxbits - i -1] = (neg) ? '0' : '1';
888 mpdiv(MP0, MP2, MP3);
889 mpcmim(MP3, MP0);
892 return;
896 static void
897 set_bit_panel()
899 int bit_str_len, i, MP1[MP_SIZE], MP2[MP_SIZE];
900 int MP[MP_SIZE];
901 char str[64], label[3];
902 int ret = usable_num(MP);
904 switch (v->syntax) {
905 case NPA:
906 MPstr_to_num(v->display, v->base, MP1);
907 mpcmim(MP1, MP2);
908 if (mpeq(MP1, MP2)) {
909 char *bit_str, label[3], tmp[MAXLINE];
910 int toclear = (v->current == KEY_CLEAR_ENTRY)
911 ? TRUE : FALSE;
913 bit_str = make_fixed(MP1, tmp, BIN, MAXLINE, toclear);
914 bit_str_len = strlen(bit_str);
915 if (bit_str_len <= MAXBITS) {
916 gtk_widget_set_sensitive(X->bit_panel, TRUE);
918 STRCPY(label, " 0");
919 for (i = 0; i < MAXBITS; i++) {
920 label[1] = (i < bit_str_len) ? bit_str[bit_str_len-i-1] : '0';
921 gtk_label_set_text(GTK_LABEL(X->bits[MAXBITS - i - 1]), label);
924 return;
927 gtk_widget_set_sensitive(X->bit_panel, FALSE);
928 break;
930 case EXPRS:
931 if (ret || !is_integer(MP)) {
932 gtk_widget_set_sensitive(X->bit_panel, FALSE);
933 return;
935 bin_str(MP, str, 64);
936 gtk_widget_set_sensitive(X->bit_panel, TRUE);
938 STRCPY(label, " 0");
939 for (i = 0; i < 64; i++) {
940 label[1] = str[64 - i - 1];
941 gtk_label_set_text(GTK_LABEL(X->bits[64 - i - 1]), label);
943 break;
945 default:
946 assert(FALSE);
951 static void
952 scroll_right()
954 if (GTK_WIDGET_VISIBLE(
955 GTK_SCROLLED_WINDOW(X->scrolledwindow)->hscrollbar)) {
956 GtkAdjustment *set;
958 set = gtk_scrolled_window_get_hadjustment(
959 GTK_SCROLLED_WINDOW(X->scrolledwindow));
960 gtk_adjustment_set_value(set, set->upper);
961 gtk_scrolled_window_set_hadjustment(
962 GTK_SCROLLED_WINDOW(X->scrolledwindow), set);
967 void
968 ui_set_display(char *str, int cursor)
970 char localized[MAX_LOCALIZED];
971 GtkTextIter iter;
973 if (str == NULL || str[0] == '\0') {
974 str = " ";
975 } else {
976 if (v->noparens == 0) {
977 localize_number(localized, str);
978 str = localized;
981 gtk_text_buffer_set_text(X->display_buffer, str, -1);
983 if (cursor < 0) {
984 gtk_text_buffer_get_end_iter(X->display_buffer, &iter);
985 } else {
986 gtk_text_buffer_get_iter_at_offset(X->display_buffer, &iter, cursor);
988 gtk_text_buffer_place_cursor(X->display_buffer, &iter);
990 if (cursor < 0) {
991 scroll_right();
996 /* When an error condition occurs:
998 * - make insensitive all buttons except Clr.
999 * - make all Scientific mode toggles and checkboxes insensitive.
1000 * - make all menubar items insensitive except:
1001 * Calculator->Quit
1002 * Help->Contents
1004 * When the error condition is cleared, resensitise everything, setting
1005 * the numeric base buttons correctly.
1008 void
1009 ui_set_error_state(gboolean error)
1011 int i;
1013 v->error = error;
1015 for (i = 0; i < NBUTTONS; i++) {
1016 gtk_widget_set_sensitive(X->buttons[i], !v->error);
1018 /* Clr button always sensitive. */
1019 gtk_widget_set_sensitive(X->clear_buttons[0], TRUE);
1020 gtk_widget_set_sensitive(X->clear_buttons[1], TRUE);
1022 if (!v->error) {
1023 ui_set_base(v->base);
1026 gtk_widget_set_sensitive(X->mode_panel, !v->error);
1028 // FIXME: Isn't this missing a whole lot of widgets?
1029 SET_MENUBAR_ITEM_STATE("copy_menu", !v->error);
1030 SET_MENUBAR_ITEM_STATE("paste_menu", !v->error);
1031 SET_MENUBAR_ITEM_STATE("insert_ascii_menu", !v->error);
1032 SET_MENUBAR_ITEM_STATE("view_basic_menu", !v->error);
1033 SET_MENUBAR_ITEM_STATE("view_advanced_menu", !v->error);
1034 SET_MENUBAR_ITEM_STATE("view_financial_menu", !v->error);
1035 SET_MENUBAR_ITEM_STATE("view_scientific_menu", !v->error);
1036 SET_MENUBAR_ITEM_STATE("show_trailing_zeroes_menu",
1037 !v->error && (v->modetype == SCIENTIFIC));
1038 SET_MENUBAR_ITEM_STATE("show_thousands_separator_menu", !v->error);
1039 SET_MENUBAR_ITEM_STATE("show_registers_menu", !v->error);
1040 SET_MENUBAR_ITEM_STATE("arithmetic_precedence_menu", !v->error);
1041 SET_MENUBAR_ITEM_STATE("about_menu", !v->error);
1045 void
1046 ui_beep()
1048 gdk_beep();
1052 char *
1053 ui_get_localized_numeric_point(void)
1055 const char *decimal_point;
1057 decimal_point = localeconv()->decimal_point;
1059 return (g_locale_to_utf8(decimal_point, -1, NULL, NULL, NULL));
1063 void
1064 ui_set_base(enum base_type base)
1066 int i, baseval = basevals[(int) base];
1068 v->base = base;
1070 for (i = 0; i < 16; i++) {
1071 gtk_widget_set_sensitive(X->digit_buttons[i], i < baseval);
1073 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(X->base[base]), 1);
1077 void
1078 ui_set_registers_visible(gboolean visible)
1080 GtkWidget *menu;
1082 ui_make_registers();
1084 menu = GET_WIDGET("show_registers_menu");
1085 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), visible);
1087 gtk_widget_realize(X->rframe);
1089 if (visible) {
1090 if (gdk_window_is_visible(X->rframe->window)) {
1091 gdk_window_raise(X->rframe->window);
1092 return;
1094 ds_position_popup(X->kframe, X->rframe, DS_POPUP_ABOVE);
1095 gtk_widget_show(X->rframe);
1096 } else {
1097 gtk_widget_hide(X->rframe);
1100 set_boolean_resource(R_REGS, visible);
1104 gchar *
1105 ui_get_display(void)
1107 GtkTextIter start, end;
1108 gtk_text_buffer_get_bounds(X->display_buffer, &start, &end);
1109 return (gtk_text_buffer_get_text(X->display_buffer,
1110 &start,
1111 &end,
1112 FALSE));
1116 static int
1117 get_cursor(void)
1119 gint pos;
1120 g_object_get(G_OBJECT(X->display_buffer), "cursor-position", &pos, NULL);
1122 /* Convert the last position to -1 */
1123 if (pos == gtk_text_buffer_get_char_count(X->display_buffer)) {
1124 return (-1);
1125 } else {
1126 return (pos);
1131 /*ARGSUSED*/
1132 static void
1133 about_cb(GtkWidget *widget)
1135 const gchar *authors[] = {
1136 "Rich Burridge <rich.burridge@sun.com>",
1137 "Sami Pietila <sampie@ariana-dsl.utu.fi>",
1138 "Robert Ancell <robert.ancell@gmail.com>",
1139 NULL
1141 const gchar *documenters[] = {
1142 "Sun Microsystems",
1143 NULL
1145 const gchar *translator_credits = _("translator-credits");
1147 const char *license[] = {
1148 N_("Gcalctool is free software; you can redistribute it and/or modify\n"
1149 "it under the terms of the GNU General Public License as published by\n"
1150 "the Free Software Foundation; either version 2 of the License, or\n"
1151 "(at your option) any later version.\n"),
1152 N_("Gcalctool is distributed in the hope that it will be useful,\n"
1153 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1154 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
1155 "GNU General Public License for more details.\n"),
1156 N_("You should have received a copy of the GNU General Public License\n"
1157 "along with Gcalctool; if not, write to the Free Software Foundation, Inc.,\n"
1158 "51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA\n")
1161 char *license_trans = g_strconcat(_(license[0]), "\n",
1162 _(license[1]), "\n",
1163 _(license[2]), "\n",
1164 NULL);
1166 gtk_show_about_dialog(GTK_WINDOW(X->kframe),
1167 "name",_("Gcalctool"),
1168 "version", VERSION,
1169 "copyright", _("\xc2\xa9 1986-2007 The Gcalctool authors"),
1170 "license", license_trans,
1171 "comments", _("Calculator with financial and scientific modes."),
1172 "authors", authors,
1173 "documenters", documenters,
1174 "translator_credits", translator_credits,
1175 "logo-icon-name", "gnome-calculator",
1176 NULL);
1180 static void
1181 cell_edited_cb(GtkCellRendererText *cell, const gchar *path_string,
1182 const gchar *new_text, gpointer data)
1184 GtkTreeModel *model = (GtkTreeModel *) data;
1185 GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
1186 GtkTreeIter iter;
1187 gchar *old_text;
1188 gint *column;
1190 column = g_object_get_data(G_OBJECT(cell), "column");
1192 gtk_tree_model_get_iter(model, &iter, path);
1194 switch (GPOINTER_TO_INT(column)) {
1195 case COLUMN_VALUE:
1196 gtk_tree_model_get(model, &iter, column, &old_text, -1);
1197 g_free(old_text);
1198 gtk_list_store_set(GTK_LIST_STORE(model), &iter, column,
1199 g_strdup(new_text), -1);
1200 break;
1202 case COLUMN_DESCRIPTION:
1203 gtk_tree_model_get(model, &iter, column, &old_text, -1);
1204 g_free(old_text);
1205 gtk_list_store_set(GTK_LIST_STORE(model), &iter, column,
1206 g_strdup(new_text), -1);
1207 break;
1210 gtk_tree_path_free(path);
1214 static void
1215 add_cf_column(GtkTreeView *treeview, gchar *name, gint colno, gboolean editable)
1217 GtkCellRenderer *renderer;
1218 GtkTreeModel *model = gtk_tree_view_get_model(treeview);
1220 renderer = gtk_cell_renderer_text_new();
1221 if (editable) {
1222 g_signal_connect(G_OBJECT(renderer), "edited",
1223 G_CALLBACK(cell_edited_cb), model);
1225 g_object_set_data(G_OBJECT(renderer), "column", GINT_TO_POINTER(colno));
1227 if (editable) {
1228 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(treeview),
1229 -1, name, renderer,
1230 "text", colno,
1231 "editable", COLUMN_EDITABLE,
1232 NULL);
1233 } else {
1234 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(treeview),
1235 -1, name, renderer,
1236 "text", colno,
1237 NULL);
1242 /*ARGSUSED*/
1243 static void
1244 aframe_response_cb(GtkWidget *dialog, gint response_id)
1246 char *ch;
1247 int val;
1249 if (response_id == GTK_RESPONSE_OK) {
1250 ch = (char *) gtk_entry_get_text(GTK_ENTRY(X->aframe_ch));
1251 val = ch[0];
1252 mpcim(&val, v->MPdisp_val);
1253 show_display(v->MPdisp_val);
1256 gtk_widget_hide(dialog);
1260 static gboolean
1261 aframe_delete_cb(GtkWidget *dialog)
1263 aframe_response_cb(dialog, GTK_RESPONSE_CANCEL);
1264 return (TRUE);
1268 /*ARGSUSED*/
1269 static void
1270 aframe_activate_cb(GtkWidget *entry)
1272 aframe_response_cb(X->aframe, GTK_RESPONSE_OK);
1276 /*ARGSUSED*/
1277 static void
1278 rframe_response_cb(GtkWidget *dialog, int response_id)
1280 ui_set_registers_visible(FALSE);
1284 static gboolean
1285 rframe_delete_cb(GtkWidget *dialog)
1287 rframe_response_cb(dialog, GTK_RESPONSE_OK);
1288 return (TRUE);
1292 /*ARGSUSED*/
1293 void
1294 disp_cb(GtkWidget *widget)
1296 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1297 do_numtype((enum num_type) g_object_get_data(G_OBJECT(widget), "numeric_mode"));
1301 /*ARGSUSED*/
1302 void
1303 base_cb(GtkWidget *widget)
1305 enum base_type base;
1307 base = (enum base_type) g_object_get_data(G_OBJECT(widget),
1308 "base_mode");
1309 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
1310 do_base(base);
1315 static void do_button(int function, int arg)
1317 switch (v->syntax) {
1318 case NPA:
1319 process_item(&buttons[function], arg);
1320 set_bit_panel();
1321 if (v->new_input && v->dtype == FIX) {
1322 STRNCPY(v->fnum, v->display, MAX_DIGITS - 1);
1323 ui_set_display(v->fnum, -1);
1325 break;
1327 case EXPRS:
1328 do_expression(function, arg, get_cursor());
1329 set_bit_panel();
1330 break;
1332 default:
1333 assert(0);
1338 static void
1339 help_display(void)
1341 GError *error = NULL;
1342 char *command;
1343 const char *lang;
1344 char *uri = NULL;
1345 GdkScreen *gscreen;
1346 int i;
1348 const char * const * langs = g_get_language_names ();
1350 for (i = 0; langs[i]; i++) {
1351 lang = langs[i];
1352 if (strchr (lang, '.')) {
1353 continue;
1356 uri = g_build_filename(PACKAGE_DATA_DIR,
1357 "/gnome/help/gcalctool/",
1358 lang,
1359 "/gcalctool.xml",
1360 NULL);
1362 if (g_file_test (uri, G_FILE_TEST_EXISTS)) {
1363 break;
1367 command = g_strconcat ("gnome-open ghelp://", uri, NULL);
1368 gscreen = gdk_screen_get_default();
1369 gdk_spawn_command_line_on_screen (gscreen, command, &error);
1370 if (error) {
1371 GtkWidget *d;
1373 d = gtk_message_dialog_new(NULL,
1374 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1375 GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
1376 error->message);
1377 gtk_dialog_run(GTK_DIALOG(d));
1378 gtk_widget_destroy(d);
1379 g_error_free(error);
1380 error = NULL;
1383 g_free (command);
1384 g_free (uri);
1388 static void
1389 put_constant(int n, char *con_value, char *con_name)
1391 char key[MAXLINE];
1392 char *cstr = g_strdup(con_value);
1394 /* Constants are written out with no thousands seaparator and with a radix
1395 * character of ".".
1398 SNPRINTF(key, MAXLINE, "constant%1dvalue", n);
1399 set_resource(key, cstr);
1400 g_free(cstr);
1402 SNPRINTF(key, MAXLINE, "constant%1dname", n);
1403 set_resource(key, con_name);
1407 static void
1408 put_function(int n, char *fun_value, char *fun_name)
1410 char key[MAXLINE];
1412 SNPRINTF(key, MAXLINE, "function%1dvalue", n);
1413 set_resource(key, fun_value);
1415 SNPRINTF(key, MAXLINE, "function%1dname", n);
1416 set_resource(key, fun_name);
1420 /*ARGSUSED*/
1421 static void
1422 constant_menu_cb(GtkMenuItem *menu)
1424 int arg = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(menu), "constant_id"));
1425 do_button(KEY_CONSTANT, arg);
1429 /*ARGSUSED*/
1430 static void
1431 function_menu_cb(GtkMenuItem *menu)
1433 int arg = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(menu), "function_id"));
1434 do_button(KEY_FUNCTION, arg);
1438 /*ARGSUSED*/
1439 static void
1440 store_menu_cb(GtkMenuItem *menu)
1442 int arg = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(menu), "register_id"));
1443 do_button(KEY_STORE, arg);
1447 /*ARGSUSED*/
1448 static void
1449 recall_menu_cb(GtkMenuItem *menu)
1451 int arg = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(menu), "register_id"));
1452 do_button(KEY_RECALL, arg);
1456 /*ARGSUSED*/
1457 static void
1458 exchange_menu_cb(GtkMenuItem *menu)
1460 int arg = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(menu), "register_id"));
1461 do_button(KEY_EXCHANGE, arg);
1465 static void
1466 update_constants_menu(void)
1468 char mline[MAXLINE];
1469 int i;
1471 for (i = 0; i < MAX_CONSTANTS; i++) {
1472 SNPRINTF(mline, MAXLINE,
1473 "<span weight=\"bold\">%s_%1d:</span> %s [%s]", _("C"), i,
1474 make_number(v->MPcon_vals[i], DEC, TRUE),
1475 v->con_names[i]);
1476 gtk_label_set_markup_with_mnemonic(GTK_LABEL(X->constant_menu_labels[i]), mline);
1481 static void
1482 update_functions_menu(void)
1484 char mline[MAXLINE];
1485 int i;
1487 for (i = 0; i < MAX_FUNCTIONS; i++) {
1488 if (strlen(v->fun_vals[i]) != 0) {
1489 SNPRINTF(mline, MAXLINE,
1490 "<span weight=\"bold\">%s_%1d:</span> %s [%s]",
1491 _("F"), i, v->fun_vals[i], v->fun_names[i]);
1492 gtk_widget_show(gtk_widget_get_parent(X->function_menu_labels[i]));
1493 gtk_label_set_markup_with_mnemonic(GTK_LABEL(X->function_menu_labels[i]), mline);
1495 else
1496 gtk_widget_hide(gtk_widget_get_parent(X->function_menu_labels[i]));
1501 static void
1502 edit_constants_response_cb(GtkDialog *dialog, gint id)
1504 GtkTreeIter iter;
1505 gint number;
1506 gchar *value;
1507 gchar *description;
1509 if (id == GTK_RESPONSE_HELP) {
1510 help_display();
1513 if (id == GTK_RESPONSE_ACCEPT) {
1514 if (gtk_tree_model_get_iter_first(X->constants_model, &iter)) {
1515 do {
1516 gtk_tree_model_get(X->constants_model, &iter,
1517 COLUMN_NUMBER, &number,
1518 COLUMN_VALUE, &value,
1519 COLUMN_DESCRIPTION, &description, -1);
1520 MPstr_to_num(value, DEC, v->MPcon_vals[number]);
1521 STRNCPY(v->con_names[number], description, MAXLINE - 1);
1522 put_constant(number, value, description);
1523 } while (gtk_tree_model_iter_next(X->constants_model, &iter));
1527 gtk_widget_hide(GTK_WIDGET(dialog));
1531 static gboolean
1532 edit_constants_delete_cb(GtkDialog *dialog)
1534 edit_constants_response_cb(dialog, GTK_RESPONSE_CANCEL);
1535 return (TRUE);
1539 static void
1540 edit_functions_response_cb(GtkDialog *dialog, gint id)
1542 GtkTreeIter iter;
1543 gint number;
1544 gchar *value;
1545 gchar *description;
1547 if (id == GTK_RESPONSE_HELP) {
1548 help_display();
1551 if (id == GTK_RESPONSE_ACCEPT) {
1552 if (gtk_tree_model_get_iter_first(X->functions_model, &iter)) {
1553 do {
1554 gtk_tree_model_get(X->functions_model, &iter,
1555 COLUMN_NUMBER, &number,
1556 COLUMN_VALUE, &value,
1557 COLUMN_DESCRIPTION, &description, -1);
1558 STRNCPY(v->fun_vals[number], convert(value), MAXLINE - 1);
1559 STRNCPY(v->fun_names[number], description, MAXLINE - 1);
1560 put_function(number, value, description);
1561 } while (gtk_tree_model_iter_next(X->functions_model, &iter));
1565 gtk_widget_hide(GTK_WIDGET(dialog));
1569 static gboolean
1570 edit_functions_delete_cb(GtkDialog *dialog)
1572 edit_functions_response_cb(dialog, GTK_RESPONSE_CANCEL);
1573 return (TRUE);
1577 /*ARGSUSED*/
1578 static GtkTreeModel *
1579 create_constants_model()
1581 gint i = 0;
1582 GtkListStore *model;
1583 GtkTreeIter iter;
1585 model = gtk_list_store_new(NUM_COLUMNS, G_TYPE_INT, G_TYPE_STRING,
1586 G_TYPE_STRING, G_TYPE_BOOLEAN);
1587 for (i = 0; i < MAX_CONSTANTS; i++) {
1588 gtk_list_store_append(model, &iter);
1590 gtk_list_store_set(model, &iter,
1591 COLUMN_NUMBER, i,
1592 COLUMN_EDITABLE, TRUE,
1593 -1);
1596 return (GTK_TREE_MODEL(model));
1600 /*ARGSUSED*/
1601 static GtkTreeModel *
1602 create_functions_model()
1604 gint i = 0;
1605 GtkListStore *model;
1606 GtkTreeIter iter;
1608 model = gtk_list_store_new(NUM_COLUMNS, G_TYPE_INT, G_TYPE_STRING,
1609 G_TYPE_STRING, G_TYPE_BOOLEAN);
1610 for (i = 0; i < MAX_FUNCTIONS; i++) {
1611 gtk_list_store_append(model, &iter);
1613 gtk_list_store_set(model, &iter,
1614 COLUMN_NUMBER, i,
1615 COLUMN_EDITABLE, TRUE,
1616 -1);
1619 return (GTK_TREE_MODEL(model));
1623 void
1624 ui_make_registers() /* Calculate memory register frame values. */
1626 char *mval, key[MAXLINE];
1627 int n;
1629 for (n = 0; n < MAX_REGISTERS; n++) {
1630 mval = make_number(v->MPmvals[n], v->base, TRUE);
1631 gtk_entry_set_width_chars(GTK_ENTRY(X->regs[n]), strlen(mval));
1632 gtk_entry_set_text(GTK_ENTRY(X->regs[n]), mval);
1633 SNPRINTF(key, MAXLINE, "register%d", n);
1634 set_resource(key, mval);
1639 static void
1640 save_win_position()
1642 int x, y;
1644 (void) gdk_window_get_origin(X->kframe->window, &x, &y);
1645 set_int_resource(R_XPOS, x);
1646 set_int_resource(R_YPOS, y);
1650 static void
1651 change_mode(int mode)
1653 v->modetype = mode;
1655 ui_set_base(DEC);
1656 ui_set_numeric_mode(FIX);
1657 ui_set_accuracy(9);
1658 ui_set_show_thousands_seperator(FALSE);
1659 ui_set_show_trailing_zeroes(FALSE);
1660 ui_set_mode(v->modetype);
1662 /* Reset display */
1663 do_clear();
1667 static gboolean
1668 request_change_mode()
1670 GtkWidget *dialog, *request_check, *button;
1671 gint response;
1673 if (!X->warn_change_mode) {
1674 return (TRUE);
1677 dialog = gtk_message_dialog_new(GTK_WINDOW(X->kframe),
1678 GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
1679 GTK_MESSAGE_WARNING,
1680 GTK_BUTTONS_CANCEL,
1681 "%s",
1682 _("Changing Modes Clears Calculation"));
1683 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
1684 "%s",
1685 _("When you change modes, the current calculation "
1686 "will be cleared, and the base will be reset to "
1687 "decimal."));
1689 request_check = gtk_check_button_new_with_mnemonic(_("_Do not warn me again"));
1690 gtk_box_pack_end(GTK_BOX(GTK_DIALOG(dialog)->vbox),
1691 request_check, FALSE, FALSE, 0);
1693 button = gtk_dialog_add_button(GTK_DIALOG(dialog),
1694 _("C_hange Mode"), GTK_RESPONSE_ACCEPT);
1695 gtk_button_set_image(GTK_BUTTON(button),
1696 gtk_image_new_from_stock(GTK_STOCK_REFRESH,
1697 GTK_ICON_SIZE_BUTTON));
1698 /* Set default focus on affirmative button */
1699 gtk_widget_grab_focus(button);
1701 gtk_dialog_set_alternative_button_order(GTK_DIALOG(dialog),
1702 GTK_RESPONSE_ACCEPT,
1703 GTK_RESPONSE_CANCEL,
1704 -1);
1706 gtk_window_set_position(GTK_WINDOW(dialog),
1707 GTK_WIN_POS_CENTER_ON_PARENT);
1709 gtk_widget_show_all(dialog);
1710 response = gtk_dialog_run(GTK_DIALOG(dialog));
1712 // FIXME: Save this in GConf
1713 X->warn_change_mode = !gtk_toggle_button_get_active(
1714 GTK_TOGGLE_BUTTON(request_check));
1716 gtk_widget_destroy(dialog);
1718 return (response == GTK_RESPONSE_ACCEPT);
1722 /*ARGSUSED*/
1723 static gboolean
1724 bit_toggle_cb(GtkWidget *event_box, GdkEventButton *event)
1726 double number;
1727 unsigned long long lval;
1728 int n, MP1[MP_SIZE], index;
1730 index = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(event_box),
1731 "bit_index"));
1732 n = MAXBITS - index - 1;
1733 MPstr_to_num(v->display, v->base, MP1);
1734 mpcmd(MP1, &number);
1735 lval = (long long) number;
1737 if (lval & (1LL << n)) {
1738 lval &= ~(1LL << n);
1739 gtk_label_set_text(GTK_LABEL(X->bits[index]), " 0");
1740 } else {
1741 lval |= (1LL << n);
1742 gtk_label_set_text(GTK_LABEL(X->bits[index]), " 1");
1745 number = (double) lval;
1746 mpcdm(&number, v->MPdisp_val);
1747 show_display(v->MPdisp_val);
1748 v->toclear = 0;
1750 return (TRUE);
1754 static void
1755 menu_item_select_cb(GtkWidget *widget)
1757 GtkStatusbar *statusbar = GTK_STATUSBAR(X->statusbar);
1758 gchar *tooltip;
1759 guint context_id;
1761 context_id = gtk_statusbar_get_context_id(statusbar, "menuhelp");
1763 tooltip = (gchar *)g_object_get_data(G_OBJECT(widget), "tooltip");
1764 if (tooltip) {
1765 gtk_statusbar_push(statusbar, context_id, tooltip);
1770 /*ARGSUSED*/
1771 static void
1772 menu_item_deselect_cb(GtkWidget *widget)
1774 GtkStatusbar *statusbar = GTK_STATUSBAR(X->statusbar);
1775 guint context_id;
1777 context_id = gtk_statusbar_get_context_id(statusbar, "menuhelp");
1778 gtk_statusbar_pop(statusbar, context_id);
1782 static void
1783 set_menubar_tooltip(gchar *menu_name)
1785 GtkWidget *menu;
1786 gchar *tooltip;
1788 menu = GET_WIDGET(menu_name);
1789 tooltip = gtk_widget_get_tooltip_text(menu);
1790 g_object_set_data(G_OBJECT(menu), "tooltip", tooltip);
1791 gtk_widget_set_tooltip_text(menu, NULL);
1795 static void
1796 update_memory_menus()
1798 char mstr[MAXLINE];
1799 int i;
1801 for (i = 0; i < MAX_REGISTERS; i++) {
1802 SNPRINTF(mstr, MAXLINE, "<span weight=\"bold\">%s_%d:</span> %s",
1803 /* translators: R is the short form of register used inter alia
1804 in popup menus */
1805 _("R"), i, make_number(v->MPmvals[i], v->base, TRUE));
1806 gtk_label_set_markup_with_mnemonic(GTK_LABEL(X->memory_store_labels[i]), mstr);
1807 gtk_label_set_markup_with_mnemonic(GTK_LABEL(X->memory_recall_labels[i]), mstr);
1808 gtk_label_set_markup_with_mnemonic(GTK_LABEL(X->memory_exchange_labels[i]), mstr);
1813 static void
1814 get_constant(int n)
1816 char nkey[MAXLINE], *nline;
1817 char vkey[MAXLINE], *vline;
1819 SNPRINTF(nkey, MAXLINE, "constant%1dname", n);
1820 if ((nline = get_resource(nkey)) == NULL) {
1821 return;
1824 SNPRINTF(vkey, MAXLINE, "constant%1dvalue", n);
1825 if ((vline = get_resource(vkey)) == NULL) {
1826 return;
1829 MPstr_to_num(vline, DEC, v->MPcon_vals[n]);
1830 STRNCPY(v->con_names[n], nline, MAXLINE - 1);
1834 static void
1835 get_display() /* The Copy function key has been pressed. */
1837 gchar *string = NULL;
1838 GtkTextIter start, end;
1840 if (gtk_text_buffer_get_selection_bounds(X->display_buffer, &start, &end) == TRUE) {
1841 string = gtk_text_buffer_get_text(X->display_buffer, &start, &end, FALSE);
1842 } else {
1843 string = ui_get_display();
1846 if (v->shelf != NULL) {
1847 free(v->shelf);
1849 v->shelf = g_locale_from_utf8(string, strlen(string), NULL, NULL, NULL);
1850 g_free(string);
1852 gtk_clipboard_set_text(gtk_clipboard_get(X->clipboard_atom), v->shelf, -1);
1856 static void
1857 get_function(int n)
1859 char nkey[MAXLINE], *nline;
1860 char vkey[MAXLINE], *vline;
1862 SNPRINTF(nkey, MAXLINE, "function%1dname", n);
1863 if ((nline = get_resource(nkey)) == NULL) {
1864 return;
1867 SNPRINTF(vkey, MAXLINE, "function%1dvalue", n);
1868 if ((vline = get_resource(vkey)) == NULL) {
1869 return;
1872 STRNCPY(v->fun_vals[n], convert(vline), MAXLINE - 1);
1873 STRNCPY(v->fun_names[n], nline, MAXLINE - 1);
1877 static gboolean
1878 check_for_localized_numeric_point(int keyval)
1880 gchar outbuf[10]; /* Minumum size 6. */
1881 gunichar ch;
1883 ch = gdk_keyval_to_unicode(keyval);
1884 g_return_val_if_fail(g_unichar_validate(ch), FALSE);
1886 outbuf[g_unichar_to_utf8(ch, outbuf)] = '\0';
1888 return (strcmp(outbuf, X->lnp) == 0);
1892 /*ARGSUSED*/
1893 static void
1894 help_cb(GtkWidget *widget)
1896 help_display();
1900 /*ARGSUSED*/
1901 void
1902 hyp_cb(GtkWidget *widget)
1904 ui_update_trig_mode();
1908 /*ARGSUSED*/
1909 void
1910 inv_cb(GtkWidget *widget)
1912 ui_update_trig_mode();
1916 /*ARGSUSED*/
1917 static gboolean
1918 display_focus_out_cb(GtkWidget *widget)
1920 if (v->syntax == EXPRS) {
1921 exp_replace(ui_get_display());
1923 return (FALSE);
1927 /*ARGSUSED*/
1928 static gboolean
1929 display_focus_in_cb(GtkWidget *widget, GdkEventKey *event)
1931 v->ghost_zero = 0;
1932 return (FALSE);
1936 /*ARGSUSED*/
1937 static void
1938 menu_pos_func(GtkMenu *menu, gint *x, gint *y,
1939 gboolean *push_in, gpointer user_data)
1941 GdkPoint *loc = (GdkPoint *) user_data;
1943 *x = loc->x;
1944 *y = loc->y;
1948 /*ARGSUSED*/
1949 static void
1950 button_cb(GtkWidget *widget, GdkEventButton *event)
1952 int function;
1953 GtkWidget *menu;
1954 GdkPoint loc;
1956 function = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget),
1957 "calc_function"));
1958 menu = (GtkWidget *)g_object_get_data(G_OBJECT(widget), "calc_menu");
1960 if (menu == NULL) {
1961 do_button(function, 0);
1962 } else {
1963 /* If gcalctool is being driven by gok, the on-screen keyboard
1964 * assistive technology, it's possible that the event returned by
1965 * gtk_get_current_event() is NULL. If this is the case, we need
1966 * to fudge the popping up on the menu associated with this menu
1967 * button.
1970 update_constants_menu();
1971 update_functions_menu();
1972 update_memory_menus();
1974 if (event == NULL) {
1975 gdk_window_get_origin(widget->window, &loc.x, &loc.y);
1976 loc.x += widget->allocation.x;
1977 loc.y += widget->allocation.y;
1978 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, menu_pos_func,
1979 (gpointer) &loc, 0, gtk_get_current_event_time());
1980 } else if (event->button == 1) {
1981 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
1982 event->button, event->time);
1988 /*ARGSUSED*/
1989 static void
1990 select_display_entry(int offset)
1992 GtkTextIter iter;
1994 gtk_text_buffer_get_iter_at_offset(X->display_buffer, &iter, offset);
1995 gtk_text_buffer_place_cursor(X->display_buffer, &iter);
1996 gtk_widget_grab_focus(X->display_item);
2000 /*ARGSUSED*/
2001 static gboolean
2002 kframe_key_press_cb(GtkWidget *widget, GdkEventKey *event)
2004 int i, j, state;
2005 GtkWidget *button;
2007 if (check_for_localized_numeric_point(event->keyval) == TRUE) {
2008 event->state = 0;
2009 event->keyval = GDK_KP_Decimal;
2012 state = event->state & (GDK_CONTROL_MASK | GDK_MOD1_MASK);
2014 /* Accuracy shortcuts */
2015 if (state == GDK_CONTROL_MASK && v->modetype == SCIENTIFIC) {
2016 switch (event->keyval) {
2017 case GDK_0:
2018 do_accuracy(0);
2019 return (TRUE);
2020 case GDK_1:
2021 do_accuracy(1);
2022 return (TRUE);
2023 case GDK_2:
2024 do_accuracy(2);
2025 return (TRUE);
2026 case GDK_3:
2027 do_accuracy(3);
2028 return (TRUE);
2029 case GDK_4:
2030 do_accuracy(4);
2031 return (TRUE);
2032 case GDK_5:
2033 do_accuracy(5);
2034 return (TRUE);
2035 case GDK_6:
2036 do_accuracy(6);
2037 return (TRUE);
2038 case GDK_7:
2039 do_accuracy(7);
2040 return (TRUE);
2041 case GDK_8:
2042 do_accuracy(8);
2043 return (TRUE);
2044 case GDK_9:
2045 do_accuracy(9);
2046 return (TRUE);
2050 /* Connect home and end keys to move into the display entry */
2051 if (!gtk_widget_is_focus(X->display_item)) {
2052 if (event->keyval == GDK_Home) { /* || event->keyval == GDK_Left) { */
2053 select_display_entry(0);
2054 return (TRUE);
2055 } else if (event->keyval == GDK_End) { /* || event->keyval == GDK_Right) { */
2056 select_display_entry(-1);
2057 return (TRUE);
2061 for (i = 0; i < NBUTTONS; i++) {
2062 button = X->buttons[i];
2064 /* Check any parent widgets are visible */
2065 if (!GTK_WIDGET_VISIBLE(gtk_widget_get_parent(button)) ||
2066 !GTK_WIDGET_VISIBLE(button) || !GTK_WIDGET_IS_SENSITIVE(button)) {
2067 continue;
2070 j = 0;
2071 while (button_widgets[i].accelerator_keys[j] != 0) {
2072 if (button_widgets[i].accelerator_keys[j] == event->keyval &&
2073 (button_widgets[i].accelerator_mods[j] & ~GDK_SHIFT_MASK) == state) {
2074 button_cb(button, NULL);
2075 return (TRUE);
2077 j++;
2081 return (FALSE);
2085 /*ARGSUSED*/
2086 static void
2087 edit_cb(GtkWidget *widget)
2089 gboolean can_paste, can_copy;
2091 can_copy = gtk_text_buffer_get_has_selection(X->display_buffer);
2092 can_paste = gtk_clipboard_wait_is_text_available(
2093 gtk_clipboard_get(X->clipboard_atom));
2095 gtk_widget_set_sensitive(GET_WIDGET("copy_menu"), can_copy);
2096 gtk_widget_set_sensitive(GET_WIDGET("paste_menu"), can_paste);
2100 /*ARGSUSED*/
2101 static void
2102 copy_cb(GtkWidget *widget)
2104 get_display();
2108 /*ARGSUSED*/
2109 static void
2110 get_proc(GtkClipboard *clipboard, const gchar *buffer, gpointer data)
2112 int ret;
2113 gchar *dstp, *end_buffer, *srcp, *text, c;
2115 if (buffer == NULL) {
2116 return;
2119 end_buffer = (gchar *) (buffer + strlen(buffer));
2120 text = malloc(strlen(buffer)+1);
2122 dstp = text;
2123 for (srcp = (gchar *) buffer; srcp < end_buffer; srcp++) {
2124 /* If the clipboard buffer contains any occurances of the "thousands
2125 * separator", remove them.
2127 if (*srcp == v->tsep[0]) {
2128 if (strstr(srcp, v->tsep) == srcp) {
2129 srcp += strlen(v->tsep) - 1;
2130 continue;
2134 /* If an "A", "B", "C", "D" or "F" character is encountered, it
2135 * will be converted to its lowercase equivalent. If an "E" is
2136 * found, and the next character is a "-" or a "+", then it
2137 * remains as an upper case "E" (it's assumed to be a possible
2138 * exponential number), otherwise its converted to a lower case
2139 * "e". See bugs #455889 and #469245 for more details.
2141 switch (*srcp) {
2142 /* Replace tabs with spaces */
2143 case '\t':
2144 c = ' ';
2145 break;
2147 /* Terminate on newlines */
2148 case '\r':
2149 case '\n':
2150 c = '\0';
2151 break;
2153 case 'A':
2154 case 'B':
2155 case 'C':
2156 case 'D':
2157 case 'F':
2158 c = tolower(*srcp);
2159 break;
2161 case 'E':
2162 c = *srcp;
2163 if (srcp < (end_buffer-1)) {
2164 if (*(srcp+1) != '-' &&
2165 *(srcp+1) != '+') {
2166 c = tolower(*srcp);
2169 break;
2171 default:
2172 c = *srcp;
2173 break;
2176 *dstp++ = c;
2178 *dstp++ = '\0';
2180 switch (v->syntax) {
2181 case NPA:
2182 ret = lr_parse((char *) text, v->MPdisp_val);
2183 if (!ret) {
2184 show_display(v->MPdisp_val);
2185 } else {
2186 ui_set_statusbar(_("Clipboard contained malformed calculation"),
2187 "gtk-dialog-error");
2189 break;
2191 case EXPRS:
2192 exp_insert((char *) text, get_cursor()); // FIXME: Move out of gtk.c
2193 refresh_display(-1);
2194 break;
2196 default:
2197 assert(0);
2199 free(text);
2203 /*ARGSUSED*/
2204 static gboolean
2205 mouse_button_cb(GtkWidget *widget, GdkEventButton *event)
2207 if (event->button == 2) {
2208 gtk_clipboard_request_text(gtk_clipboard_get(X->primary_atom),
2209 get_proc, NULL);
2212 return (FALSE);
2216 /*ARGSUSED*/
2217 static void
2218 paste_cb(GtkWidget *widget)
2220 gtk_clipboard_request_text(gtk_clipboard_get(X->clipboard_atom),
2221 get_proc, NULL);
2225 /*ARGSUSED*/
2226 static void
2227 popup_paste_cb(GtkWidget *menu)
2229 paste_cb(menu);
2233 /*ARGSUSED*/
2234 static void
2235 undo_cb(GtkWidget *widget)
2237 perform_undo();
2241 /*ARGSUSED*/
2242 static void
2243 redo_cb(GtkWidget *widget)
2245 perform_redo();
2246 refresh_display(-1);
2250 /*ARGSUSED*/
2251 static void
2252 for_each_menu(GtkWidget *widget, gpointer data)
2254 /* Find the "Paste" entry and activate it (see bug #317786). */
2255 if (strcmp(G_OBJECT_TYPE_NAME(widget), "GtkImageMenuItem") == 0) {
2256 GtkWidget *label = gtk_bin_get_child(GTK_BIN(widget));
2258 if (strcmp(gtk_label_get_text(GTK_LABEL(label)), _("Paste")) == 0) {
2259 if (gtk_clipboard_wait_is_text_available(
2260 gtk_clipboard_get(X->clipboard_atom))) {
2261 gtk_widget_set_sensitive(GTK_WIDGET(widget), TRUE);
2262 g_signal_connect(GTK_OBJECT(widget), "activate",
2263 G_CALLBACK(popup_paste_cb), NULL);
2270 /*ARGSUSED*/
2271 static void
2272 buffer_populate_popup_cb(GtkTextView *textview, GtkMenu *menu)
2274 gtk_container_foreach(GTK_CONTAINER(menu), for_each_menu, NULL);
2278 /*ARGSUSED*/
2279 static void
2280 insert_ascii_cb(GtkWidget *widget)
2282 if (!GTK_WIDGET_VISIBLE(X->aframe)) {
2283 ds_position_popup(X->kframe, X->aframe, DS_POPUP_LEFT);
2285 gtk_window_set_focus(GTK_WINDOW(X->kframe), GTK_WIDGET(X->aframe_ch));
2286 gtk_widget_show(X->aframe);
2290 static void
2291 shift_cb(GtkWidget *widget)
2293 int count = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget),
2294 "shiftcount"));
2295 do_button(KEY_SHIFT, count);
2299 /*ARGSUSED*/
2300 static void
2301 show_bitcalculating_cb(GtkWidget *widget)
2303 gboolean visible;
2304 visible = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget));
2305 ui_set_show_bitcalculating(visible);
2309 /*ARGSUSED*/
2310 static void
2311 show_registers_cb(GtkWidget *widget)
2313 gboolean visible;
2314 visible = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget));
2315 ui_set_registers_visible(visible);
2319 static void
2320 arithmetic_mode_cb(GtkWidget *widget)
2322 enum syntax mode;
2323 mode = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget)) ? EXPRS : NPA;
2324 ui_set_syntax_mode(mode);
2328 /*ARGSUSED*/
2329 static void
2330 mode_radio_cb(GtkWidget *menu)
2332 int mode; /* The new mode. */
2334 if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menu))) {
2335 return;
2338 mode = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(menu), "calcmode"));
2340 /* If the user has completed a calculation and we are going to a
2341 * new mode that is "compatible" with this one, then just change
2342 * modes. Otherwise display a dialog warning the user that the
2343 * current calculation will be cleared.
2345 * Incompatible modes are:
2347 * Scientific -> Basic
2348 * Scientific -> Advanced
2349 * Scientific -> Financial
2351 * (unless we are in Scientific mode with Decimal numeric base and Fixed).
2353 if (display_is_result() &&
2354 ((v->modetype != SCIENTIFIC) ||
2355 (v->dtype == FIX && v->base == DEC))) {
2356 v->modetype = mode;
2357 ui_set_mode(v->modetype);
2358 } else {
2359 if (request_change_mode()) {
2360 change_mode(mode);
2366 /*ARGSUSED*/
2367 static void
2368 accuracy_radio_cb(GtkWidget *widget)
2370 int count;
2371 count = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "accuracy"));
2372 if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) {
2373 do_accuracy(count);
2378 /*ARGSUSED*/
2379 static void
2380 accuracy_other_cb(GtkWidget *widget)
2382 if (!GTK_WIDGET_VISIBLE(X->spframe)) {
2383 ds_position_popup(X->kframe, X->spframe, DS_POPUP_LEFT);
2385 gtk_window_set_focus(GTK_WINDOW(X->spframe), GTK_WIDGET(X->precision_spin));
2386 gtk_widget_show(X->spframe);
2390 /*ARGSUSED*/
2391 static void
2392 show_trailing_zeroes_cb(GtkWidget *widget)
2394 gboolean visible;
2395 visible = gtk_check_menu_item_get_active(
2396 GTK_CHECK_MENU_ITEM(widget));
2397 ui_set_show_trailing_zeroes(visible);
2401 /*ARGSUSED*/
2402 static void
2403 quit_cb(GtkWidget *widget)
2405 save_win_position();
2406 gtk_main_quit();
2410 static void
2411 spframe_response_cb(GtkWidget *dialog, gint response_id)
2413 int val;
2414 if (response_id == GTK_RESPONSE_OK) {
2415 val = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(X->precision_spin));
2416 ui_set_accuracy(val);
2419 gtk_widget_hide(dialog);
2423 static gboolean
2424 spframe_delete_cb(GtkWidget *dialog)
2426 spframe_response_cb(dialog, GTK_RESPONSE_CANCEL);
2427 return (TRUE);
2431 /*ARGSUSED*/
2432 static void
2433 spframe_activate_cb(GtkWidget *spin)
2435 spframe_response_cb(X->spframe, GTK_RESPONSE_OK);
2439 /*ARGSUSED*/
2440 void
2441 trig_cb(GtkWidget *widget)
2443 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
2444 do_trigtype((enum trig_type) g_object_get_data(G_OBJECT(widget),
2445 "trig_mode"));
2449 /*ARGSUSED*/
2450 static void
2451 show_thousands_separator_cb(GtkWidget *widget)
2453 gboolean visible;
2455 visible = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget));
2456 ui_set_show_thousands_seperator(visible);
2460 /*ARGSUSED*/
2461 static void
2462 edit_constants_cb(GtkMenuItem *item)
2464 gtk_widget_show(X->con_dialog);
2468 /*ARGSUSED*/
2469 static void
2470 edit_functions_cb(GtkMenuItem *item)
2472 gtk_widget_show(X->fun_dialog);
2476 static void
2477 set_win_position()
2479 int intval, screen_height, screen_width;
2480 int x = 0, y = 0;
2482 screen_width = gdk_screen_get_width(gdk_screen_get_default());
2483 screen_height = gdk_screen_get_height(gdk_screen_get_default());
2485 if (get_int_resource(R_XPOS, &intval)) {
2486 x = intval;
2487 if (x < 0 || x > screen_width) {
2488 x = 0;
2492 if (get_int_resource(R_YPOS, &intval)) {
2493 y = intval;
2494 if (y < 0 || y > screen_height) {
2495 y = 0;
2499 gtk_window_move(GTK_WINDOW(X->kframe), x, y);
2503 static void
2504 create_kframe()
2506 int i;
2507 char name[MAXLINE];
2508 GtkWidget *widget;
2509 PangoFontDescription *font_desc;
2510 GtkSizeGroup *size_group;
2511 GtkAccelGroup *accel_group;
2512 GtkWidget *treeview;
2514 X->ui = glade_xml_new(UI_FILE, NULL, NULL);
2515 if (X->ui == NULL) {
2516 GtkWidget *dialog;
2518 dialog = gtk_message_dialog_new(NULL, 0,
2519 GTK_MESSAGE_ERROR,
2520 GTK_BUTTONS_NONE,
2521 N_("Error loading user interface"));
2522 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
2523 N_("The user interace file %s is missing or unable to be loaded. Please check your installation."), UI_FILE);
2524 gtk_dialog_add_buttons(GTK_DIALOG(dialog), GTK_STOCK_QUIT, GTK_RESPONSE_ACCEPT, NULL);
2526 gtk_dialog_run(GTK_DIALOG(dialog));
2527 exit(0);
2530 /* When connecting up signals, would ideally use autoconnect but not
2531 * sure how to get the build process working.
2532 * See http://library.gnome.org/devel/libglade/unstable and
2533 * http://www.jamesh.id.au/software/libglade/
2534 * for some information on how to get this to work
2535 * glade_xml_signal_autoconnect(X->ui);
2537 CONNECT_SIGNAL(kframe_key_press_cb);
2538 CONNECT_SIGNAL(button_cb);
2539 CONNECT_SIGNAL(menu_item_select_cb);
2540 CONNECT_SIGNAL(menu_item_deselect_cb);
2541 CONNECT_SIGNAL(mode_radio_cb);
2542 CONNECT_SIGNAL(inv_cb);
2543 CONNECT_SIGNAL(hyp_cb);
2544 CONNECT_SIGNAL(trig_cb);
2545 CONNECT_SIGNAL(base_cb);
2546 CONNECT_SIGNAL(disp_cb);
2547 CONNECT_SIGNAL(quit_cb);
2548 CONNECT_SIGNAL(edit_cb);
2549 CONNECT_SIGNAL(copy_cb);
2550 CONNECT_SIGNAL(paste_cb);
2551 CONNECT_SIGNAL(insert_ascii_cb);
2552 CONNECT_SIGNAL(undo_cb);
2553 CONNECT_SIGNAL(redo_cb);
2554 CONNECT_SIGNAL(help_cb);
2555 CONNECT_SIGNAL(about_cb);
2556 CONNECT_SIGNAL(show_trailing_zeroes_cb);
2557 CONNECT_SIGNAL(show_thousands_separator_cb);
2558 CONNECT_SIGNAL(show_bitcalculating_cb);
2559 CONNECT_SIGNAL(show_registers_cb);
2560 CONNECT_SIGNAL(accuracy_radio_cb);
2561 CONNECT_SIGNAL(accuracy_other_cb);
2562 CONNECT_SIGNAL(constant_menu_cb);
2563 CONNECT_SIGNAL(function_menu_cb);
2564 CONNECT_SIGNAL(store_menu_cb);
2565 CONNECT_SIGNAL(recall_menu_cb);
2566 CONNECT_SIGNAL(exchange_menu_cb);
2567 CONNECT_SIGNAL(arithmetic_mode_cb);
2568 CONNECT_SIGNAL(mouse_button_cb);
2569 CONNECT_SIGNAL(display_focus_in_cb);
2570 CONNECT_SIGNAL(display_focus_out_cb);
2571 /* Detect when populating the right-click menu to enable pasting */
2572 CONNECT_SIGNAL(buffer_populate_popup_cb);
2573 CONNECT_SIGNAL(shift_cb);
2574 CONNECT_SIGNAL(bit_toggle_cb);
2575 CONNECT_SIGNAL(aframe_delete_cb);
2576 CONNECT_SIGNAL(aframe_activate_cb);
2577 CONNECT_SIGNAL(aframe_response_cb);
2578 CONNECT_SIGNAL(spframe_delete_cb);
2579 CONNECT_SIGNAL(spframe_activate_cb);
2580 CONNECT_SIGNAL(spframe_response_cb);
2581 CONNECT_SIGNAL(rframe_delete_cb);
2582 CONNECT_SIGNAL(rframe_response_cb);
2583 CONNECT_SIGNAL(edit_constants_cb);
2584 CONNECT_SIGNAL(edit_functions_cb);
2585 CONNECT_SIGNAL(edit_constants_delete_cb);
2586 CONNECT_SIGNAL(edit_constants_response_cb);
2587 CONNECT_SIGNAL(edit_constants_delete_cb);
2588 CONNECT_SIGNAL(edit_functions_response_cb);
2589 CONNECT_SIGNAL(edit_functions_delete_cb);
2591 X->clipboard_atom = gdk_atom_intern("CLIPBOARD", FALSE);
2592 X->primary_atom = gdk_atom_intern("PRIMARY", FALSE);
2593 X->kframe = GET_WIDGET("calc_window");
2594 X->aframe = GET_WIDGET("ascii_dialog");
2595 X->aframe_ch = GET_WIDGET("ascii_entry");
2596 X->spframe = GET_WIDGET("precision_dialog");
2597 X->precision_spin = GET_WIDGET("spframe_spin");
2598 X->rframe = GET_WIDGET("register_dialog");
2599 X->con_dialog = GET_WIDGET("edit_constants_dialog");
2600 X->fun_dialog = GET_WIDGET("edit_functions_dialog");
2601 X->menubar = GET_WIDGET("menubar");
2602 X->scrolledwindow = GET_WIDGET("display_scroll"),
2603 X->display_item = GET_WIDGET("displayitem"),
2604 X->bas_panel = GET_WIDGET("basic_panel");
2605 X->sci_panel = GET_WIDGET("scientific_panel");
2606 X->adv_panel = GET_WIDGET("advanced_panel");
2607 X->fin_panel = GET_WIDGET("financial_panel");
2608 X->bit_panel = GET_WIDGET("bit_panel");
2609 X->clear_buttons[0] = GET_WIDGET("calc_clear_simple_button");
2610 X->clear_buttons[1] = GET_WIDGET("calc_clear_advanced_button");
2611 X->mode_panel = GET_WIDGET("mode_panel");
2612 X->trig[0] = GET_WIDGET("degrees_radio");
2613 X->trig[1] = GET_WIDGET("gradians_radio");
2614 X->trig[2] = GET_WIDGET("radians_radio");
2615 X->base[0] = GET_WIDGET("binary_radio");
2616 X->base[1] = GET_WIDGET("octal_radio");
2617 X->base[2] = GET_WIDGET("decimal_radio");
2618 X->base[3] = GET_WIDGET("hexadecimal_radio");
2619 X->disp[0] = GET_WIDGET("engineering_radio");
2620 X->disp[1] = GET_WIDGET("fixed_point_radio");
2621 X->disp[2] = GET_WIDGET("scientific_radio");
2622 X->inverse_toggle = GET_WIDGET("inverse_check");
2623 X->hyperbolic_toggle = GET_WIDGET("hyperbolic_check");
2624 X->statusbar = GET_WIDGET("statusbar");
2625 for (i = 0; i < 16; i++) {
2626 SNPRINTF(name, MAXLINE, "calc_%x_button", i);
2627 X->digit_buttons[i] = GET_WIDGET(name);
2629 for (i = 0; i < MAX_REGISTERS; i++) {
2630 SNPRINTF(name, MAXLINE, "register_entry_%d", i);
2631 X->regs[i] = GET_WIDGET(name);
2634 /* Load buttons and set them all to be the same size */
2635 size_group = gtk_size_group_new(GTK_SIZE_GROUP_BOTH);
2636 for (i = 0; i < NBUTTONS; i++) {
2637 SNPRINTF(name, MAXLINE, "calc_%s_button",
2638 button_widgets[i].widget_name);
2639 X->buttons[i] = GET_WIDGET(name);
2640 assert(X->buttons[i] != NULL);
2642 gtk_size_group_add_widget(size_group, X->buttons[i]);
2644 g_object_set_data(G_OBJECT(X->buttons[i]), "calc_function",
2645 GINT_TO_POINTER(button_widgets[i].key));
2648 /* Make popup buttons */
2649 g_object_set_data(G_OBJECT(GET_WIDGET("calc_accuracy_button")),
2650 "calc_menu", GET_WIDGET("accuracy_popup"));
2651 g_object_set_data(G_OBJECT(GET_WIDGET("calc_shift_left_button")),
2652 "calc_menu", GET_WIDGET("left_shift_popup"));
2653 g_object_set_data(G_OBJECT(GET_WIDGET("calc_shift_right_button")),
2654 "calc_menu", GET_WIDGET("right_shift_popup"));
2656 g_object_set_data(G_OBJECT(GET_WIDGET("calc_constants_button")),
2657 "calc_menu", GET_WIDGET("constants_popup"));
2658 for (i = 0; i < MAX_CONSTANTS; i++) {
2659 SNPRINTF(name, MAXLINE, "constant_menu_item%d", i);
2660 widget = GET_WIDGET(name);
2661 g_object_set_data(G_OBJECT(widget), "constant_id", GINT_TO_POINTER(i));
2662 X->constant_menu_labels[i] = gtk_bin_get_child(GTK_BIN(widget));
2665 g_object_set_data(G_OBJECT(GET_WIDGET("calc_functions_button")),
2666 "calc_menu", GET_WIDGET("functions_popup"));
2667 for (i = 0; i < MAX_FUNCTIONS; i++) {
2668 SNPRINTF(name, MAXLINE, "function_menu_item%d", i);
2669 widget = GET_WIDGET(name);
2670 g_object_set_data(G_OBJECT(widget), "function_id", GINT_TO_POINTER(i));
2671 X->function_menu_labels[i] = gtk_bin_get_child(GTK_BIN(widget));
2674 g_object_set_data(G_OBJECT(GET_WIDGET("calc_store_button")),
2675 "calc_menu", GET_WIDGET("memory_store_popup"));
2676 g_object_set_data(G_OBJECT(GET_WIDGET("calc_recall_button")),
2677 "calc_menu", GET_WIDGET("memory_recall_popup"));
2678 g_object_set_data(G_OBJECT(GET_WIDGET("calc_exchange_button")),
2679 "calc_menu", GET_WIDGET("memory_exchange_popup"));
2680 for (i = 0; i < MAX_REGISTERS; i++) {
2681 SNPRINTF(name, MAXLINE, "store_menu_item%d", i);
2682 widget = GET_WIDGET(name);
2683 g_object_set_data(G_OBJECT(widget), "register_id", GINT_TO_POINTER(i));
2684 X->memory_store_labels[i] = gtk_bin_get_child(GTK_BIN(widget));
2686 SNPRINTF(name, MAXLINE, "recall_menu_item%d", i);
2687 widget = GET_WIDGET(name);
2688 g_object_set_data(G_OBJECT(widget), "register_id", GINT_TO_POINTER(i));
2689 X->memory_recall_labels[i] = gtk_bin_get_child(GTK_BIN(widget));
2691 SNPRINTF(name, MAXLINE, "exchange_menu_item%d", i);
2692 widget = GET_WIDGET(name);
2693 g_object_set_data(G_OBJECT(widget), "register_id", GINT_TO_POINTER(i));
2694 X->memory_exchange_labels[i] = gtk_bin_get_child(GTK_BIN(widget));
2697 /* Load bit panel */
2698 for (i = 0; i < MAXBITS; i++)
2700 SNPRINTF(name, MAXLINE, "bit_label_%d", i);
2701 X->bits[i] = GET_WIDGET(name);
2702 SNPRINTF(name, MAXLINE, "bit_eventbox_%d", i);
2703 g_object_set_data(G_OBJECT(GET_WIDGET(name)),
2704 "bit_index", GINT_TO_POINTER(i));
2707 /* Make menu tooltips displayed in the status bar */
2708 set_menubar_tooltip("quit_menu");
2709 set_menubar_tooltip("copy_menu");
2710 set_menubar_tooltip("paste_menu");
2711 set_menubar_tooltip("insert_ascii_menu");
2712 set_menubar_tooltip("undo_menu");
2713 set_menubar_tooltip("redo_menu");
2714 set_menubar_tooltip("view_basic_menu");
2715 set_menubar_tooltip("view_advanced_menu");
2716 set_menubar_tooltip("view_financial_menu");
2717 set_menubar_tooltip("view_scientific_menu");
2718 set_menubar_tooltip("show_trailing_zeroes_menu");
2719 set_menubar_tooltip("show_thousands_separator_menu");
2720 set_menubar_tooltip("show_bitcalculating_menu");
2721 set_menubar_tooltip("show_registers_menu");
2722 set_menubar_tooltip("ltr_precedence_menu");
2723 set_menubar_tooltip("arithmetic_precedence_menu");
2724 set_menubar_tooltip("help_menu");
2725 set_menubar_tooltip("about_menu");
2727 // ???
2728 widget = GET_WIDGET("kvbox");
2729 gtk_widget_set_direction(widget, GTK_TEXT_DIR_LTR);
2730 gtk_widget_set_direction(X->fin_panel, GTK_TEXT_DIR_LTR);
2732 /* Make dialogs transient of the main window */
2733 gtk_window_set_transient_for(GTK_WINDOW(X->aframe), GTK_WINDOW(X->kframe));
2734 gtk_window_set_transient_for(GTK_WINDOW(X->spframe), GTK_WINDOW(X->kframe));
2735 gtk_window_set_transient_for(GTK_WINDOW(X->rframe), GTK_WINDOW(X->kframe));
2736 gtk_window_set_transient_for(GTK_WINDOW(X->con_dialog),
2737 GTK_WINDOW(X->kframe));
2739 /* Can't set max length for spin buttons in Glade 2 */
2740 gtk_entry_set_max_length(GTK_ENTRY(X->precision_spin), 2);
2742 gtk_dialog_set_default_response(GTK_DIALOG(X->con_dialog),
2743 GTK_RESPONSE_ACCEPT);
2745 /* Make constant tree model */
2746 X->constants_model = create_constants_model();
2747 treeview = GET_WIDGET("edit_constants_treeview");
2748 gtk_tree_view_set_model(GTK_TREE_VIEW(treeview), X->constants_model);
2749 gtk_tree_selection_set_mode(
2750 gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)),
2751 GTK_SELECTION_SINGLE);
2752 add_cf_column(GTK_TREE_VIEW(treeview), _("No."),
2753 COLUMN_NUMBER, FALSE);
2754 add_cf_column(GTK_TREE_VIEW(treeview), _("Value"),
2755 COLUMN_VALUE, TRUE);
2756 add_cf_column(GTK_TREE_VIEW(treeview), _("Description"),
2757 COLUMN_DESCRIPTION, TRUE);
2759 /* Make function tree model */
2760 X->functions_model = create_functions_model();
2761 treeview = GET_WIDGET("edit_functions_treeview");
2762 gtk_dialog_set_default_response(GTK_DIALOG(X->fun_dialog),
2763 GTK_RESPONSE_ACCEPT);
2764 gtk_window_set_transient_for(GTK_WINDOW(X->fun_dialog),
2765 GTK_WINDOW(X->kframe));
2766 gtk_tree_view_set_model(GTK_TREE_VIEW(treeview), X->functions_model);
2767 gtk_tree_selection_set_mode(
2768 gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)),
2769 GTK_SELECTION_SINGLE);
2770 add_cf_column(GTK_TREE_VIEW(treeview), _("No."),
2771 COLUMN_NUMBER, FALSE);
2772 add_cf_column(GTK_TREE_VIEW(treeview), _("Value"),
2773 COLUMN_VALUE, TRUE);
2774 add_cf_column(GTK_TREE_VIEW(treeview), _("Description"),
2775 COLUMN_DESCRIPTION, TRUE);
2778 X->display_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(X->display_item));
2779 gtk_widget_ensure_style(X->display_item);
2780 font_desc = pango_font_description_copy(X->display_item->style->font_desc);
2781 pango_font_description_set_size(font_desc, 16 * PANGO_SCALE);
2782 gtk_widget_modify_font(X->display_item, font_desc);
2783 pango_font_description_free(font_desc);
2784 gtk_widget_set_name(X->display_item, "displayitem");
2785 atk_object_set_role(gtk_widget_get_accessible(X->display_item),
2786 ATK_ROLE_EDITBAR);
2788 gtk_widget_realize(X->kframe);
2789 set_win_position();
2791 for (i = 0; i < 3; i++)
2792 g_object_set_data(G_OBJECT(X->trig[i]),
2793 "trig_mode", GINT_TO_POINTER(i));
2794 for (i = 0; i < 4; i++)
2795 g_object_set_data(G_OBJECT(X->base[i]),
2796 "base_mode", GINT_TO_POINTER(i));
2797 for (i = 0; i < 3; i++)
2798 g_object_set_data(G_OBJECT(X->disp[i]),
2799 "numeric_mode", GINT_TO_POINTER(i));
2801 /* Put status image into statusbar (glade doesn't support child widgets
2802 * in statusbars) */
2803 X->status_image = gtk_image_new_from_stock("", GTK_ICON_SIZE_BUTTON);
2804 gtk_widget_show(X->status_image);
2805 gtk_box_pack_start(GTK_BOX(X->statusbar), X->status_image, FALSE, TRUE, 0);
2807 /* Set modes for menu items */
2808 for (i = 1; i < 16; i++) {
2809 SNPRINTF(name, MAXLINE, "shift_left%d_menu", i);
2810 g_object_set_data(G_OBJECT(GET_WIDGET(name)),
2811 "shiftcount", GINT_TO_POINTER(i));
2812 SNPRINTF(name, MAXLINE, "shift_right%d_menu", i);
2813 g_object_set_data(G_OBJECT(GET_WIDGET(name)),
2814 "shiftcount", GINT_TO_POINTER(-i));
2816 g_object_set_data(G_OBJECT(GET_WIDGET("view_basic_menu")),
2817 "calcmode", GINT_TO_POINTER(BASIC));
2818 g_object_set_data(G_OBJECT(GET_WIDGET("view_advanced_menu")),
2819 "calcmode", GINT_TO_POINTER(ADVANCED));
2820 g_object_set_data(G_OBJECT(GET_WIDGET("view_financial_menu")),
2821 "calcmode", GINT_TO_POINTER(FINANCIAL));
2822 g_object_set_data(G_OBJECT(GET_WIDGET("view_scientific_menu")),
2823 "calcmode", GINT_TO_POINTER(SCIENTIFIC));
2825 /* Make shortcuts for accuracy menus */
2826 accel_group = gtk_accel_group_new();
2827 gtk_window_add_accel_group(GTK_WINDOW(X->kframe), accel_group);
2828 for (i = 0; i < 10; i++) {
2829 SNPRINTF(name, MAXLINE, "acc_item%d", i);
2830 widget = GET_WIDGET(name);
2831 g_object_set_data(G_OBJECT(widget), "accuracy", GINT_TO_POINTER(i));
2836 static void
2837 read_cfdefs() /* Read constant/function definitions. */
2839 int n;
2841 for (n = 0; n < MAX_CONSTANTS; n++) {
2842 get_constant(n);
2844 for (n = 0; n < MAX_FUNCTIONS; n++) {
2845 STRCPY(v->fun_vals[n], ""); /* Initially empty function strings. */
2846 get_function(n);
2851 void
2852 ui_init(int *argc, char ***argv)
2854 X = (XVars) LINT_CAST(calloc(1, sizeof(struct Xobject)));
2856 gtk_init(argc, argv);
2858 X->lnp = ui_get_localized_numeric_point();
2860 gtk_rc_get_default_files();
2862 v->home = (char *) g_get_home_dir();
2863 gtk_rc_parse(g_build_path(v->home, RCNAME, NULL));
2865 gtk_window_set_default_icon_name("gnome-calculator");
2869 void
2870 ui_load()
2872 int boolval;
2873 char *resource;
2874 gboolean show_bit;
2876 read_cfdefs();
2878 /* Create main gcalctool window. */
2879 create_kframe();
2881 /* Load configuration */
2882 resource = get_resource(R_BITCALC);
2883 show_bit = resource != NULL && strcmp(resource, Rcstr[0]) != 0;
2885 ui_set_show_thousands_seperator(v->show_tsep);
2886 ui_set_show_trailing_zeroes(v->show_zeroes);
2887 ui_set_show_bitcalculating(show_bit);
2889 ui_set_syntax_mode(v->syntax);
2890 ui_set_mode(v->modetype);
2891 ui_set_numeric_mode(FIX);
2892 ui_set_base(v->base);
2893 ui_set_accuracy(v->accuracy);
2894 ui_set_undo_enabled(FALSE, FALSE);
2895 ui_update_trig_mode();
2897 /* Show the memory register window? */
2898 ui_make_registers();
2899 if (get_boolean_resource(R_REGS, &boolval))
2900 ui_set_registers_visible(boolval);
2902 /* Focus on the clear button */
2903 if (v->modetype == BASIC) {
2904 gtk_window_set_focus(GTK_WINDOW(X->kframe),
2905 GTK_WIDGET(X->clear_buttons[0]));
2906 } else {
2907 gtk_window_set_focus(GTK_WINDOW(X->kframe),
2908 GTK_WIDGET(X->clear_buttons[1]));
2912 void
2913 ui_start()
2915 X->warn_change_mode = TRUE; // FIXME: Load from GConf
2917 ui_set_base(v->base);
2918 ui_set_trigonometric_mode(v->ttype);
2919 ui_set_numeric_mode(v->dtype);
2921 gtk_widget_show(X->kframe);
2923 /* Init expression mode.
2924 * This must be executed after do_base is called at init.
2926 reset_display();
2928 gtk_main();