more ui tidyup
[gcalctool.git] / gcalctool / gtk.c
blob9639ad35b227fea76988a3378d11f9fdea9d31de
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 /* This table shows the keyboard values that are currently being used:
67 * | 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
68 *-----------+-----------------------------------------------------
69 * Lower: | a b c d e f i l m n p r s t u v x
70 * Upper: | A C D E F G J K L M N P R S T X Y
71 * Numeric: | 0 1 2 3 4 5 6 7 8 9
72 * Other: | @ . + - * / = % ( ) # < > [ ] { } | & ~ ^ ? ! :
73 * | BackSpace Delete Return
74 *-----------+-----------------------------------------------------
77 static struct button_widget button_widgets[] = {
78 {KEY_0, "0",
79 { 0, GDK_SHIFT_MASK, 0, 0, 0 },
80 { GDK_0, GDK_0, GDK_KP_0, GDK_KP_Insert, 0 }},
82 {KEY_1, "1",
83 { 0, GDK_SHIFT_MASK, 0, 0, 0, 0 },
84 { GDK_1, GDK_1, GDK_KP_1, GDK_KP_End, GDK_R13, 0 }},
86 {KEY_2, "2",
87 { 0, GDK_SHIFT_MASK, 0, 0, 0 },
88 { GDK_2, GDK_2, GDK_KP_2, GDK_KP_Down, 0 }},
90 {KEY_3, "3",
91 { 0, GDK_SHIFT_MASK, 0, 0, 0, 0 },
92 { GDK_3, GDK_3, GDK_KP_3, GDK_KP_Page_Down, GDK_R15, 0 }},
94 {KEY_4, "4",
95 { 0, GDK_SHIFT_MASK, 0, 0, 0 },
96 { GDK_4, GDK_4, GDK_KP_4, GDK_KP_Left, 0 }},
98 {KEY_5, "5",
99 { 0, GDK_SHIFT_MASK, 0, 0, 0, 0 },
100 { GDK_5, GDK_5, GDK_KP_5, GDK_KP_Begin, GDK_R11, 0 }},
102 {KEY_6, "6",
103 { 0, GDK_SHIFT_MASK, 0, 0, 0 },
104 { GDK_6, GDK_6, GDK_KP_6, GDK_KP_Right, 0 }},
106 {KEY_7, "7",
107 { 0, GDK_SHIFT_MASK, 0, 0, 0, 0 },
108 { GDK_7, GDK_7, GDK_KP_7, GDK_KP_Home, GDK_R7, 0 }},
110 {KEY_8, "8",
111 { 0, GDK_SHIFT_MASK, 0, 0, 0 },
112 { GDK_8, GDK_8, GDK_KP_8, GDK_KP_Up, 0 }},
114 {KEY_9, "9",
115 { 0, GDK_SHIFT_MASK, 0, 0, 0, 0 },
116 { GDK_9, GDK_9, GDK_KP_9, GDK_KP_Page_Up, GDK_R9, 0 }},
118 {KEY_A, "a",
119 { 0, 0 },
120 { GDK_a, 0 }},
122 {KEY_B, "b",
123 { 0, 0 },
124 { GDK_b, 0 }},
126 {KEY_C, "c",
127 { 0, 0 },
128 { GDK_c, 0 }},
130 {KEY_D, "d",
131 { 0, 0 },
132 { GDK_d, 0 }},
134 {KEY_E, "e",
135 { 0, 0 },
136 { GDK_e, 0 }},
138 {KEY_F, "f",
139 { 0, 0 },
140 { GDK_f, 0 }},
142 {KEY_CLEAR, "clear_simple",
143 { 0, 0 },
144 { GDK_Delete, 0 }},
146 {KEY_CLEAR, "clear_advanced",
147 { 0, 0 },
148 { GDK_Delete, 0 }},
150 {KEY_SHIFT, "shift_left",
151 { GDK_SHIFT_MASK, 0 },
152 { GDK_less, 0 }},
154 {KEY_SHIFT, "shift_right",
155 { GDK_SHIFT_MASK, 0 },
156 { GDK_greater, 0 }},
158 {KEY_SET_ACCURACY, "accuracy",
159 { GDK_SHIFT_MASK, 0 },
160 { GDK_A, 0 }},
162 {KEY_CONSTANT, "constants",
163 { GDK_SHIFT_MASK, 0, 0 },
164 { GDK_numbersign, GDK_numbersign, 0 }},
166 {KEY_FUNCTION, "functions",
167 { GDK_SHIFT_MASK, 0 },
168 { GDK_F, 0 }},
170 {KEY_STORE, "store",
171 { GDK_SHIFT_MASK, 0 },
172 { GDK_S, 0 }},
174 {KEY_RECALL, "recall",
175 { GDK_SHIFT_MASK, 0 },
176 { GDK_R, 0 }},
178 {KEY_EXCHANGE, "exchange",
179 { GDK_SHIFT_MASK, 0 },
180 { GDK_X, 0 }},
182 {KEY_CLEAR_ENTRY, "clear_entry_simple",
183 { GDK_CONTROL_MASK, 0, 0 },
184 { GDK_BackSpace, GDK_Escape, 0 }},
186 {KEY_CLEAR_ENTRY, "clear_entry_advanced",
187 { GDK_CONTROL_MASK, 0, 0 },
188 { GDK_BackSpace, GDK_Escape, 0 }},
190 {KEY_BACKSPACE, "backspace_simple",
191 { 0, 0 },
192 { GDK_BackSpace, 0 }},
194 {KEY_BACKSPACE, "backspace_advanced",
195 { 0, 0 },
196 { GDK_BackSpace, 0 }},
198 {KEY_NUMERIC_POINT, "numeric_point",
199 { 0, 0, 0, 0 },
200 { GDK_period, GDK_KP_Decimal, GDK_KP_Delete, GDK_KP_Separator, 0 }},
202 {KEY_CALCULATE, "result",
203 { 0, 0, 0, GDK_SHIFT_MASK, 0 },
204 { GDK_equal, GDK_KP_Enter, GDK_Return, GDK_equal, 0 }},
206 {KEY_START_BLOCK, "start_group",
207 { GDK_SHIFT_MASK, 0 },
208 { GDK_parenleft, 0 }},
210 {KEY_END_BLOCK, "end_group",
211 { GDK_SHIFT_MASK, 0 },
212 { GDK_parenright, 0 }},
214 {KEY_ADD, "add",
215 { GDK_SHIFT_MASK, 0, 0, 0 },
216 { GDK_plus, GDK_plus, GDK_KP_Add, 0 }},
218 {KEY_SUBTRACT, "subtract",
219 { 0, 0, 0, 0 },
220 { GDK_minus, GDK_KP_Subtract, GDK_R4, 0 }},
222 {KEY_MULTIPLY, "multiply",
223 { GDK_SHIFT_MASK, 0, 0, 0, 0 },
224 { GDK_asterisk, GDK_KP_Multiply, GDK_x, GDK_R6, 0 }},
226 {KEY_DIVIDE, "divide",
227 { 0, GDK_SHIFT_MASK, 0, 0, GDK_SHIFT_MASK, 0 },
228 { GDK_slash, GDK_slash, GDK_KP_Divide, GDK_R5, GDK_slash, 0 }},
230 {KEY_CHANGE_SIGN, "change_sign_simple",
231 { GDK_SHIFT_MASK, 0 },
232 { GDK_C, 0 }},
234 {KEY_CHANGE_SIGN, "change_sign_advanced",
235 { GDK_SHIFT_MASK, 0 },
236 { GDK_C, 0 }},
238 {KEY_INTEGER, "integer_portion",
239 { 0, 0 },
240 { GDK_i, 0 }},
242 {KEY_FRACTION, "fractional_portion",
243 { GDK_SHIFT_MASK, 0 },
244 { GDK_colon, 0 }},
246 {KEY_PERCENTAGE, "percentage",
247 { GDK_SHIFT_MASK, 0 },
248 { GDK_percent, 0 }},
250 {KEY_SQUARE, "square",
251 { GDK_SHIFT_MASK, 0 },
252 { GDK_at, 0 }},
254 {KEY_SQUARE_ROOT, "sqrt",
255 { 0, 0 },
256 { GDK_s, 0 }},
258 {KEY_RECIPROCAL, "reciprocal",
259 { 0, 0 },
260 { GDK_r, 0 }},
262 {KEY_ABSOLUTE_VALUE, "abs",
263 { 0, 0 },
264 { GDK_u, 0 }},
266 {KEY_MASK_16, "mask_16",
267 { 0, 0 },
268 { GDK_bracketright, 0 }},
270 {KEY_MASK_32, "mask_32",
271 { 0, 0 },
272 { GDK_bracketleft, 0 }},
274 {KEY_MODULUS_DIVIDE, "modulus_divide",
275 { GDK_SHIFT_MASK, 0 },
276 { GDK_M, 0 }},
278 {KEY_EXPONENTIAL, "exponential",
279 { GDK_SHIFT_MASK, 0 },
280 { GDK_E, 0 }},
282 {KEY_E_POW_X, "pow_e",
283 { GDK_SHIFT_MASK, 0 },
284 { GDK_braceleft, 0 }},
286 {KEY_10_POW_X, "pow_10",
287 { GDK_SHIFT_MASK, 0 },
288 { GDK_braceright, 0 }},
290 {KEY_X_POW_Y, "x_pow_y",
291 { GDK_SHIFT_MASK, GDK_SHIFT_MASK, 0 },
292 { GDK_caret, GDK_asciicircum, 0 }},
294 {KEY_NATURAL_LOGARITHM, "natural_logarithm",
295 { GDK_SHIFT_MASK, 0 },
296 { GDK_N, 0 }},
298 {KEY_LOGARITHM, "logarithm",
299 { GDK_SHIFT_MASK, 0 },
300 { GDK_G, 0 }},
302 {KEY_FACTORIAL, "factorial",
303 { GDK_SHIFT_MASK, 0 },
304 { GDK_exclam, 0 }},
306 {KEY_RANDOM, "random",
307 { GDK_SHIFT_MASK, 0 },
308 { GDK_question, 0 }},
310 {KEY_SIN, "sine",
311 { GDK_SHIFT_MASK, 0 },
312 { GDK_K, 0 }},
314 {KEY_COS, "cosine",
315 { GDK_SHIFT_MASK, 0 },
316 { GDK_J, 0 }},
318 {KEY_TAN, "tangent",
319 { GDK_SHIFT_MASK, 0 },
320 { GDK_L, 0 }},
322 {KEY_NOT, "not",
323 { GDK_SHIFT_MASK, 0 },
324 { GDK_asciitilde, 0 }},
326 {KEY_OR, "or",
327 { GDK_SHIFT_MASK, 0 },
328 { GDK_bar, 0 }},
330 {KEY_AND, "and",
331 { GDK_SHIFT_MASK, 0 },
332 { GDK_ampersand, 0 }},
334 {KEY_XOR, "xor",
335 { 0 },
336 { 0 }},
338 {KEY_XNOR, "xnor",
339 { 0, 0 },
340 { GDK_n, 0 }},
342 {KEY_FINC_CTRM, "finc_compounding_term",
343 { 0, 0 },
344 { GDK_m, 0 }},
346 {KEY_FINC_DDB, "finc_double_declining_depreciation",
347 { GDK_SHIFT_MASK, 0 },
348 { GDK_D, 0 }},
350 {KEY_FINC_FV, "finc_future_value",
351 { 0, 0 },
352 { GDK_v, 0 }},
354 {KEY_FINC_PMT, "finc_periodic_payment",
355 { GDK_SHIFT_MASK, 0 },
356 { GDK_P, 0 }},
358 {KEY_FINC_PV, "finc_present_value",
359 { 0, 0 },
360 { GDK_p, 0 }},
362 {KEY_FINC_RATE, "finc_periodic_interest_rate",
363 { GDK_SHIFT_MASK, 0 },
364 { GDK_T, 0 }},
366 {KEY_FINC_SLN, "finc_straight_line_depreciation",
367 { 0, 0 },
368 { GDK_l, 0 }},
370 {KEY_FINC_SYD, "finc_sum_of_the_years_digits_depreciation",
371 { 0, 0 },
372 { GDK_Y, 0 }},
374 {KEY_FINC_TERM, "finc_term",
375 { 0, 0 },
376 { GDK_T, 0 }},
378 #define NBUTTONS (sizeof(button_widgets) / sizeof(struct button_widget))
380 #define UI_FILE PACKAGE_GLADE_DIR "/gcalctool.glade"
382 #define MAXBITS 64 /* Bit panel: number of bit fields. */
384 #define GET_WIDGET(name) \
385 glade_xml_get_widget(X->ui, (name))
387 #define SET_MENUBAR_ITEM_STATE(name, state) \
388 g_object_set_data(G_OBJECT(GET_WIDGET(name)), "sensitive", \
389 GINT_TO_POINTER(state));
391 #define CONNECT_SIGNAL(name) glade_xml_signal_connect(X->ui, #name, \
392 G_CALLBACK(name))
394 struct Xobject { /* Gtk+/Xlib graphics object. */
395 GdkAtom clipboard_atom;
396 GdkAtom primary_atom;
398 GladeXML *ui;
400 GtkWidget *kframe; /* Main window. */
402 GtkTreeModel *constants_model;
403 GtkWidget *con_dialog; /* Edit constants dialog. */
405 GtkTreeModel *functions_model;
406 GtkWidget *fun_dialog; /* Edit functions dialog. */
407 GtkWidget *menubar; // FIXME: Why is this needed?
409 GtkWidget *bit_panel;
410 GtkWidget *bits[MAXBITS]; /* The 0/1 labels in the bit panel. */
412 GtkWidget *status_image; /* Statusbar image */
413 GtkWidget *statusbar;
415 GtkWidget *aframe; /* ASCII window. */
416 GtkWidget *aframe_ch;
418 GtkWidget *display_item; /* Calculator display. */
419 GtkTextBuffer *display_buffer; /* Buffer used in display */
420 GtkWidget *scrolledwindow; /* Scrolled window for display_item. */
422 GtkWidget *rframe; /* Register window. */
423 GtkWidget *regs[MAX_REGISTERS]; /* Memory registers. */
425 GtkWidget *spframe; /* Set Precision window. */
426 GtkWidget *spframe_val;
428 GtkWidget *buttons[NBUTTONS];
429 GtkWidget *digit_buttons[16];
430 GtkWidget *clear_buttons[2];
432 GtkWidget *bas_panel; /* Panel containing basic mode widgets. */
433 GtkWidget *adv_panel; /* Panel containing advanced mode widgets. */
434 GtkWidget *fin_panel; /* Panel containing financial mode widgets. */
435 GtkWidget *sci_panel; /* Panel containing scientific mode widgets. */
436 GtkWidget *mode_panel; /* Panel containing scientific mode widgets. */
438 /* Labels for popup menus */
439 GtkWidget *constant_menu_labels[MAX_CONSTANTS];
440 GtkWidget *function_menu_labels[MAX_FUNCTIONS];
441 GtkWidget *memory_store_labels[MAX_REGISTERS];
442 GtkWidget *memory_recall_labels[MAX_REGISTERS];
443 GtkWidget *memory_exchange_labels[MAX_REGISTERS];
445 /* Scientific mode widgets */
446 GtkWidget *hyperbolic_toggle; /* Hyperbolic mode. */
447 GtkWidget *inverse_toggle; /* Inverse mode. */
448 GtkWidget *base[MAXBASES]; /* Numeric base radio buttons. */
449 GtkWidget *disp[MAXDISPMODES]; /* Numeric display mode. */
450 GtkWidget *trig[MAXTRIGMODES]; /* Trigonometric mode. */
452 int menuval; /* Index to button array at menu time. */
453 char *lnp; /* Localized numerical point (UTF8 format) */
456 typedef struct Xobject *XVars;
458 enum {
459 COLUMN_NUMBER,
460 COLUMN_VALUE,
461 COLUMN_DESCRIPTION,
462 COLUMN_EDITABLE,
463 NUM_COLUMNS
466 static XVars X;
469 void
470 ui_set_syntax_mode(enum syntax mode)
472 struct exprm_state *e;
473 GtkWidget *widget;
475 /* TODO: Always do clear things when mode is changed. */
476 v->syntax = mode;
477 switch (v->syntax) {
478 case NPA:
479 v->noparens = 0;
480 MPstr_to_num("0", DEC, v->MPdisp_val);
481 show_display(v->MPdisp_val);
482 ui_set_statusbar(_("Activated no operator precedence mode"), "");
483 clear_undo_history();
484 break;
486 case EXPRS:
487 e = get_state();
488 MPstr_to_num("0", DEC, e->ans);
489 exp_del();
490 show_display(e->ans);
491 ui_set_statusbar(
492 _("Activated expression mode with operator precedence"), "");
493 break;
495 default:
496 assert(0);
498 set_resource(R_SYNTAX, Rsstr[v->syntax]);
499 ui_set_mode(v->modetype);
500 // FIXME: We can't allow the display to be editable. See bug #326938
501 gtk_text_view_set_editable(GTK_TEXT_VIEW(X->display_item),
502 (v->syntax == EXPRS));
504 /* Use loaded Arithmetic Precedence mode setting. */
505 // FIXME: Merge with arithmetic_mode_cb()
506 if (v->syntax == EXPRS) {
507 widget = GET_WIDGET("arithmetic_precedence_menu");
508 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget), TRUE);
509 } else {
510 widget = GET_WIDGET("ltr_precedence_menu");
511 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget), TRUE);
516 void
517 ui_set_accuracy(int accuracy)
519 GtkWidget *widget;
520 char text[MAXLINE];
521 char *desc, *current, *tooltip;
523 v->accuracy = accuracy;
525 SNPRINTF(text, MAXLINE, _("Other (%d) ..."), accuracy);
526 widget = gtk_bin_get_child(GTK_BIN(GET_WIDGET("acc_item_other")));
527 gtk_label_set_text(GTK_LABEL(widget), text);
529 desc = g_strdup_printf(ngettext("Set accuracy from 0 to %d numeric places.",
530 "Set accuracy from 0 to %d numeric places.",
531 MAXACC),
532 MAXACC);
534 /* Translator: This refers to the current accuracy setting */
535 current = g_strdup_printf(ngettext("Currently set to %d places.",
536 "Currently set to %d places.",
537 accuracy),
538 accuracy);
539 tooltip = g_strdup_printf ("%s %s [A]", desc, current);
540 gtk_widget_set_tooltip_text (GET_WIDGET("calc_accuracy_button"), tooltip);
541 g_free(desc);
542 g_free(current);
543 g_free(tooltip);
545 if (accuracy >= 0 && accuracy <= 9) {
546 SNPRINTF(text, MAXLINE, "acc_item%d", accuracy);
547 widget = GET_WIDGET(text);
548 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget), TRUE);
553 static void
554 ui_update_trig_mode()
556 static char *sine_labels[] = {N_("Sin"), N_("Sinh"),
557 N_("Sin<sup>-1</sup>"),
558 N_("Sinh<sup>-1</sup>")};
559 static int sine_functions[] = {KEY_SIN, KEY_SINH, KEY_ASIN, KEY_ASINH};
560 static char *cosine_labels[] = {N_("Cos"), N_("Cosh"),
561 N_("Cos<sup>-1</sup>"),
562 N_("Cosh<sup>-1</sup>")};
563 static int cosine_functions[] = {KEY_COS, KEY_COSH, KEY_ACOS, KEY_ACOSH};
564 static char *tangent_labels[] = {N_("Tan"), N_("Tanh"),
565 N_("Tan<sup>-1</sup>"),
566 N_("Tanh<sup>-1</sup>")};
567 static int tangent_functions[] = {KEY_TAN, KEY_TANH, KEY_ATAN, KEY_ATANH};
568 int index = 0;
570 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(X->hyperbolic_toggle))) {
571 index |= 0x1;
573 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(X->inverse_toggle))) {
574 index |= 0x2;
577 gtk_label_set_markup(GTK_LABEL(GET_WIDGET("sine_label")),
578 sine_labels[index]);
579 g_object_set_data(G_OBJECT(GET_WIDGET("calc_sine_button")), "calc_function",
580 GINT_TO_POINTER(sine_functions[index]));
582 gtk_label_set_markup(GTK_LABEL(GET_WIDGET("cosine_label")),
583 cosine_labels[index]);
584 g_object_set_data(G_OBJECT(GET_WIDGET("calc_cosine_button")), "calc_function",
585 GINT_TO_POINTER(cosine_functions[index]));
587 gtk_label_set_markup(GTK_LABEL(GET_WIDGET("tangent_label")),
588 tangent_labels[index]);
589 g_object_set_data(G_OBJECT(GET_WIDGET("calc_tangent_button")), "calc_function",
590 GINT_TO_POINTER(tangent_functions[index]));
594 void
595 ui_set_hyperbolic_state(gboolean state)
597 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(X->hyperbolic_toggle), state);
598 ui_update_trig_mode();
602 void
603 ui_set_inverse_state(gboolean state)
605 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(X->inverse_toggle), state);
606 ui_update_trig_mode();
610 void
611 ui_set_trigonometric_mode(enum trig_type mode)
613 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(X->trig[mode]), 1);
617 void
618 ui_set_numeric_mode(enum base_type mode)
620 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(X->disp[mode]), 1);
624 void
625 ui_set_show_thousands_seperator(gboolean visible)
627 GtkWidget *menu;
629 v->show_tsep = visible;
630 set_boolean_resource(R_TSEP, v->show_tsep);
632 menu = GET_WIDGET("show_thousands_separator_menu");
633 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), visible);
635 syntaxdep_show_display();
636 ui_make_registers();
640 void
641 ui_set_show_bitcalculating(gboolean visible)
643 GtkWidget *menu;
645 v->bitcalculating_mode = visible;
646 ui_set_mode(v->modetype);
647 set_resource(R_BITCALC, Rcstr[v->bitcalculating_mode]);
649 menu = GET_WIDGET("show_bitcalculating_menu");
650 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), visible);
654 void
655 ui_set_show_trailing_zeroes(gboolean visible)
657 GtkWidget *menu;
659 v->show_zeroes = visible;
660 set_boolean_resource(R_ZEROES, visible);
662 syntaxdep_show_display();
663 ui_make_registers();
665 menu = GET_WIDGET("show_trailing_zeroes_menu");
666 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), visible);
667 menu = GET_WIDGET("acc_trailing_zeroes_item");
668 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), visible);
672 void
673 ui_set_undo_enabled(gboolean undo, gboolean redo)
675 gtk_widget_set_sensitive(GET_WIDGET("undo_menu"), undo);
676 gtk_widget_set_sensitive(GET_WIDGET("redo_menu"), redo);
680 static char *
681 make_hostname()
683 Display *dpy = GDK_DISPLAY();
684 char client_hostname[MAXHOSTNAMELEN + 4];
685 char hostname[MAXHOSTNAMELEN];
686 char *display = DisplayString(dpy);
687 char *scanner = display;
689 GETHOSTNAME(hostname, MAXHOSTNAMELEN);
691 while (*scanner) {
692 scanner++;
695 while (*scanner != ':') {
696 scanner--;
699 *scanner = '\0';
701 if (strcmp(display, hostname) &&
702 strcmp(display, "localhost") &&
703 strcmp(display, "unix") &&
704 strcmp(display, "")) {
705 SPRINTF(client_hostname, " [%s] ", hostname);
706 } else {
707 STRCPY(client_hostname, "");
710 *scanner = ':';
712 if (client_hostname[0] == '\0')
713 return NULL;
714 else
715 return(strdup(client_hostname));
719 void
720 ui_set_mode(enum mode_type mode)
722 GtkRequisition *r;
723 gint w, h;
724 char *hostname, title[MAXLINE];
725 GtkWidget *menu;
727 switch (mode) {
728 case BASIC:
729 gtk_widget_show(X->bas_panel);
730 gtk_widget_hide(X->adv_panel);
731 gtk_widget_hide(X->fin_panel);
732 gtk_widget_hide(X->mode_panel);
733 gtk_widget_hide(X->bit_panel);
734 gtk_widget_hide(X->sci_panel);
735 menu = GET_WIDGET("view_basic_menu");
736 break;
738 case ADVANCED:
739 gtk_widget_hide(X->bas_panel);
740 gtk_widget_show(X->adv_panel);
741 gtk_widget_hide(X->fin_panel);
742 gtk_widget_hide(X->mode_panel);
743 gtk_widget_hide(X->bit_panel);
744 gtk_widget_hide(X->sci_panel);
745 menu = GET_WIDGET("view_advanced_menu");
746 break;
748 case FINANCIAL:
749 gtk_widget_hide(X->bas_panel);
750 gtk_widget_show(X->adv_panel);
751 gtk_widget_show(X->fin_panel);
752 gtk_widget_hide(X->mode_panel);
753 gtk_widget_hide(X->bit_panel);
754 gtk_widget_hide(X->sci_panel);
755 menu = GET_WIDGET("view_financial_menu");
756 break;
758 case SCIENTIFIC:
759 gtk_widget_hide(X->bas_panel);
760 gtk_widget_show(X->adv_panel);
761 gtk_widget_hide(X->fin_panel);
762 gtk_widget_show_all(X->mode_panel);
763 if (v->bitcalculating_mode) {
764 gtk_widget_show_all(X->bit_panel);
765 } else {
766 gtk_widget_hide(X->bit_panel);
768 gtk_widget_show(X->sci_panel);
769 menu = GET_WIDGET("view_scientific_menu");
770 break;
772 default:
773 assert(FALSE);
774 return;
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;
804 /* For initial display. */
805 gtk_window_set_default_size(GTK_WINDOW(X->kframe), w, h);
806 gtk_window_resize(GTK_WINDOW(X->kframe), w, h);
808 g_free(r);
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 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), TRUE);
822 void
823 ui_set_statusbar(gchar *text, const gchar *imagename)
825 GtkImage *image = GTK_IMAGE(X->status_image);
827 assert(text);
828 assert(imagename);
829 assert(image);
831 gtk_image_set_from_stock(image, imagename, GTK_ICON_SIZE_BUTTON);
832 gtk_statusbar_pop(GTK_STATUSBAR(X->statusbar), 0);
833 gtk_statusbar_push(GTK_STATUSBAR(X->statusbar), 0, text);
837 static void
838 bin_str(int MP_value[MP_SIZE], char *str, int maxbits)
840 int i, MP0[MP_SIZE], MP1[MP_SIZE], MP2[MP_SIZE], MP3[MP_SIZE];
841 int neg = 0;
843 MPstr_to_num("0", DEC, MP0);
844 MPstr_to_num("1", DEC, MP1);
845 MPstr_to_num("2", DEC, MP2);
847 if (mplt(MP_value, MP0)) {
848 mpcmim(MP_value, MP0);
849 mpadd(MP0, MP1, MP0);
850 neg = 1;
851 } else {
852 mpcmim(MP_value, MP0);
855 for (i = 0; i < maxbits; i++) {
856 double lsb; /* Least significant bit. */
857 calc_and(MP3, MP0, MP1);
858 mpcmd(MP3, &lsb);
860 if (lsb == 0) {
861 str[maxbits - i -1] = (neg) ? '1' : '0';
862 } else {
863 str[maxbits - i -1] = (neg) ? '0' : '1';
866 mpdiv(MP0, MP2, MP3);
867 mpcmim(MP3, MP0);
870 return;
874 static void
875 set_bit_panel()
877 int bit_str_len, i, MP1[MP_SIZE], MP2[MP_SIZE];
878 int MP[MP_SIZE];
879 char str[64], label[3];
880 int ret = usable_num(MP);
882 switch (v->syntax) {
883 case NPA:
884 MPstr_to_num(v->display, v->base, MP1);
885 mpcmim(MP1, MP2);
886 if (mpeq(MP1, MP2)) {
887 char *bit_str, label[3], tmp[MAXLINE];
888 int toclear = (v->current == KEY_CLEAR_ENTRY)
889 ? TRUE : FALSE;
891 bit_str = make_fixed(MP1, tmp, BIN, MAXLINE, toclear);
892 bit_str_len = strlen(bit_str);
893 if (bit_str_len <= MAXBITS) {
894 gtk_widget_set_sensitive(X->bit_panel, TRUE);
896 STRCPY(label, " 0");
897 for (i = 0; i < MAXBITS; i++) {
898 label[1] = (i < bit_str_len) ? bit_str[bit_str_len-i-1] : '0';
899 gtk_label_set_text(GTK_LABEL(X->bits[MAXBITS - i - 1]), label);
902 return;
905 gtk_widget_set_sensitive(X->bit_panel, FALSE);
906 break;
908 case EXPRS:
909 if (ret || !is_integer(MP)) {
910 gtk_widget_set_sensitive(X->bit_panel, FALSE);
911 return;
913 bin_str(MP, str, 64);
914 gtk_widget_set_sensitive(X->bit_panel, TRUE);
916 STRCPY(label, " 0");
917 for (i = 0; i < 64; i++) {
918 label[1] = str[64 - i - 1];
919 gtk_label_set_text(GTK_LABEL(X->bits[64 - i - 1]), label);
921 break;
923 default:
924 assert(FALSE);
929 static void
930 scroll_right()
932 if (!v->started) {
933 return;
936 if (GTK_WIDGET_VISIBLE(
937 GTK_SCROLLED_WINDOW(X->scrolledwindow)->hscrollbar)) {
938 GtkAdjustment *set;
940 set = gtk_scrolled_window_get_hadjustment(
941 GTK_SCROLLED_WINDOW(X->scrolledwindow));
942 gtk_adjustment_set_value(set, set->upper);
943 gtk_scrolled_window_set_hadjustment(
944 GTK_SCROLLED_WINDOW(X->scrolledwindow), set);
949 void
950 ui_set_display(char *str, gboolean minimize_changes)
952 char localized[MAX_LOCALIZED];
953 GtkTextIter start, end;
954 gchar *text;
955 gint diff;
956 gint len1, len2;
957 gboolean done;
959 if (str == NULL || str[0] == '\0') {
960 str = " ";
961 } else {
962 if (v->noparens == 0) {
963 localize_number(localized, str);
964 str = localized;
967 gtk_text_buffer_get_bounds(X->display_buffer, &start, &end);
968 text = gtk_text_buffer_get_text(X->display_buffer, &start, &end, TRUE);
969 diff = strcmp (text, str);
970 if (diff != 0) {
971 len1 = strlen(text);
972 len2 = strlen(str);
974 done = FALSE;
975 if (minimize_changes) {
976 if (len1 < len2 && strncmp(text, str, len1) == 0) {
977 /* Text insertion */
978 gtk_text_buffer_insert(X->display_buffer, &end, str + len1, -1);
979 done = TRUE;
980 } else if (len1 > len2 && strncmp(text, str, len2) == 0) {
981 /* Text deletion */
982 gtk_text_buffer_get_iter_at_offset (X->display_buffer, &start, len2);
983 gtk_text_buffer_delete(X->display_buffer, &start, &end);
984 done = TRUE;
988 if (!done) {
989 gtk_text_buffer_delete(X->display_buffer, &start, &end);
990 gtk_text_buffer_insert(X->display_buffer, &end, str, -1);
993 scroll_right();
994 g_free(text);
998 /* When an error condition occurs:
1000 * - make insensitive all buttons except Clr.
1001 * - make all Scientific mode toggles and checkboxes insensitive.
1002 * - make all menubar items insensitive except:
1003 * Calculator->Quit
1004 * Help->Contents
1006 * When the error condition is cleared, resensitise everything, setting
1007 * the numeric base buttons correctly.
1010 void
1011 ui_set_error_state(gboolean error)
1013 int i;
1015 v->error = error;
1017 for (i = 0; i < NBUTTONS; i++) {
1018 gtk_widget_set_sensitive(X->buttons[i], !v->error);
1020 /* Clr button always sensitive. */
1021 gtk_widget_set_sensitive(X->clear_buttons[0], TRUE);
1022 gtk_widget_set_sensitive(X->clear_buttons[1], TRUE);
1024 if (!v->error) {
1025 ui_set_base(v->base);
1028 gtk_widget_set_sensitive(X->mode_panel, !v->error);
1030 // FIXME: Isn't this missing a whole lot of widgets?
1031 SET_MENUBAR_ITEM_STATE("copy_menu", !v->error);
1032 SET_MENUBAR_ITEM_STATE("paste_menu", !v->error);
1033 SET_MENUBAR_ITEM_STATE("insert_ascii_menu", !v->error);
1034 SET_MENUBAR_ITEM_STATE("view_basic_menu", !v->error);
1035 SET_MENUBAR_ITEM_STATE("view_advanced_menu", !v->error);
1036 SET_MENUBAR_ITEM_STATE("view_financial_menu", !v->error);
1037 SET_MENUBAR_ITEM_STATE("view_scientific_menu", !v->error);
1038 SET_MENUBAR_ITEM_STATE("show_trailing_zeroes_menu",
1039 !v->error && (v->modetype == SCIENTIFIC));
1040 SET_MENUBAR_ITEM_STATE("show_thousands_separator_menu", !v->error);
1041 SET_MENUBAR_ITEM_STATE("show_registers_menu", !v->error);
1042 SET_MENUBAR_ITEM_STATE("arithmetic_precedence_menu", !v->error);
1043 SET_MENUBAR_ITEM_STATE("about_menu", !v->error);
1047 /*ARGSUSED*/
1048 static void
1049 about_cb(GtkWidget *widget)
1051 const gchar *authors[] = {
1052 "Rich Burridge <rich.burridge@sun.com>",
1053 "Sami Pietila <sampie@ariana-dsl.utu.fi>",
1054 "Robert Ancell <robert.ancell@gmail.com>",
1055 NULL
1057 const gchar *documenters[] = {
1058 "Sun Microsystems",
1059 NULL
1061 const gchar *translator_credits = _("translator-credits");
1063 const char *license[] = {
1064 N_("Gcalctool is free software; you can redistribute it and/or modify\n"
1065 "it under the terms of the GNU General Public License as published by\n"
1066 "the Free Software Foundation; either version 2 of the License, or\n"
1067 "(at your option) any later version.\n"),
1068 N_("Gcalctool is distributed in the hope that it will be useful,\n"
1069 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1070 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
1071 "GNU General Public License for more details.\n"),
1072 N_("You should have received a copy of the GNU General Public License\n"
1073 "along with Gcalctool; if not, write to the Free Software Foundation, Inc.,\n"
1074 "51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA\n")
1077 char *license_trans = g_strconcat(_(license[0]), "\n",
1078 _(license[1]), "\n",
1079 _(license[2]), "\n",
1080 NULL);
1082 gtk_show_about_dialog(GTK_WINDOW(X->kframe),
1083 "name",_("Gcalctool"),
1084 "version", VERSION,
1085 "copyright", _("\xc2\xa9 1986-2007 The Gcalctool authors"),
1086 "license", license_trans,
1087 "comments", _("Calculator with financial and scientific modes."),
1088 "authors", authors,
1089 "documenters", documenters,
1090 "translator_credits", translator_credits,
1091 "logo-icon-name", "gnome-calculator",
1092 NULL);
1096 static void
1097 cell_edited_cb(GtkCellRendererText *cell, const gchar *path_string,
1098 const gchar *new_text, gpointer data)
1100 GtkTreeModel *model = (GtkTreeModel *) data;
1101 GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
1102 GtkTreeIter iter;
1103 gchar *old_text;
1104 gint *column;
1106 column = g_object_get_data(G_OBJECT(cell), "column");
1108 gtk_tree_model_get_iter(model, &iter, path);
1110 switch (GPOINTER_TO_INT(column)) {
1111 case COLUMN_VALUE:
1112 gtk_tree_model_get(model, &iter, column, &old_text, -1);
1113 g_free(old_text);
1114 gtk_list_store_set(GTK_LIST_STORE(model), &iter, column,
1115 g_strdup(new_text), -1);
1116 break;
1118 case COLUMN_DESCRIPTION:
1119 gtk_tree_model_get(model, &iter, column, &old_text, -1);
1120 g_free(old_text);
1121 gtk_list_store_set(GTK_LIST_STORE(model), &iter, column,
1122 g_strdup(new_text), -1);
1123 break;
1126 gtk_tree_path_free(path);
1130 static void
1131 add_cf_column(GtkTreeView *treeview, gchar *name, gint colno, gboolean editable)
1133 GtkCellRenderer *renderer;
1134 GtkTreeModel *model = gtk_tree_view_get_model(treeview);
1136 renderer = gtk_cell_renderer_text_new();
1137 if (editable) {
1138 g_signal_connect(G_OBJECT(renderer), "edited",
1139 G_CALLBACK(cell_edited_cb), model);
1141 g_object_set_data(G_OBJECT(renderer), "column", GINT_TO_POINTER(colno));
1143 if (editable) {
1144 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(treeview),
1145 -1, name, renderer,
1146 "text", colno,
1147 "editable", COLUMN_EDITABLE,
1148 NULL);
1149 } else {
1150 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(treeview),
1151 -1, name, renderer,
1152 "text", colno,
1153 NULL);
1158 /*ARGSUSED*/
1159 static void
1160 aframe_cancel_cb(GtkButton *button, gpointer user_data)
1162 gtk_widget_hide(X->aframe);
1166 /*ARGSUSED*/
1167 static gboolean
1168 aframe_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer data)
1170 g_return_val_if_fail(GTK_IS_WIDGET(widget), FALSE);
1172 if (event->keyval == GDK_Escape) {
1173 gtk_widget_hide(X->aframe);
1176 return(FALSE);
1180 /*ARGSUSED*/
1181 static void
1182 aframe_ok_cb(GtkButton *button, gpointer user_data)
1184 char *ch;
1185 int val;
1187 ch = (char *) gtk_entry_get_text(GTK_ENTRY(X->aframe_ch));
1188 val = ch[0];
1189 mpcim(&val, v->MPdisp_val);
1190 show_display(v->MPdisp_val);
1191 gtk_widget_hide(X->aframe);
1195 /*ARGSUSED*/
1196 void
1197 base_cb(GtkWidget *widget)
1199 enum base_type base;
1201 base = (enum base_type) g_object_get_data(G_OBJECT(widget),
1202 "base_mode");
1203 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
1204 do_base(base);
1209 void
1210 ui_beep()
1212 gdk_beep();
1215 static void do_button(int function, int arg)
1217 struct exprm_state *e;
1219 switch (v->syntax) {
1220 case NPA:
1221 process_item(&buttons[function], arg);
1222 set_bit_panel();
1223 if (v->new_input && v->dtype == FIX) {
1224 STRNCPY(v->fnum, v->display, MAX_DIGITS - 1);
1225 ui_set_display(v->fnum, TRUE);
1227 break;
1229 case EXPRS:
1230 e = get_state();
1231 e->value = arg;
1232 MEMCPY(&(e->button), &buttons[function], sizeof(struct button));
1233 new_state();
1234 do_expression();
1235 set_bit_panel();
1236 break;
1238 default:
1239 assert(0);
1244 static void
1245 help_display(void)
1247 GError *error = NULL;
1248 char *command;
1249 const char *lang;
1250 char *uri = NULL;
1251 GdkScreen *gscreen;
1253 int i;
1255 const char * const * langs = g_get_language_names ();
1257 for (i = 0; langs[i]; i++) {
1258 lang = langs[i];
1259 if (strchr (lang, '.')) {
1260 continue;
1263 uri = g_build_filename(PACKAGE_DATA_DIR,
1264 "/gnome/help/gcalctool/",
1265 lang,
1266 "/gcalctool.xml",
1267 NULL);
1269 if (g_file_test (uri, G_FILE_TEST_EXISTS)) {
1270 break;
1274 command = g_strconcat ("gnome-open ghelp://", uri, NULL);
1275 gscreen = gdk_screen_get_default();
1276 gdk_spawn_command_line_on_screen (gscreen, command, &error);
1277 if (error) {
1278 GtkWidget *d;
1280 d = gtk_message_dialog_new(NULL,
1281 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1282 GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
1283 error->message);
1284 gtk_dialog_run(GTK_DIALOG(d));
1285 gtk_widget_destroy(d);
1286 g_error_free(error);
1287 error = NULL;
1290 g_free (command);
1291 g_free (uri);
1295 static void
1296 put_constant(int n, char *con_value, char *con_name)
1298 char key[MAXLINE];
1299 char *cstr = g_strdup(con_value);
1301 /* Constants are written out with no thousands seaparator and with a radix
1302 * character of ".".
1305 SNPRINTF(key, MAXLINE, "constant%1dvalue", n);
1306 set_resource(key, cstr);
1307 g_free(cstr);
1309 SNPRINTF(key, MAXLINE, "constant%1dname", n);
1310 set_resource(key, con_name);
1314 static void
1315 put_function(int n, char *fun_value, char *fun_name)
1317 char key[MAXLINE];
1319 SNPRINTF(key, MAXLINE, "function%1dvalue", n);
1320 set_resource(key, fun_value);
1322 SNPRINTF(key, MAXLINE, "function%1dname", n);
1323 set_resource(key, fun_name);
1327 /*ARGSUSED*/
1328 static void
1329 constant_menu_cb(GtkMenuItem *menu)
1331 int arg = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(menu), "constant_id"));
1332 do_button(KEY_CONSTANT, arg);
1336 /*ARGSUSED*/
1337 static void
1338 function_menu_cb(GtkMenuItem *menu)
1340 int arg = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(menu), "function_id"));
1341 do_button(KEY_FUNCTION, arg);
1345 /*ARGSUSED*/
1346 static void
1347 store_menu_cb(GtkMenuItem *menu)
1349 int arg = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(menu), "register_id"));
1350 do_button(KEY_STORE, arg);
1354 /*ARGSUSED*/
1355 static void
1356 recall_menu_cb(GtkMenuItem *menu)
1358 int arg = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(menu), "register_id"));
1359 do_button(KEY_RECALL, arg);
1363 /*ARGSUSED*/
1364 static void
1365 exchange_menu_cb(GtkMenuItem *menu)
1367 int arg = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(menu), "register_id"));
1368 do_button(KEY_EXCHANGE, arg);
1372 static void
1373 update_constants_menu(void)
1375 char mline[MAXLINE];
1376 int i;
1378 for (i = 0; i < MAX_CONSTANTS; i++) {
1379 SNPRINTF(mline, MAXLINE,
1380 "<span weight=\"bold\">%s_%1d:</span> %s [%s]", _("C"), i,
1381 make_number(v->MPcon_vals[i], DEC, TRUE),
1382 v->con_names[i]);
1383 gtk_label_set_markup_with_mnemonic(GTK_LABEL(X->constant_menu_labels[i]), mline);
1388 static void
1389 update_functions_menu(void)
1391 char mline[MAXLINE];
1392 int i;
1394 for (i = 0; i < MAX_FUNCTIONS; i++) {
1395 if (strlen(v->fun_vals[i]) != 0) {
1396 SNPRINTF(mline, MAXLINE,
1397 "<span weight=\"bold\">%s_%1d:</span> %s [%s]",
1398 _("F"), i, v->fun_vals[i], v->fun_names[i]);
1399 gtk_widget_show(gtk_widget_get_parent(X->function_menu_labels[i]));
1400 gtk_label_set_markup_with_mnemonic(GTK_LABEL(X->function_menu_labels[i]), mline);
1402 else
1403 gtk_widget_hide(gtk_widget_get_parent(X->function_menu_labels[i]));
1408 static void
1409 edit_constants_response_cb(GtkDialog *dialog, gint id)
1411 GtkTreeIter iter;
1412 gint number;
1413 gchar *value;
1414 gchar *description;
1416 if (id == GTK_RESPONSE_HELP) {
1417 help_display();
1420 if (id == GTK_RESPONSE_ACCEPT) {
1421 if (gtk_tree_model_get_iter_first(X->constants_model, &iter)) {
1422 do {
1423 gtk_tree_model_get(X->constants_model, &iter,
1424 COLUMN_NUMBER, &number,
1425 COLUMN_VALUE, &value,
1426 COLUMN_DESCRIPTION, &description, -1);
1427 MPstr_to_num(value, DEC, v->MPcon_vals[number]);
1428 STRNCPY(v->con_names[number], description, MAXLINE - 1);
1429 put_constant(number, value, description);
1430 } while (gtk_tree_model_iter_next(X->constants_model, &iter));
1434 gtk_widget_hide(GTK_WIDGET(dialog));
1438 static void
1439 edit_functions_response_cb(GtkDialog *dialog, gint id)
1441 GtkTreeIter iter;
1442 gint number;
1443 gchar *value;
1444 gchar *description;
1446 if (id == GTK_RESPONSE_HELP) {
1447 help_display();
1450 if (id == GTK_RESPONSE_ACCEPT) {
1451 if (gtk_tree_model_get_iter_first(X->functions_model, &iter)) {
1452 do {
1453 gtk_tree_model_get(X->functions_model, &iter,
1454 COLUMN_NUMBER, &number,
1455 COLUMN_VALUE, &value,
1456 COLUMN_DESCRIPTION, &description, -1);
1457 STRNCPY(v->fun_vals[number], convert(value), MAXLINE - 1);
1458 STRNCPY(v->fun_names[number], description, MAXLINE - 1);
1459 put_function(number, value, description);
1460 } while (gtk_tree_model_iter_next(X->functions_model, &iter));
1464 gtk_widget_hide(GTK_WIDGET(dialog));
1468 /*ARGSUSED*/
1469 static GtkTreeModel *
1470 create_constants_model()
1472 gint i = 0;
1473 GtkListStore *model;
1474 GtkTreeIter iter;
1476 model = gtk_list_store_new(NUM_COLUMNS, G_TYPE_INT, G_TYPE_STRING,
1477 G_TYPE_STRING, G_TYPE_BOOLEAN);
1478 for (i = 0; i < MAX_CONSTANTS; i++) {
1479 gtk_list_store_append(model, &iter);
1481 gtk_list_store_set(model, &iter,
1482 COLUMN_NUMBER, i,
1483 COLUMN_EDITABLE, TRUE,
1484 -1);
1487 return(GTK_TREE_MODEL(model));
1491 /*ARGSUSED*/
1492 static GtkTreeModel *
1493 create_functions_model()
1495 gint i = 0;
1496 GtkListStore *model;
1497 GtkTreeIter iter;
1499 model = gtk_list_store_new(NUM_COLUMNS, G_TYPE_INT, G_TYPE_STRING,
1500 G_TYPE_STRING, G_TYPE_BOOLEAN);
1501 for (i = 0; i < MAX_FUNCTIONS; i++) {
1502 gtk_list_store_append(model, &iter);
1504 gtk_list_store_set(model, &iter,
1505 COLUMN_NUMBER, i,
1506 COLUMN_EDITABLE, TRUE,
1507 -1);
1510 return(GTK_TREE_MODEL(model));
1514 void
1515 ui_make_registers() /* Calculate memory register frame values. */
1517 char *mval, key[MAXLINE];
1518 int n;
1520 for (n = 0; n < MAX_REGISTERS; n++) {
1521 mval = make_number(v->MPmvals[n], v->base, TRUE);
1522 gtk_entry_set_width_chars(GTK_ENTRY(X->regs[n]), strlen(mval));
1523 gtk_entry_set_text(GTK_ENTRY(X->regs[n]), mval);
1524 SNPRINTF(key, MAXLINE, "register%d", n);
1525 set_resource(key, mval);
1530 static void
1531 reset_mode_display(void)
1533 switch (v->syntax) {
1534 case NPA:
1535 show_display(v->MPdisp_val);
1536 break;
1538 case EXPRS:
1539 refresh_display();
1540 break;
1542 default:
1543 assert(FALSE);
1545 ui_make_registers();
1549 static void
1550 save_win_position()
1552 int x, y;
1554 (void) gdk_window_get_origin(X->kframe->window, &x, &y);
1555 set_int_resource(R_XPOS, x);
1556 set_int_resource(R_YPOS, y);
1560 static void
1561 change_mode(int mode)
1563 v->modetype = mode;
1565 ui_set_base(DEC);
1566 ui_set_numeric_mode(FIX);
1567 ui_set_accuracy(9);
1568 ui_set_show_thousands_seperator(FALSE);
1569 ui_set_show_trailing_zeroes(FALSE);
1571 reset_mode_display();
1572 do_mode(TRUE);
1576 static gboolean
1577 request_change_mode()
1579 GtkWidget *dialog, *request_check, *button;
1580 gint response;
1582 if (!v->warn_change_mode)
1583 return TRUE;
1585 dialog = gtk_message_dialog_new(GTK_WINDOW(X->kframe),
1586 GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
1587 GTK_MESSAGE_WARNING,
1588 GTK_BUTTONS_CANCEL,
1589 "%s",
1590 _("Changing Modes Clears Calculation"));
1591 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
1592 "%s",
1593 _("When you change modes, the current calculation "
1594 "will be cleared, and the base will be reset to "
1595 "decimal."));
1597 request_check = gtk_check_button_new_with_mnemonic(_("_Do not warn me again"));
1598 gtk_box_pack_end(GTK_BOX(GTK_DIALOG(dialog)->vbox),
1599 request_check, FALSE, FALSE, 0);
1601 button = gtk_dialog_add_button(GTK_DIALOG(dialog),
1602 _("C_hange Mode"), GTK_RESPONSE_ACCEPT);
1603 gtk_button_set_image(GTK_BUTTON(button),
1604 gtk_image_new_from_stock(GTK_STOCK_REFRESH,
1605 GTK_ICON_SIZE_BUTTON));
1606 /* Set default focus on affirmative button */
1607 gtk_widget_grab_focus(button);
1609 gtk_dialog_set_alternative_button_order(GTK_DIALOG(dialog),
1610 GTK_RESPONSE_ACCEPT,
1611 GTK_RESPONSE_CANCEL,
1612 -1);
1614 gtk_window_set_position(GTK_WINDOW(dialog),
1615 GTK_WIN_POS_CENTER_ON_PARENT);
1617 gtk_widget_show_all(dialog);
1618 response = gtk_dialog_run(GTK_DIALOG(dialog));
1620 // FIXME: Save this in GConf
1621 v->warn_change_mode = !gtk_toggle_button_get_active(
1622 GTK_TOGGLE_BUTTON(request_check));
1624 gtk_widget_destroy(dialog);
1626 return response == GTK_RESPONSE_ACCEPT;
1630 /*ARGSUSED*/
1631 static gboolean
1632 bit_toggle_cb(GtkWidget *event_box, GdkEventButton *event)
1634 double number;
1635 unsigned long long lval;
1636 int n, MP1[MP_SIZE], index;
1638 index = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(event_box),
1639 "bit_index"));
1640 n = MAXBITS - index - 1;
1641 MPstr_to_num(v->display, v->base, MP1);
1642 mpcmd(MP1, &number);
1643 lval = (long long) number;
1645 if (lval & (1LL << n)) {
1646 lval &= ~(1LL << n);
1647 gtk_label_set_text(GTK_LABEL(X->bits[index]), " 0");
1648 } else {
1649 lval |= (1LL << n);
1650 gtk_label_set_text(GTK_LABEL(X->bits[index]), " 1");
1653 number = (double) lval;
1654 mpcdm(&number, v->MPdisp_val);
1655 show_display(v->MPdisp_val);
1656 v->toclear = 0;
1658 return(TRUE);
1662 static void
1663 menu_item_select_cb(GtkWidget *widget)
1665 GtkStatusbar *statusbar = GTK_STATUSBAR(X->statusbar);
1666 gchar *tooltip;
1667 guint context_id;
1669 context_id = gtk_statusbar_get_context_id(statusbar, "menuhelp");
1671 tooltip = (gchar *)g_object_get_data(G_OBJECT(widget), "tooltip");
1672 if (tooltip) {
1673 gtk_statusbar_push(statusbar, context_id, tooltip);
1678 /*ARGSUSED*/
1679 static void
1680 menu_item_deselect_cb(GtkWidget *widget)
1682 GtkStatusbar *statusbar = GTK_STATUSBAR(X->statusbar);
1683 guint context_id;
1685 context_id = gtk_statusbar_get_context_id(statusbar, "menuhelp");
1686 gtk_statusbar_pop(statusbar, context_id);
1690 static void
1691 set_menubar_tooltip(gchar *menu_name)
1693 GtkWidget *menu;
1694 gchar *tooltip;
1696 menu = GET_WIDGET(menu_name);
1697 tooltip = gtk_widget_get_tooltip_text(menu);
1698 g_object_set_data(G_OBJECT(menu), "tooltip", tooltip);
1699 gtk_widget_set_tooltip_text(menu, NULL);
1703 static void
1704 update_memory_menus()
1706 char mstr[MAXLINE];
1707 int i;
1709 for (i = 0; i < MAX_REGISTERS; i++) {
1710 SNPRINTF(mstr, MAXLINE, "<span weight=\"bold\">%s_%d:</span> %s",
1711 /* translators: R is the short form of register used inter alia
1712 in popup menus */
1713 _("R"), i, make_number(v->MPmvals[i], v->base, TRUE));
1714 gtk_label_set_markup_with_mnemonic(GTK_LABEL(X->memory_store_labels[i]), mstr);
1715 gtk_label_set_markup_with_mnemonic(GTK_LABEL(X->memory_recall_labels[i]), mstr);
1716 gtk_label_set_markup_with_mnemonic(GTK_LABEL(X->memory_exchange_labels[i]), mstr);
1721 /*ARGSUSED*/
1722 static void
1723 rframe_response_cb(GtkDialog *dialog, int response)
1725 ui_set_registers_visible(FALSE);
1729 /*ARGSUSED*/
1730 static gboolean
1731 aframe_delete_cb(GtkWidget *widget, GdkEvent *event, gpointer user_data)
1733 gtk_widget_hide(widget);
1735 return(TRUE);
1739 /*ARGSUSED*/
1740 static gboolean
1741 rframe_delete_cb(GtkWidget *widget, GdkEvent *event, gpointer user_data)
1743 gtk_dialog_response(GTK_DIALOG(widget), GTK_RESPONSE_DELETE_EVENT);
1745 return(TRUE);
1749 /*ARGSUSED*/
1750 static gboolean
1751 spframe_delete_cb(GtkWidget *widget, GdkEvent *event, gpointer user_data)
1753 gtk_widget_hide(X->spframe);
1755 return(TRUE);
1759 /*ARGSUSED*/
1760 void
1761 disp_cb(GtkWidget *widget)
1763 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1764 do_numtype((enum num_type) g_object_get_data(G_OBJECT(widget), "numeric_mode"));
1768 static void
1769 get_constant(int n)
1771 char nkey[MAXLINE], *nline;
1772 char vkey[MAXLINE], *vline;
1774 SNPRINTF(nkey, MAXLINE, "constant%1dname", n);
1775 if ((nline = get_resource(nkey)) == NULL) {
1776 return;
1779 SNPRINTF(vkey, MAXLINE, "constant%1dvalue", n);
1780 if ((vline = get_resource(vkey)) == NULL) {
1781 return;
1784 MPstr_to_num(vline, DEC, v->MPcon_vals[n]);
1785 STRNCPY(v->con_names[n], nline, MAXLINE - 1);
1789 static void
1790 get_display() /* The Copy function key has been pressed. */
1792 gchar *string = NULL;
1793 GtkTextIter start, end;
1795 if (gtk_text_buffer_get_selection_bounds(X->display_buffer, &start, &end) == TRUE) {
1796 string = gtk_text_buffer_get_text(X->display_buffer, &start, &end, FALSE);
1797 } else {
1798 gtk_text_buffer_get_bounds(X->display_buffer, &start, &end);
1799 string = gtk_text_buffer_get_text(X->display_buffer, &start, &end, FALSE);
1802 if (v->shelf != NULL) {
1803 free(v->shelf);
1805 v->shelf = g_locale_from_utf8(string, strlen(string), NULL, NULL, NULL);
1806 g_free(string);
1808 gtk_clipboard_set_text(gtk_clipboard_get(X->clipboard_atom), v->shelf, -1);
1812 static void
1813 get_function(int n)
1815 char nkey[MAXLINE], *nline;
1816 char vkey[MAXLINE], *vline;
1818 SNPRINTF(nkey, MAXLINE, "function%1dname", n);
1819 if ((nline = get_resource(nkey)) == NULL) {
1820 return;
1823 SNPRINTF(vkey, MAXLINE, "function%1dvalue", n);
1824 if ((vline = get_resource(vkey)) == NULL) {
1825 return;
1828 STRNCPY(v->fun_vals[n], convert(vline), MAXLINE - 1);
1829 STRNCPY(v->fun_names[n], nline, MAXLINE - 1);
1833 char *
1834 ui_get_localized_numeric_point(void)
1836 const char *decimal_point;
1838 decimal_point = localeconv()->decimal_point;
1840 return(g_locale_to_utf8(decimal_point, -1, NULL, NULL, NULL));
1844 /*ARGSUSED*/
1845 static void
1846 get_proc(GtkClipboard *clipboard, const gchar *buffer, gpointer data)
1848 int ret;
1849 gchar *dstp, *end_buffer, *srcp, *text;
1851 if (buffer == NULL) {
1852 return;
1855 end_buffer = (gchar *) (buffer + strlen(buffer));
1856 text = malloc(strlen(buffer)+1);
1858 srcp = (gchar *) buffer;
1859 dstp = text;
1860 while (srcp < end_buffer) {
1862 /* If the clipboard buffer contains any occurances of the "thousands
1863 * separator", remove them.
1865 if (*srcp == v->tsep[0]) {
1866 if (strstr(srcp, v->tsep) == srcp) {
1867 srcp += strlen(v->tsep);
1868 } else {
1869 *dstp++ = *srcp++;
1871 } else {
1873 /* If an "A", "B", "C", "D" or "F" character is encountered, it
1874 * will be converted to its lowercase equivalent. If an "E" is
1875 * found, and the next character is a "-" or a "+", then it
1876 * remains as an upper case "E" (it's assumed to be a possible
1877 * exponential number), otherwise its converted to a lower case
1878 * "e". See bugs #455889 and #469245 for more details.
1880 switch (*srcp) {
1881 case 'A':
1882 case 'B':
1883 case 'C':
1884 case 'D':
1885 case 'F': *dstp++ = tolower(*srcp);
1886 srcp++;
1887 break;
1889 case 'E': if (srcp < (end_buffer-1)) {
1890 if (*(srcp+1) != '-' &&
1891 *(srcp+1) != '+') {
1892 *dstp++ = tolower(*srcp);
1893 srcp++;
1894 break;
1897 /*FALLTHROUGH*/
1899 default: *dstp++ = *srcp++;
1903 *dstp++ = '\0';
1905 switch (v->syntax) {
1906 case NPA:
1907 ret = lr_parse((char *) text, v->MPdisp_val);
1908 if (!ret) {
1909 show_display(v->MPdisp_val);
1910 } else {
1911 ui_set_statusbar(_("Clipboard contained malformed calculation"),
1912 "gtk-dialog-error");
1914 break;
1916 case EXPRS:
1917 exp_append((char *) text);
1918 refresh_display();
1919 break;
1921 default:
1922 assert(0);
1924 free(text);
1928 void
1929 ui_set_base(enum base_type base)
1931 int i, baseval = basevals[(int) base];
1933 v->base = base;
1935 for (i = 0; i < 16; i++) {
1936 gtk_widget_set_sensitive(X->digit_buttons[i], i < baseval);
1938 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(X->base[base]), 1);
1942 void
1943 ui_set_registers_visible(gboolean visible)
1945 GtkWidget *menu;
1946 ui_make_registers();
1948 menu = GET_WIDGET("show_registers_menu");
1949 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), visible);
1951 gtk_widget_realize(X->rframe);
1953 if (visible) {
1954 if (gdk_window_is_visible(X->rframe->window)) {
1955 gdk_window_raise(X->rframe->window);
1956 return;
1958 ds_position_popup(X->kframe, X->rframe, DS_POPUP_ABOVE);
1959 gtk_widget_show(X->rframe);
1960 } else {
1961 gtk_widget_hide(X->rframe);
1964 set_boolean_resource(R_REGS, visible);
1968 /*ARGSUSED*/
1969 static void
1970 help_cb(GtkWidget *widget)
1972 if (v->started)
1973 help_display();
1977 /*ARGSUSED*/
1978 void
1979 hyp_cb(GtkWidget *widget)
1981 ui_update_trig_mode();
1985 /*ARGSUSED*/
1986 void
1987 inv_cb(GtkWidget *widget)
1989 ui_update_trig_mode();
1993 static gboolean
1994 check_for_localized_numeric_point(int keyval)
1996 gchar outbuf[10]; /* Minumum size 6. */
1997 gunichar ch;
1999 ch = gdk_keyval_to_unicode(keyval);
2000 g_return_val_if_fail(g_unichar_validate(ch), FALSE);
2002 outbuf[g_unichar_to_utf8(ch, outbuf)] = '\0';
2004 return(strcmp(outbuf, X->lnp) == 0);
2008 static void
2009 ui_parse_display()
2011 char *text;
2012 GtkTextIter start, end;
2014 gtk_text_buffer_get_bounds(X->display_buffer, &start, &end);
2016 text = gtk_text_buffer_get_text(X->display_buffer,
2017 &start,
2018 &end,
2019 FALSE);
2020 exp_replace(text);
2025 ui_get_cursor(void)
2027 gint pos;
2028 g_object_get(G_OBJECT(X->display_buffer), "cursor-position", &pos, NULL);
2029 return pos;
2033 /*ARGSUSED*/
2034 static gboolean
2035 display_focus_out_cb(GtkWidget *widget, GdkEventKey *event)
2037 if (v->syntax == EXPRS) {
2038 ui_parse_display();
2041 return(FALSE);
2045 /*ARGSUSED*/
2046 static gboolean
2047 display_focus_in_cb(GtkWidget *widget, GdkEventKey *event)
2049 v->ghost_zero = 0;
2051 return(FALSE);
2055 /*ARGSUSED*/
2056 static void
2057 menu_pos_func(GtkMenu *menu, gint *x, gint *y,
2058 gboolean *push_in, gpointer user_data)
2060 GdkPoint *loc = (GdkPoint *) user_data;
2062 *x = loc->x;
2063 *y = loc->y;
2067 /*ARGSUSED*/
2068 static void
2069 button_cb(GtkWidget *widget, GdkEventButton *event)
2071 int function;
2072 GtkWidget *menu;
2073 GdkPoint loc;
2075 function = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget),
2076 "calc_function"));
2077 menu = (GtkWidget *)g_object_get_data(G_OBJECT(widget), "calc_menu");
2079 if (menu == NULL) {
2080 do_button(function, 0);
2081 } else {
2082 /* If gcalctool is being driven by gok, the on-screen keyboard
2083 * assistive technology, it's possible that the event returned by
2084 * gtk_get_current_event() is NULL. If this is the case, we need
2085 * to fudge the popping up on the menu associated with this menu
2086 * button.
2089 update_constants_menu();
2090 update_functions_menu();
2091 update_memory_menus();
2093 if (event == NULL) {
2094 gdk_window_get_origin(widget->window, &loc.x, &loc.y);
2095 loc.x += widget->allocation.x;
2096 loc.y += widget->allocation.y;
2097 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, menu_pos_func,
2098 (gpointer) &loc, 0, gtk_get_current_event_time());
2099 } else if (event->button == 1) {
2100 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
2101 event->button, event->time);
2107 /*ARGSUSED*/
2108 static void
2109 select_display_entry(int offset)
2111 GtkTextIter iter;
2113 gtk_text_buffer_get_iter_at_offset(X->display_buffer, &iter, offset);
2114 gtk_text_buffer_place_cursor(X->display_buffer, &iter);
2115 gtk_widget_grab_focus(X->display_item);
2119 /*ARGSUSED*/
2120 static gboolean
2121 kframe_key_press_cb(GtkWidget *widget, GdkEventKey *event)
2123 int i, j, state;
2124 GtkWidget *button;
2126 if (check_for_localized_numeric_point(event->keyval) == TRUE) {
2127 event->state = 0;
2128 event->keyval = GDK_KP_Decimal;
2131 state = event->state & (GDK_CONTROL_MASK | GDK_MOD1_MASK);
2133 /* Accuracy shortcuts */
2134 if (state == GDK_CONTROL_MASK && v->modetype == SCIENTIFIC)
2136 switch (event->keyval) {
2137 case GDK_0:
2138 do_accuracy(0);
2139 return (TRUE);
2140 case GDK_1:
2141 do_accuracy(1);
2142 return (TRUE);
2143 case GDK_2:
2144 do_accuracy(2);
2145 return (TRUE);
2146 case GDK_3:
2147 do_accuracy(3);
2148 return (TRUE);
2149 case GDK_4:
2150 do_accuracy(4);
2151 return (TRUE);
2152 case GDK_5:
2153 do_accuracy(5);
2154 return (TRUE);
2155 case GDK_6:
2156 do_accuracy(6);
2157 return (TRUE);
2158 case GDK_7:
2159 do_accuracy(7);
2160 return (TRUE);
2161 case GDK_8:
2162 do_accuracy(8);
2163 return (TRUE);
2164 case GDK_9:
2165 do_accuracy(9);
2166 return (TRUE);
2170 /* Connect home and end keys to move into the display entry */
2171 if (event->keyval == GDK_Home)
2173 select_display_entry(0);
2174 return (TRUE);
2175 } else if (event->keyval == GDK_End)
2177 select_display_entry(-1);
2178 return (TRUE);
2181 for (i = 0; i < NBUTTONS; i++) {
2182 button = X->buttons[i];
2184 /* Check any parent widgets are visible */
2185 if (!GTK_WIDGET_VISIBLE(gtk_widget_get_parent(button)) ||
2186 !GTK_WIDGET_VISIBLE(button) || !GTK_WIDGET_IS_SENSITIVE(button)) {
2187 continue;
2190 j = 0;
2191 while (button_widgets[i].accelerator_keys[j] != 0) {
2192 if (button_widgets[i].accelerator_keys[j] == event->keyval &&
2193 (button_widgets[i].accelerator_mods[j] & ~GDK_SHIFT_MASK) == state) {
2194 button_cb(button, NULL);
2195 return(TRUE);
2197 j++;
2201 return(FALSE);
2205 /*ARGSUSED*/
2206 static gboolean
2207 mouse_button_cb(GtkWidget *widget, GdkEventButton *event)
2209 if (event->button == 2) {
2210 gtk_clipboard_request_text(gtk_clipboard_get(X->primary_atom),
2211 get_proc, NULL);
2214 return(FALSE);
2218 static void
2219 set_win_position()
2221 int intval, screen_height, screen_width;
2222 int x = 0, y = 0;
2224 screen_width = gdk_screen_get_width(gdk_screen_get_default());
2225 screen_height = gdk_screen_get_height(gdk_screen_get_default());
2227 if (get_int_resource(R_XPOS, &intval)) {
2228 x = intval;
2229 if (x < 0 || x > screen_width) {
2230 x = 0;
2234 if (get_int_resource(R_YPOS, &intval)) {
2235 y = intval;
2236 if (y < 0 || y > screen_height) {
2237 y = 0;
2241 gtk_window_move(GTK_WINDOW(X->kframe), x, y);
2244 static void
2245 show_ascii_frame() /* Display ASCII popup. */
2247 if (!GTK_WIDGET_VISIBLE(X->aframe)) {
2248 ds_position_popup(X->kframe, X->aframe, DS_POPUP_LEFT);
2250 gtk_window_set_focus(GTK_WINDOW(X->kframe), GTK_WIDGET(X->aframe_ch));
2251 gtk_widget_show(X->aframe);
2255 static void
2256 show_precision_frame() /* Display Set Precision popup. */
2258 if (!GTK_WIDGET_VISIBLE(X->spframe)) {
2259 ds_position_popup(X->kframe, X->spframe, DS_POPUP_LEFT);
2261 gtk_window_set_focus(GTK_WINDOW(X->spframe), GTK_WIDGET(X->spframe_val));
2262 gtk_widget_show(X->spframe);
2266 /* Handle menu bar menu selection. */
2268 /*ARGSUSED*/
2269 static void
2270 edit_cb(GtkWidget *widget)
2272 gboolean can_paste;
2273 gboolean can_copy;
2275 if (!v->started) {
2276 return;
2279 can_copy = gtk_text_buffer_get_has_selection(X->display_buffer);
2280 can_paste = gtk_clipboard_wait_is_text_available(
2281 gtk_clipboard_get(X->clipboard_atom));
2283 gtk_widget_set_sensitive(GET_WIDGET("copy_menu"), can_copy);
2284 gtk_widget_set_sensitive(GET_WIDGET("paste_menu"), can_paste);
2288 static void
2289 handle_selection() /* Handle the GET function key being pressed. */
2291 gtk_clipboard_request_text(gtk_clipboard_get(X->clipboard_atom),
2292 get_proc, NULL);
2296 /*ARGSUSED*/
2297 static void
2298 popup_paste_cb(GtkMenuItem *menuitem)
2300 handle_selection();
2304 /*ARGSUSED*/
2305 static void
2306 copy_cb(GtkWidget *widget)
2308 if (v->started) {
2309 get_display();
2314 /*ARGSUSED*/
2315 static void
2316 paste_cb(GtkWidget *widget)
2318 if (v->started) {
2319 handle_selection();
2324 /*ARGSUSED*/
2325 static void
2326 undo_cb(GtkWidget *widget)
2328 if (v->started) {
2329 perform_undo();
2330 refresh_display();
2335 /*ARGSUSED*/
2336 static void
2337 redo_cb(GtkWidget *widget)
2339 if (v->started) {
2340 perform_redo();
2341 refresh_display();
2346 /*ARGSUSED*/
2347 static void
2348 for_each_menu(GtkWidget *widget, gpointer data)
2350 /* Find the "Paste" entry and activate it (see bug #317786). */
2351 if (strcmp(G_OBJECT_TYPE_NAME(widget), "GtkImageMenuItem") == 0) {
2352 GtkWidget *label = gtk_bin_get_child(GTK_BIN(widget));
2354 if (strcmp(gtk_label_get_text(GTK_LABEL(label)), _("Paste")) == 0) {
2355 if (gtk_clipboard_wait_is_text_available(
2356 gtk_clipboard_get(X->clipboard_atom))) {
2357 gtk_widget_set_sensitive(GTK_WIDGET(widget), TRUE);
2358 g_signal_connect(GTK_OBJECT(widget), "activate",
2359 G_CALLBACK(popup_paste_cb), NULL);
2366 /*ARGSUSED*/
2367 static void
2368 buffer_populate_popup_cb(GtkTextView *textview, GtkMenu *menu)
2370 gtk_container_foreach(GTK_CONTAINER(menu), for_each_menu, NULL);
2374 /*ARGSUSED*/
2375 static void
2376 insert_ascii_cb(GtkWidget *widget)
2378 if (v->started) {
2379 show_ascii_frame();
2384 static void
2385 shift_cb(GtkWidget *widget)
2387 int count = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget),
2388 "shiftcount"));
2389 if (v->started) {
2390 do_button(KEY_SHIFT, count);
2395 /*ARGSUSED*/
2396 static void
2397 show_bitcalculating_cb(GtkWidget *widget)
2399 gboolean visible;
2401 visible = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget));
2402 if (v->started) {
2403 ui_set_show_bitcalculating(visible);
2408 /*ARGSUSED*/
2409 static void
2410 show_registers_cb(GtkWidget *widget)
2412 gboolean visible;
2414 visible = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget));
2415 if (v->started) {
2416 ui_set_registers_visible(visible);
2421 static void
2422 arithmetic_mode_cb(GtkWidget *widget)
2424 enum syntax mode;
2426 mode = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget)) ? EXPRS : NPA;
2427 if (v->started) {
2428 ui_set_syntax_mode(mode);
2433 /*ARGSUSED*/
2434 static void
2435 mode_radio_cb(GtkWidget *menu)
2437 struct exprm_state *e;
2438 int mode; /* The new mode. */
2439 int immediate = 0; /* Set if we can change mode without warning user. */
2440 int complete = 0; /* Set if the user has completed a calculation. */
2442 if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menu))) {
2443 return;
2446 if (!v->started) {
2447 return;
2450 mode = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(menu), "calcmode"));
2452 /* If the user has completed a calculation and we are going to a
2453 * new mode that is "compatible" with this one, then just change
2454 * modes. Otherwise display a dialog warning the user that the
2455 * current calculation will be cleared.
2457 * Incompatible modes are:
2459 * Scientific -> Basic
2460 * Scientific -> Advanced
2461 * Scientific -> Financial
2463 * (unless we are in Scientific mode with Decimal numeric base and Fixed).
2466 switch (v->syntax) {
2467 case NPA:
2468 if (v->old_cal_value < 0 ||
2469 v->old_cal_value == KEY_CALCULATE) {
2470 complete = 1; /* Calculation is complete. */
2472 break;
2474 case EXPRS:
2475 e = get_state();
2476 if (!e->expression || !strcmp(e->expression, "Ans")) {
2477 complete = 1; /* Calculation is complete. */
2479 break;
2481 default:
2482 assert(FALSE);
2485 if (complete) {
2486 if ((v->modetype != SCIENTIFIC) ||
2487 (v->dtype == FIX && v->base == DEC)) {
2488 immediate = 1;
2492 if (immediate) {
2493 v->modetype = mode;
2494 reset_mode_display();
2495 do_mode(FALSE);
2496 } else if (request_change_mode()) {
2497 change_mode(mode);
2502 /*ARGSUSED*/
2503 static void
2504 accuracy_radio_cb(GtkWidget *widget)
2506 int count;
2508 count = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "accuracy"));
2510 if (v->started &&
2511 gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) {
2512 do_accuracy(count);
2517 /*ARGSUSED*/
2518 static void
2519 accuracy_other_cb(GtkWidget *widget)
2521 if (v->started) {
2522 show_precision_frame();
2527 /*ARGSUSED*/
2528 static void
2529 show_trailing_zeroes_cb(GtkWidget *widget)
2531 gboolean visible;
2533 visible = gtk_check_menu_item_get_active(
2534 GTK_CHECK_MENU_ITEM(widget));
2535 if (v->started) {
2536 ui_set_show_trailing_zeroes(visible);
2541 /*ARGSUSED*/
2542 static void
2543 quit_cb(GtkWidget *widget)
2545 save_win_position();
2546 gtk_main_quit();
2550 /*ARGSUSED*/
2551 static void
2552 spframe_cancel_cb(GtkButton *button)
2554 gtk_widget_hide(X->spframe);
2558 /*ARGSUSED*/
2559 static gboolean
2560 spframe_key_cb(GtkWidget *widget, GdkEventKey *event)
2562 if (event->keyval == GDK_minus) {
2563 ui_set_statusbar(_("Accuracy value out of range"),
2564 "gtk-dialog-error");
2565 ui_beep();
2566 } else if (event->keyval == GDK_Escape) {
2567 gtk_widget_hide(X->spframe);
2570 return(FALSE);
2574 /*ARGSUSED*/
2575 static void
2576 spframe_ok_cb(GtkButton *button)
2578 int val = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(X->spframe_val));
2580 v->accuracy = val;
2582 set_int_resource(R_ACCURACY, v->accuracy);
2584 ui_set_accuracy(v->accuracy);
2586 ui_make_registers();
2587 refresh_display();
2589 gtk_widget_hide(X->spframe);
2593 /*ARGSUSED*/
2594 void
2595 trig_cb(GtkWidget *widget)
2597 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
2598 do_trigtype((enum trig_type) g_object_get_data(G_OBJECT(widget),
2599 "trig_mode"));
2603 void
2604 ui_start()
2606 struct exprm_state *e;
2608 v->started = 1;
2609 ui_set_base(v->base);
2610 ui_set_trigonometric_mode(v->ttype);
2611 ui_set_numeric_mode(v->dtype);
2613 gtk_widget_show(X->kframe);
2615 switch (v->syntax) {
2616 case NPA:
2617 break;
2619 case EXPRS:
2620 /* Init expression mode.
2621 * This must be executed after do_base is called at init.
2622 * FIXME: The init code here is duplicated elsewhere.
2624 e = get_state();
2625 MPstr_to_num("0", DEC, e->ans);
2626 exp_del();
2627 show_display(e->ans);
2628 break;
2630 default:
2631 assert(0);
2634 gtk_main();
2638 /*ARGSUSED*/
2639 static void
2640 show_thousands_separator_cb(GtkWidget *widget)
2642 gboolean visible;
2644 visible = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget));
2645 if (v->started) {
2646 ui_set_show_thousands_seperator(visible);
2651 /*ARGSUSED*/
2652 static void
2653 edit_constants_cb(GtkMenuItem *item)
2655 gtk_widget_show(X->con_dialog);
2659 /*ARGSUSED*/
2660 static void
2661 edit_functions_cb(GtkMenuItem *item)
2663 gtk_widget_show(X->fun_dialog);
2667 static void
2668 create_kframe()
2670 int i;
2671 char name[MAXLINE];
2672 GtkWidget *widget;
2673 PangoFontDescription *font_desc;
2674 GtkSizeGroup *size_group;
2675 GtkAccelGroup *accel_group;
2676 GtkWidget *treeview;
2678 X->ui = glade_xml_new(UI_FILE, NULL, NULL);
2679 if (X->ui == NULL) {
2680 GtkWidget *dialog;
2682 dialog = gtk_message_dialog_new(NULL, 0,
2683 GTK_MESSAGE_ERROR,
2684 GTK_BUTTONS_NONE,
2685 N_("Error loading user interface"));
2686 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
2687 N_("The user interace file %s is missing or unable to be loaded. Please check your installation."), UI_FILE);
2688 gtk_dialog_add_buttons(GTK_DIALOG(dialog), GTK_STOCK_QUIT, GTK_RESPONSE_ACCEPT, NULL);
2690 gtk_dialog_run(GTK_DIALOG(dialog));
2691 exit(0);
2694 /* When connecting up signals, would ideally use autoconnect but not
2695 * sure how to get the build process working.
2696 * See http://library.gnome.org/devel/libglade/unstable and
2697 * http://www.jamesh.id.au/software/libglade/
2698 * for some information on how to get this to work
2699 * glade_xml_signal_autoconnect(X->ui);
2701 CONNECT_SIGNAL(kframe_key_press_cb);
2702 CONNECT_SIGNAL(button_cb);
2703 CONNECT_SIGNAL(menu_item_select_cb);
2704 CONNECT_SIGNAL(menu_item_deselect_cb);
2705 CONNECT_SIGNAL(mode_radio_cb);
2706 CONNECT_SIGNAL(inv_cb);
2707 CONNECT_SIGNAL(hyp_cb);
2708 CONNECT_SIGNAL(trig_cb);
2709 CONNECT_SIGNAL(base_cb);
2710 CONNECT_SIGNAL(disp_cb);
2711 CONNECT_SIGNAL(quit_cb);
2712 CONNECT_SIGNAL(edit_cb);
2713 CONNECT_SIGNAL(copy_cb);
2714 CONNECT_SIGNAL(paste_cb);
2715 CONNECT_SIGNAL(insert_ascii_cb);
2716 CONNECT_SIGNAL(undo_cb);
2717 CONNECT_SIGNAL(redo_cb);
2718 CONNECT_SIGNAL(help_cb);
2719 CONNECT_SIGNAL(about_cb);
2720 CONNECT_SIGNAL(show_trailing_zeroes_cb);
2721 CONNECT_SIGNAL(show_thousands_separator_cb);
2722 CONNECT_SIGNAL(show_bitcalculating_cb);
2723 CONNECT_SIGNAL(show_registers_cb);
2724 CONNECT_SIGNAL(accuracy_radio_cb);
2725 CONNECT_SIGNAL(accuracy_other_cb);
2726 CONNECT_SIGNAL(constant_menu_cb);
2727 CONNECT_SIGNAL(function_menu_cb);
2728 CONNECT_SIGNAL(store_menu_cb);
2729 CONNECT_SIGNAL(recall_menu_cb);
2730 CONNECT_SIGNAL(exchange_menu_cb);
2731 CONNECT_SIGNAL(arithmetic_mode_cb);
2732 CONNECT_SIGNAL(mouse_button_cb);
2733 CONNECT_SIGNAL(display_focus_in_cb);
2734 CONNECT_SIGNAL(display_focus_out_cb);
2735 /* Detect when populating the right-click menu to enable pasting */
2736 CONNECT_SIGNAL(buffer_populate_popup_cb);
2737 CONNECT_SIGNAL(shift_cb);
2738 CONNECT_SIGNAL(bit_toggle_cb);
2739 CONNECT_SIGNAL(aframe_delete_cb);
2740 CONNECT_SIGNAL(aframe_ok_cb);
2741 CONNECT_SIGNAL(aframe_cancel_cb);
2742 CONNECT_SIGNAL(aframe_key_cb);
2743 CONNECT_SIGNAL(spframe_delete_cb);
2744 CONNECT_SIGNAL(spframe_ok_cb);
2745 CONNECT_SIGNAL(spframe_cancel_cb);
2746 CONNECT_SIGNAL(spframe_key_cb);
2747 CONNECT_SIGNAL(rframe_delete_cb);
2748 CONNECT_SIGNAL(rframe_response_cb);
2749 CONNECT_SIGNAL(edit_constants_cb);
2750 CONNECT_SIGNAL(edit_functions_cb);
2751 CONNECT_SIGNAL(edit_constants_response_cb);
2752 CONNECT_SIGNAL(edit_functions_response_cb);
2754 X->clipboard_atom = gdk_atom_intern("CLIPBOARD", FALSE);
2755 X->primary_atom = gdk_atom_intern("PRIMARY", FALSE);
2756 X->kframe = GET_WIDGET("calc_window");
2757 X->aframe = GET_WIDGET("ascii_window");
2758 X->aframe_ch = GET_WIDGET("ascii_entry");
2759 X->spframe = GET_WIDGET("precision_dialog");
2760 X->spframe_val = GET_WIDGET("spframe_spin");
2761 X->rframe = GET_WIDGET("register_dialog");
2762 X->con_dialog = GET_WIDGET("edit_constants_dialog");
2763 X->fun_dialog = GET_WIDGET("edit_functions_dialog");
2764 X->menubar = GET_WIDGET("menubar");
2765 X->scrolledwindow = GET_WIDGET("display_scroll"),
2766 X->display_item = GET_WIDGET("displayitem"),
2767 X->bas_panel = GET_WIDGET("basic_panel");
2768 X->sci_panel = GET_WIDGET("scientific_panel");
2769 X->adv_panel = GET_WIDGET("advanced_panel");
2770 X->fin_panel = GET_WIDGET("financial_panel");
2771 X->bit_panel = GET_WIDGET("bit_panel");
2772 X->clear_buttons[0] = GET_WIDGET("calc_clear_simple_button");
2773 X->clear_buttons[1] = GET_WIDGET("calc_clear_advanced_button");
2774 X->mode_panel = GET_WIDGET("mode_panel");
2775 X->trig[0] = GET_WIDGET("degrees_radio");
2776 X->trig[1] = GET_WIDGET("gradians_radio");
2777 X->trig[2] = GET_WIDGET("radians_radio");
2778 X->base[0] = GET_WIDGET("binary_radio");
2779 X->base[1] = GET_WIDGET("octal_radio");
2780 X->base[2] = GET_WIDGET("decimal_radio");
2781 X->base[3] = GET_WIDGET("hexadecimal_radio");
2782 X->disp[0] = GET_WIDGET("engineering_radio");
2783 X->disp[1] = GET_WIDGET("fixed_point_radio");
2784 X->disp[2] = GET_WIDGET("scientific_radio");
2785 X->inverse_toggle = GET_WIDGET("inverse_check");
2786 X->hyperbolic_toggle = GET_WIDGET("hyperbolic_check");
2787 X->statusbar = GET_WIDGET("statusbar");
2788 for (i = 0; i < 16; i++) {
2789 SNPRINTF(name, MAXLINE, "calc_%x_button", i);
2790 X->digit_buttons[i] = GET_WIDGET(name);
2792 for (i = 0; i < MAX_REGISTERS; i++) {
2793 SNPRINTF(name, MAXLINE, "register_entry_%d", i);
2794 X->regs[i] = GET_WIDGET(name);
2797 /* Load buttons and set them all to be the same size */
2798 size_group = gtk_size_group_new(GTK_SIZE_GROUP_BOTH);
2799 for (i = 0; i < NBUTTONS; i++) {
2800 SNPRINTF(name, MAXLINE, "calc_%s_button",
2801 button_widgets[i].widget_name);
2802 X->buttons[i] = GET_WIDGET(name);
2803 assert(X->buttons[i] != NULL);
2805 gtk_size_group_add_widget(size_group, X->buttons[i]);
2807 g_object_set_data(G_OBJECT(X->buttons[i]), "calc_function",
2808 GINT_TO_POINTER(button_widgets[i].key));
2811 /* Make popup buttons */
2812 g_object_set_data(G_OBJECT(GET_WIDGET("calc_accuracy_button")),
2813 "calc_menu", GET_WIDGET("accuracy_popup"));
2814 g_object_set_data(G_OBJECT(GET_WIDGET("calc_shift_left_button")),
2815 "calc_menu", GET_WIDGET("left_shift_popup"));
2816 g_object_set_data(G_OBJECT(GET_WIDGET("calc_shift_right_button")),
2817 "calc_menu", GET_WIDGET("right_shift_popup"));
2819 g_object_set_data(G_OBJECT(GET_WIDGET("calc_constants_button")),
2820 "calc_menu", GET_WIDGET("constants_popup"));
2821 for (i = 0; i < MAX_CONSTANTS; i++) {
2822 SNPRINTF(name, MAXLINE, "constant_menu_item%d", i);
2823 widget = GET_WIDGET(name);
2824 g_object_set_data(G_OBJECT(widget), "constant_id", GINT_TO_POINTER(i));
2825 X->constant_menu_labels[i] = gtk_bin_get_child(GTK_BIN(widget));
2828 g_object_set_data(G_OBJECT(GET_WIDGET("calc_functions_button")),
2829 "calc_menu", GET_WIDGET("functions_popup"));
2830 for (i = 0; i < MAX_FUNCTIONS; i++) {
2831 SNPRINTF(name, MAXLINE, "function_menu_item%d", i);
2832 widget = GET_WIDGET(name);
2833 g_object_set_data(G_OBJECT(widget), "function_id", GINT_TO_POINTER(i));
2834 X->function_menu_labels[i] = gtk_bin_get_child(GTK_BIN(widget));
2837 g_object_set_data(G_OBJECT(GET_WIDGET("calc_store_button")),
2838 "calc_menu", GET_WIDGET("memory_store_popup"));
2839 g_object_set_data(G_OBJECT(GET_WIDGET("calc_recall_button")),
2840 "calc_menu", GET_WIDGET("memory_recall_popup"));
2841 g_object_set_data(G_OBJECT(GET_WIDGET("calc_exchange_button")),
2842 "calc_menu", GET_WIDGET("memory_exchange_popup"));
2843 for (i = 0; i < MAX_REGISTERS; i++) {
2844 SNPRINTF(name, MAXLINE, "store_menu_item%d", i);
2845 widget = GET_WIDGET(name);
2846 g_object_set_data(G_OBJECT(widget), "register_id", GINT_TO_POINTER(i));
2847 X->memory_store_labels[i] = gtk_bin_get_child(GTK_BIN(widget));
2849 SNPRINTF(name, MAXLINE, "recall_menu_item%d", i);
2850 widget = GET_WIDGET(name);
2851 g_object_set_data(G_OBJECT(widget), "register_id", GINT_TO_POINTER(i));
2852 X->memory_recall_labels[i] = gtk_bin_get_child(GTK_BIN(widget));
2854 SNPRINTF(name, MAXLINE, "exchange_menu_item%d", i);
2855 widget = GET_WIDGET(name);
2856 g_object_set_data(G_OBJECT(widget), "register_id", GINT_TO_POINTER(i));
2857 X->memory_exchange_labels[i] = gtk_bin_get_child(GTK_BIN(widget));
2860 /* Load bit panel */
2861 for (i = 0; i < MAXBITS; i++)
2863 SNPRINTF(name, MAXLINE, "bit_label_%d", i);
2864 X->bits[i] = GET_WIDGET(name);
2865 SNPRINTF(name, MAXLINE, "bit_eventbox_%d", i);
2866 g_object_set_data(G_OBJECT(GET_WIDGET(name)),
2867 "bit_index", GINT_TO_POINTER(i));
2870 /* Make menu tooltips displayed in the status bar */
2871 set_menubar_tooltip("quit_menu");
2872 set_menubar_tooltip("copy_menu");
2873 set_menubar_tooltip("paste_menu");
2874 set_menubar_tooltip("insert_ascii_menu");
2875 set_menubar_tooltip("undo_menu");
2876 set_menubar_tooltip("redo_menu");
2877 set_menubar_tooltip("view_basic_menu");
2878 set_menubar_tooltip("view_advanced_menu");
2879 set_menubar_tooltip("view_financial_menu");
2880 set_menubar_tooltip("view_scientific_menu");
2881 set_menubar_tooltip("show_trailing_zeroes_menu");
2882 set_menubar_tooltip("show_thousands_separator_menu");
2883 set_menubar_tooltip("show_bitcalculating_menu");
2884 set_menubar_tooltip("show_registers_menu");
2885 set_menubar_tooltip("ltr_precedence_menu");
2886 set_menubar_tooltip("arithmetic_precedence_menu");
2887 set_menubar_tooltip("help_menu");
2888 set_menubar_tooltip("about_menu");
2890 // ???
2891 widget = GET_WIDGET("kvbox");
2892 gtk_widget_set_direction(widget, GTK_TEXT_DIR_LTR);
2893 gtk_widget_set_direction(X->fin_panel, GTK_TEXT_DIR_LTR);
2895 /* Make dialogs transient of the main window */
2896 gtk_window_set_transient_for(GTK_WINDOW(X->aframe), GTK_WINDOW(X->kframe));
2897 gtk_window_set_transient_for(GTK_WINDOW(X->spframe), GTK_WINDOW(X->kframe));
2898 gtk_window_set_transient_for(GTK_WINDOW(X->rframe), GTK_WINDOW(X->kframe));
2899 gtk_window_set_transient_for(GTK_WINDOW(X->con_dialog),
2900 GTK_WINDOW(X->kframe));
2902 gtk_spin_button_set_value(GTK_SPIN_BUTTON(X->spframe_val),
2903 (double) v->accuracy); // FIXME
2904 gtk_entry_set_max_length(GTK_ENTRY(X->spframe_val), 2);
2906 gtk_dialog_set_default_response(GTK_DIALOG(X->con_dialog),
2907 GTK_RESPONSE_ACCEPT);
2909 /* Make constant tree model */
2910 X->constants_model = create_constants_model();
2911 treeview = GET_WIDGET("edit_constants_treeview");
2912 gtk_tree_view_set_model(GTK_TREE_VIEW(treeview), X->constants_model);
2913 gtk_tree_selection_set_mode(
2914 gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)),
2915 GTK_SELECTION_SINGLE);
2916 add_cf_column(GTK_TREE_VIEW(treeview), _("No."),
2917 COLUMN_NUMBER, FALSE);
2918 add_cf_column(GTK_TREE_VIEW(treeview), _("Value"),
2919 COLUMN_VALUE, TRUE);
2920 add_cf_column(GTK_TREE_VIEW(treeview), _("Description"),
2921 COLUMN_DESCRIPTION, TRUE);
2923 /* Make function tree model */
2924 X->functions_model = create_functions_model();
2925 treeview = GET_WIDGET("edit_functions_treeview");
2926 gtk_dialog_set_default_response(GTK_DIALOG(X->fun_dialog),
2927 GTK_RESPONSE_ACCEPT);
2928 gtk_window_set_transient_for(GTK_WINDOW(X->fun_dialog),
2929 GTK_WINDOW(X->kframe));
2930 gtk_tree_view_set_model(GTK_TREE_VIEW(treeview), X->functions_model);
2931 gtk_tree_selection_set_mode(
2932 gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)),
2933 GTK_SELECTION_SINGLE);
2934 add_cf_column(GTK_TREE_VIEW(treeview), _("No."),
2935 COLUMN_NUMBER, FALSE);
2936 add_cf_column(GTK_TREE_VIEW(treeview), _("Value"),
2937 COLUMN_VALUE, TRUE);
2938 add_cf_column(GTK_TREE_VIEW(treeview), _("Description"),
2939 COLUMN_DESCRIPTION, TRUE);
2942 X->display_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(X->display_item));
2943 gtk_widget_ensure_style(X->display_item);
2944 font_desc = pango_font_description_copy(X->display_item->style->font_desc);
2945 pango_font_description_set_size(font_desc, 16 * PANGO_SCALE);
2946 gtk_widget_modify_font(X->display_item, font_desc);
2947 pango_font_description_free(font_desc);
2948 gtk_widget_set_name(X->display_item, "displayitem");
2949 // FIXME: We can't allow the display to be editable. See bug #326938
2950 gtk_text_view_set_editable(GTK_TEXT_VIEW(X->display_item),
2951 (v->syntax == EXPRS));
2952 atk_object_set_role(gtk_widget_get_accessible(X->display_item),
2953 ATK_ROLE_EDITBAR);
2955 gtk_widget_realize(X->kframe);
2956 set_win_position();
2958 for (i = 0; i < 3; i++)
2959 g_object_set_data(G_OBJECT(X->trig[i]),
2960 "trig_mode", GINT_TO_POINTER(i));
2961 for (i = 0; i < 4; i++)
2962 g_object_set_data(G_OBJECT(X->base[i]),
2963 "base_mode", GINT_TO_POINTER(i));
2964 for (i = 0; i < 3; i++)
2965 g_object_set_data(G_OBJECT(X->disp[i]),
2966 "numeric_mode", GINT_TO_POINTER(i));
2968 /* Put status image into statusbar (glade doesn't support child widgets
2969 * in statusbars) */
2970 X->status_image = gtk_image_new_from_stock("", GTK_ICON_SIZE_BUTTON);
2971 gtk_widget_show(X->status_image);
2972 gtk_box_pack_start(GTK_BOX(X->statusbar), X->status_image, FALSE, TRUE, 0);
2974 /* Set modes for menu items */
2975 for (i = 1; i < 16; i++) {
2976 SNPRINTF(name, MAXLINE, "shift_left%d_menu", i);
2977 g_object_set_data(G_OBJECT(GET_WIDGET(name)),
2978 "shiftcount", GINT_TO_POINTER(i));
2979 SNPRINTF(name, MAXLINE, "shift_right%d_menu", i);
2980 g_object_set_data(G_OBJECT(GET_WIDGET(name)),
2981 "shiftcount", GINT_TO_POINTER(-i));
2983 g_object_set_data(G_OBJECT(GET_WIDGET("view_basic_menu")),
2984 "calcmode", GINT_TO_POINTER(BASIC));
2985 g_object_set_data(G_OBJECT(GET_WIDGET("view_advanced_menu")),
2986 "calcmode", GINT_TO_POINTER(ADVANCED));
2987 g_object_set_data(G_OBJECT(GET_WIDGET("view_financial_menu")),
2988 "calcmode", GINT_TO_POINTER(FINANCIAL));
2989 g_object_set_data(G_OBJECT(GET_WIDGET("view_scientific_menu")),
2990 "calcmode", GINT_TO_POINTER(SCIENTIFIC));
2992 /* Make shortcuts for accuracy menus */
2993 accel_group = gtk_accel_group_new();
2994 gtk_window_add_accel_group(GTK_WINDOW(X->kframe), accel_group);
2995 for (i = 0; i < 10; i++) {
2996 SNPRINTF(name, MAXLINE, "acc_item%d", i);
2997 widget = GET_WIDGET(name);
2998 g_object_set_data(G_OBJECT(widget), "accuracy", GINT_TO_POINTER(i));
3003 static void
3004 read_cfdefs() /* Read constant/function definitions. */
3006 int n;
3008 for (n = 0; n < MAX_CONSTANTS; n++) {
3009 get_constant(n);
3011 for (n = 0; n < MAX_FUNCTIONS; n++) {
3012 STRCPY(v->fun_vals[n], ""); /* Initially empty function strings. */
3013 get_function(n);
3018 void
3019 ui_init(int *argc, char ***argv)
3021 X = (XVars) LINT_CAST(calloc(1, sizeof(struct Xobject)));
3023 gtk_init(argc, argv);
3025 X->lnp = ui_get_localized_numeric_point();
3027 gtk_rc_get_default_files();
3029 v->home = (char *) g_get_home_dir();
3030 gtk_rc_parse(g_build_path(v->home, RCNAME, NULL));
3032 gtk_window_set_default_icon_name("gnome-calculator");
3035 void
3036 ui_load()
3038 int boolval;
3040 read_cfdefs();
3042 /* Create main gcalctool window. */
3043 create_kframe();
3045 ui_set_show_thousands_seperator(v->show_tsep);
3046 ui_set_show_trailing_zeroes(v->show_zeroes);
3047 ui_set_show_bitcalculating(v->bitcalculating_mode);
3049 ui_set_syntax_mode(v->syntax);
3050 ui_set_display("0.00", FALSE);
3051 ui_set_mode(v->modetype);
3052 ui_set_numeric_mode(FIX);
3053 ui_set_base(v->base);
3054 ui_set_accuracy(v->accuracy);
3055 ui_set_undo_enabled(FALSE, FALSE);
3056 ui_update_trig_mode();
3058 /* Show the memory register window? */
3059 ui_make_registers();
3060 if (get_boolean_resource(R_REGS, &boolval))
3061 ui_set_registers_visible(boolval);
3063 /* Focus on the clear button */
3064 if (v->modetype == BASIC) {
3065 gtk_window_set_focus(GTK_WINDOW(X->kframe),
3066 GTK_WIDGET(X->clear_buttons[0]));
3067 } else {
3068 gtk_window_set_focus(GTK_WINDOW(X->kframe),
3069 GTK_WIDGET(X->clear_buttons[1]));