simplify change mode
[gcalctool.git] / gcalctool / gtk.c
blobb09a6510babccbafd723af53a95d784ae7742e1d
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 /* Popup menu types. */
46 /* FIXME: This enum could be removed */
47 enum menu_type { M_ACC, M_CON, M_EXCH, M_FUN, M_LSHF,
48 M_RCL, M_RSHF, M_STO, M_NONE };
49 #define MAXMENUS 9 /* Maximum number of popup menus. */
51 #define MAX_ACCELERATORS 8
52 struct button_widget {
53 int key;
54 char *widget_name;
55 enum menu_type mtype;
56 guint accelerator_mods[MAX_ACCELERATORS];
57 guint accelerator_keys[MAX_ACCELERATORS];
60 /* Window titles dependant on mode */
61 static char *titles[] = {
62 N_("Calculator"), N_("Calculator - Advanced"), N_("Calculator - Financial"),
63 N_("Calculator - Scientific")
66 /* Window titles dependant on mode and hostname */
67 static char *hostname_titles[] = {
68 N_("Calculator [%s]"), N_("Calculator [%s] - Advanced"), N_("Calculator [%s] - Financial"),
69 N_("Calculator [%s] - Scientific")
72 /* This table shows the keyboard values that are currently being used:
74 * | 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
75 *-----------+-----------------------------------------------------
76 * Lower: | a b c d e f i l m n p r s t u v x
77 * Upper: | A C D E F G J K L M N P R S T X Y
78 * Numeric: | 0 1 2 3 4 5 6 7 8 9
79 * Other: | @ . + - * / = % ( ) # < > [ ] { } | & ~ ^ ? ! :
80 * | BackSpace Delete Return
81 *-----------+-----------------------------------------------------
84 static struct button_widget button_widgets[] = {
85 {KEY_0, "0", M_NONE,
86 { 0, GDK_SHIFT_MASK, 0, 0, 0 },
87 { GDK_0, GDK_0, GDK_KP_0, GDK_KP_Insert, 0 }},
89 {KEY_1, "1", M_NONE,
90 { 0, GDK_SHIFT_MASK, 0, 0, 0, 0 },
91 { GDK_1, GDK_1, GDK_KP_1, GDK_KP_End, GDK_R13, 0 }},
93 {KEY_2, "2", M_NONE,
94 { 0, GDK_SHIFT_MASK, 0, 0, 0 },
95 { GDK_2, GDK_2, GDK_KP_2, GDK_KP_Down, 0 }},
97 {KEY_3, "3", M_NONE,
98 { 0, GDK_SHIFT_MASK, 0, 0, 0, 0 },
99 { GDK_3, GDK_3, GDK_KP_3, GDK_KP_Page_Down, GDK_R15, 0 }},
101 {KEY_4, "4", M_NONE,
102 { 0, GDK_SHIFT_MASK, 0, 0, 0 },
103 { GDK_4, GDK_4, GDK_KP_4, GDK_KP_Left, 0 }},
105 {KEY_5, "5", M_NONE,
106 { 0, GDK_SHIFT_MASK, 0, 0, 0, 0 },
107 { GDK_5, GDK_5, GDK_KP_5, GDK_KP_Begin, GDK_R11, 0 }},
109 {KEY_6, "6", M_NONE,
110 { 0, GDK_SHIFT_MASK, 0, 0, 0 },
111 { GDK_6, GDK_6, GDK_KP_6, GDK_KP_Right, 0 }},
113 {KEY_7, "7", M_NONE,
114 { 0, GDK_SHIFT_MASK, 0, 0, 0, 0 },
115 { GDK_7, GDK_7, GDK_KP_7, GDK_KP_Home, GDK_R7, 0 }},
117 {KEY_8, "8", M_NONE,
118 { 0, GDK_SHIFT_MASK, 0, 0, 0 },
119 { GDK_8, GDK_8, GDK_KP_8, GDK_KP_Up, 0 }},
121 {KEY_9, "9", M_NONE,
122 { 0, GDK_SHIFT_MASK, 0, 0, 0, 0 },
123 { GDK_9, GDK_9, GDK_KP_9, GDK_KP_Page_Up, GDK_R9, 0 }},
125 {KEY_A, "a", M_NONE,
126 { 0, 0 },
127 { GDK_a, 0 }},
129 {KEY_B, "b", M_NONE,
130 { 0, 0 },
131 { GDK_b, 0 }},
133 {KEY_C, "c", M_NONE,
134 { 0, 0 },
135 { GDK_c, 0 }},
137 {KEY_D, "d", M_NONE,
138 { 0, 0 },
139 { GDK_d, 0 }},
141 {KEY_E, "e", M_NONE,
142 { 0, 0 },
143 { GDK_e, 0 }},
145 {KEY_F, "f", M_NONE,
146 { 0, 0 },
147 { GDK_f, 0 }},
149 {KEY_CLEAR, "clear_simple", M_NONE,
150 { 0, 0 },
151 { GDK_Delete, 0 }},
153 {KEY_CLEAR, "clear_advanced", M_NONE,
154 { 0, 0 },
155 { GDK_Delete, 0 }},
157 {KEY_LEFT_SHIFT, "shift_left", M_LSHF,
158 { GDK_SHIFT_MASK, 0 },
159 { GDK_less, 0 }},
161 {KEY_RIGHT_SHIFT, "shift_right", M_RSHF,
162 { GDK_SHIFT_MASK, 0 },
163 { GDK_greater, 0 }},
165 {KEY_SET_ACCURACY, "accuracy", M_ACC,
166 { GDK_SHIFT_MASK, 0 },
167 { GDK_A, 0 }},
169 {KEY_CONSTANT, "constants", M_CON,
170 { GDK_SHIFT_MASK, 0, 0 },
171 { GDK_numbersign, GDK_numbersign, 0 }},
173 {KEY_FUNCTION, "functions", M_FUN,
174 { GDK_SHIFT_MASK, 0 },
175 { GDK_F, 0 }},
177 {KEY_STORE, "store", M_STO,
178 { GDK_SHIFT_MASK, 0 },
179 { GDK_S, 0 }},
181 {KEY_RECALL, "recall", M_RCL,
182 { GDK_SHIFT_MASK, 0 },
183 { GDK_R, 0 }},
185 {KEY_EXCHANGE, "exchange", M_EXCH,
186 { GDK_SHIFT_MASK, 0 },
187 { GDK_X, 0 }},
189 {KEY_CLEAR_ENTRY, "clear_entry_simple", M_NONE,
190 { GDK_CONTROL_MASK, 0, 0 },
191 { GDK_BackSpace, GDK_Escape, 0 }},
193 {KEY_CLEAR_ENTRY, "clear_entry_advanced", M_NONE,
194 { GDK_CONTROL_MASK, 0, 0 },
195 { GDK_BackSpace, GDK_Escape, 0 }},
197 {KEY_BACKSPACE, "backspace_simple", M_NONE,
198 { 0, 0 },
199 { GDK_BackSpace, 0 }},
201 {KEY_BACKSPACE, "backspace_advanced", M_NONE,
202 { 0, 0 },
203 { GDK_BackSpace, 0 }},
205 {KEY_NUMERIC_POINT, "numeric_point", M_NONE,
206 { 0, 0, 0, 0 },
207 { GDK_period, GDK_KP_Decimal, GDK_KP_Delete, GDK_KP_Separator, 0 }},
209 {KEY_CALCULATE, "result", M_NONE,
210 { 0, 0, 0, GDK_SHIFT_MASK, 0 },
211 { GDK_equal, GDK_KP_Enter, GDK_Return, GDK_equal, 0 }},
213 {KEY_START_BLOCK, "start_group", M_NONE,
214 { GDK_SHIFT_MASK, 0 },
215 { GDK_parenleft, 0 }},
217 {KEY_END_BLOCK, "end_group", M_NONE,
218 { GDK_SHIFT_MASK, 0 },
219 { GDK_parenright, 0 }},
221 {KEY_ADD, "add", M_NONE,
222 { GDK_SHIFT_MASK, 0, 0, 0 },
223 { GDK_plus, GDK_plus, GDK_KP_Add, 0 }},
225 {KEY_SUBTRACT, "subtract", M_NONE,
226 { 0, 0, 0, 0 },
227 { GDK_minus, GDK_KP_Subtract, GDK_R4, 0 }},
229 {KEY_MULTIPLY, "multiply", M_NONE,
230 { GDK_SHIFT_MASK, 0, 0, 0, 0 },
231 { GDK_asterisk, GDK_KP_Multiply, GDK_x, GDK_R6, 0 }},
233 {KEY_DIVIDE, "divide", M_NONE,
234 { 0, GDK_SHIFT_MASK, 0, 0, GDK_SHIFT_MASK, 0 },
235 { GDK_slash, GDK_slash, GDK_KP_Divide, GDK_R5, GDK_slash, 0 }},
237 {KEY_CHANGE_SIGN, "change_sign_simple", M_NONE,
238 { GDK_SHIFT_MASK, 0 },
239 { GDK_C, 0 }},
241 {KEY_CHANGE_SIGN, "change_sign_advanced", M_NONE,
242 { GDK_SHIFT_MASK, 0 },
243 { GDK_C, 0 }},
245 {KEY_INTEGER, "integer_portion", M_NONE,
246 { 0, 0 },
247 { GDK_i, 0 }},
249 {KEY_FRACTION, "fractional_portion", M_NONE,
250 { GDK_SHIFT_MASK, 0 },
251 { GDK_colon, 0 }},
253 {KEY_PERCENTAGE, "percentage", M_NONE,
254 { GDK_SHIFT_MASK, 0 },
255 { GDK_percent, 0 }},
257 {KEY_SQUARE, "square", M_NONE,
258 { GDK_SHIFT_MASK, 0 },
259 { GDK_at, 0 }},
261 {KEY_SQUARE_ROOT, "sqrt", M_NONE,
262 { 0, 0 },
263 { GDK_s, 0 }},
265 {KEY_RECIPROCAL, "reciprocal", M_NONE,
266 { 0, 0 },
267 { GDK_r, 0 }},
269 {KEY_ABSOLUTE_VALUE, "abs", M_NONE,
270 { 0, 0 },
271 { GDK_u, 0 }},
273 {KEY_MASK_16, "mask_16", M_NONE,
274 { 0, 0 },
275 { GDK_bracketright, 0 }},
277 {KEY_MASK_32, "mask_32", M_NONE,
278 { 0, 0 },
279 { GDK_bracketleft, 0 }},
281 {KEY_MODULUS_DIVIDE, "modulus_divide", M_NONE,
282 { GDK_SHIFT_MASK, 0 },
283 { GDK_M, 0 }},
285 {KEY_EXPONENTIAL, "exponential", M_NONE,
286 { GDK_SHIFT_MASK, 0 },
287 { GDK_E, 0 }},
289 {KEY_E_POW_X, "pow_e", M_NONE,
290 { GDK_SHIFT_MASK, 0 },
291 { GDK_braceleft, 0 }},
293 {KEY_10_POW_X, "pow_10", M_NONE,
294 { GDK_SHIFT_MASK, 0 },
295 { GDK_braceright, 0 }},
297 {KEY_X_POW_Y, "x_pow_y", M_NONE,
298 { GDK_SHIFT_MASK, GDK_SHIFT_MASK, 0 },
299 { GDK_caret, GDK_asciicircum, 0 }},
301 {KEY_NATURAL_LOGARITHM, "natural_logarithm", M_NONE,
302 { GDK_SHIFT_MASK, 0 },
303 { GDK_N, 0 }},
305 {KEY_LOGARITHM, "logarithm", M_NONE,
306 { GDK_SHIFT_MASK, 0 },
307 { GDK_G, 0 }},
309 {KEY_FACTORIAL, "factorial", M_NONE,
310 { GDK_SHIFT_MASK, 0 },
311 { GDK_exclam, 0 }},
313 {KEY_RANDOM, "random", M_NONE,
314 { GDK_SHIFT_MASK, 0 },
315 { GDK_question, 0 }},
317 {KEY_SINE, "sine", M_NONE,
318 { GDK_SHIFT_MASK, 0 },
319 { GDK_K, 0 }},
321 {KEY_COSINE, "cosine", M_NONE,
322 { GDK_SHIFT_MASK, 0 },
323 { GDK_J, 0 }},
325 {KEY_TANGENT, "tangent", M_NONE,
326 { GDK_SHIFT_MASK, 0 },
327 { GDK_L, 0 }},
329 {KEY_NOT, "not", M_NONE,
330 { GDK_SHIFT_MASK, 0 },
331 { GDK_asciitilde, 0 }},
333 {KEY_OR, "or", M_NONE,
334 { GDK_SHIFT_MASK, 0 },
335 { GDK_bar, 0 }},
337 {KEY_AND, "and", M_NONE,
338 { GDK_SHIFT_MASK, 0 },
339 { GDK_ampersand, 0 }},
341 {KEY_XOR, "xor", M_NONE,
342 { 0 },
343 { 0 }},
345 {KEY_XNOR, "xnor", M_NONE,
346 { 0, 0 },
347 { GDK_n, 0 }},
349 {KEY_FINC_CTRM, "finc_compounding_term", M_NONE,
350 { 0, 0 },
351 { GDK_m, 0 }},
353 {KEY_FINC_DDB, "finc_double_declining_depreciation", M_NONE,
354 { GDK_SHIFT_MASK, 0 },
355 { GDK_D, 0 }},
357 {KEY_FINC_FV, "finc_future_value", M_NONE,
358 { 0, 0 },
359 { GDK_v, 0 }},
361 {KEY_FINC_PMT, "finc_periodic_payment", M_NONE,
362 { GDK_SHIFT_MASK, 0 },
363 { GDK_P, 0 }},
365 {KEY_FINC_PV, "finc_present_value", M_NONE,
366 { 0, 0 },
367 { GDK_p, 0 }},
369 {KEY_FINC_RATE, "finc_periodic_interest_rate", M_NONE,
370 { GDK_SHIFT_MASK, 0 },
371 { GDK_T, 0 }},
373 {KEY_FINC_SLN, "finc_straight_line_depreciation", M_NONE,
374 { 0, 0 },
375 { GDK_l, 0 }},
377 {KEY_FINC_SYD, "finc_sum_of_the_years_digits_depreciation", M_NONE,
378 { 0, 0 },
379 { GDK_Y, 0 }},
381 {KEY_FINC_TERM, "finc_term", M_NONE,
382 { 0, 0 },
383 { GDK_T, 0 }},
385 #define NBUTTONS (sizeof(button_widgets) / sizeof(struct button_widget))
387 #define UI_FILE PACKAGE_GLADE_DIR "/gcalctool.glade"
389 #define MAXBITS 64 /* Bit panel: number of bit fields. */
391 #define GET_WIDGET(name) \
392 glade_xml_get_widget(X->ui, (name))
394 #define SET_MENUBAR_ITEM_STATE(name, state) \
395 g_object_set_data(G_OBJECT(GET_WIDGET(name)), "sensitive", \
396 GINT_TO_POINTER(state));
398 #define CONNECT_SIGNAL(name) glade_xml_signal_connect(X->ui, #name, \
399 G_CALLBACK(name))
401 struct Xobject { /* Gtk+/Xlib graphics object. */
402 GdkAtom clipboard_atom;
403 GdkAtom primary_atom;
405 GladeXML *ui;
407 GtkWidget *kframe; /* Main window. */
409 GtkWidget *cm_dialog; /* Change Mode dialog. */
410 GtkTreeModel *constants_model;
411 GtkWidget *con_dialog; /* Edit constants dialog. */
413 GtkTreeModel *functions_model;
414 GtkWidget *fun_dialog; /* Edit functions dialog. */
415 GtkWidget *menubar; // FIXME: Why is this needed?
417 GtkWidget *bit_panel;
418 GtkWidget *bits[MAXBITS]; /* The 0/1 labels in the bit panel. */
420 GtkWidget *status_image; /* Statusbar image */
421 GtkWidget *statusbar;
423 GtkWidget *undo; /* Undo menuitem */
424 GtkWidget *redo; /* Redo menuitem */
425 GtkWidget *copy; /* Copy menuitem */
426 GtkWidget *paste; /* Paste menuitem */
428 GtkWidget *aframe; /* ASCII window. */
429 GtkWidget *aframe_ch;
431 GtkWidget *display_item; /* Calculator display. */
432 GtkTextBuffer *display_buffer; /* Buffer used in display */
433 GtkWidget *scrolledwindow; /* Scrolled window for display_item. */
435 GtkWidget *rframe; /* Register window. */
436 GtkWidget *regs[MAXREGS]; /* Memory registers. */
438 GtkWidget *spframe; /* Set Precision window. */
439 GtkWidget *spframe_val;
440 GtkWidget *menus[MAXMENUS];
442 GtkWidget *buttons[NBUTTONS];
443 GtkWidget *digit_buttons[16];
444 GtkWidget *clear_buttons[2];
446 GtkWidget *bas_panel; /* Panel containing basic mode widgets. */
447 GtkWidget *adv_panel; /* Panel containing advanced mode widgets. */
448 GtkWidget *fin_panel; /* Panel containing financial mode widgets. */
449 GtkWidget *sci_panel; /* Panel containing scientific mode widgets. */
450 GtkWidget *mode_panel; /* Panel containing scientific mode widgets. */
452 /* Labels for popup menus */
453 GtkWidget *constant_menu_items[MAXCONFUN];
454 GtkWidget *function_menu_items[MAXCONFUN];
455 GtkWidget *memory_store_items[MAXREGS];
456 GtkWidget *memory_recall_items[MAXREGS];
457 GtkWidget *memory_exchange_items[MAXREGS];
459 /* Scientific mode widgets */
460 GtkWidget *hyp; /* Hyperbolic mode. */
461 GtkWidget *inv; /* Inverse mode. */
462 GtkWidget *base[MAXBASES]; /* Numeric base radio buttons. */
463 GtkWidget *disp[MAXDISPMODES]; /* Numeric display mode. */
464 GtkWidget *trig[MAXTRIGMODES]; /* Trigonometric mode. */
466 int mode; /* The new mode. */
467 int menuval; /* Index to button array at menu time. */
468 char *lnp; /* Localized numerical point (UTF8 format) */
469 struct button *mrec[MAXMENUS];
472 typedef struct Xobject *XVars;
474 enum {
475 COLUMN_NUMBER,
476 COLUMN_VALUE,
477 COLUMN_DESCRIPTION,
478 COLUMN_EDITABLE,
479 NUM_COLUMNS
482 static XVars X;
485 void
486 ui_set_statusbar(gchar *text, const gchar *imagename)
488 GtkImage *image = GTK_IMAGE(X->status_image);
490 assert(text);
491 assert(imagename);
492 assert(image);
494 gtk_image_set_from_stock(image, imagename, GTK_ICON_SIZE_BUTTON);
495 gtk_statusbar_pop(GTK_STATUSBAR(X->statusbar), 0);
496 gtk_statusbar_push(GTK_STATUSBAR(X->statusbar), 0, text);
500 static void
501 bin_str(int MP_value[MP_SIZE], char *str, int maxbits)
503 int i, MP0[MP_SIZE], MP1[MP_SIZE], MP2[MP_SIZE], MP3[MP_SIZE];
504 int neg = 0;
506 MPstr_to_num("0", DEC, MP0);
507 MPstr_to_num("1", DEC, MP1);
508 MPstr_to_num("2", DEC, MP2);
510 if (mplt(MP_value, MP0)) {
511 mpcmim(MP_value, MP0);
512 mpadd(MP0, MP1, MP0);
513 neg = 1;
514 } else {
515 mpcmim(MP_value, MP0);
518 for (i = 0; i < maxbits; i++) {
519 double lsb; /* Least significant bit. */
520 calc_and(MP3, MP0, MP1);
521 mpcmd(MP3, &lsb);
523 if (lsb == 0) {
524 str[maxbits - i -1] = (neg) ? '1' : '0';
525 } else {
526 str[maxbits - i -1] = (neg) ? '0' : '1';
529 mpdiv(MP0, MP2, MP3);
530 mpcmim(MP3, MP0);
533 return;
537 static void
538 set_bit_panel()
540 int bit_str_len, i, MP1[MP_SIZE], MP2[MP_SIZE];
541 int MP[MP_SIZE];
542 char str[64], label[3];
543 int ret = usable_num(MP);
545 switch (v->syntax) {
546 case npa:
547 MPstr_to_num(v->display, v->base, MP1);
548 mpcmim(MP1, MP2);
549 if (mpeq(MP1, MP2)) {
550 char *bit_str, label[3], tmp[MAXLINE];
551 int toclear = (v->current == KEY_CLEAR_ENTRY)
552 ? TRUE : FALSE;
554 bit_str = make_fixed(MP1, tmp, BIN, MAXLINE, toclear);
555 bit_str_len = strlen(bit_str);
556 if (bit_str_len <= MAXBITS) {
557 gtk_widget_set_sensitive(X->bit_panel, TRUE);
559 STRCPY(label, " 0");
560 for (i = 0; i < MAXBITS; i++) {
561 label[1] = (i < bit_str_len) ? bit_str[bit_str_len-i-1] : '0';
562 gtk_label_set_text(GTK_LABEL(X->bits[MAXBITS - i - 1]), label);
565 return;
568 gtk_widget_set_sensitive(X->bit_panel, FALSE);
569 break;
571 case exprs:
572 if (ret || !is_integer(MP)) {
573 gtk_widget_set_sensitive(X->bit_panel, FALSE);
574 return;
576 bin_str(MP, str, 64);
577 gtk_widget_set_sensitive(X->bit_panel, TRUE);
579 STRCPY(label, " 0");
580 for (i = 0; i < 64; i++) {
581 label[1] = str[64 - i - 1];
582 gtk_label_set_text(GTK_LABEL(X->bits[64 - i - 1]), label);
584 break;
589 static void
590 scroll_right()
592 if (!v->started) {
593 return;
596 if (GTK_WIDGET_VISIBLE(
597 GTK_SCROLLED_WINDOW(X->scrolledwindow)->hscrollbar)) {
598 GtkAdjustment *set;
600 set = gtk_scrolled_window_get_hadjustment(
601 GTK_SCROLLED_WINDOW(X->scrolledwindow));
602 gtk_adjustment_set_value(set, set->upper);
603 gtk_scrolled_window_set_hadjustment(
604 GTK_SCROLLED_WINDOW(X->scrolledwindow), set);
609 void
610 ui_set_display(char *str, int minimize_changes)
612 char localized[MAX_LOCALIZED];
613 GtkTextIter start, end;
614 gchar *text;
615 gint diff;
616 gint len1, len2;
617 gboolean done;
619 if (str == NULL || *str == 0) {
620 str = " ";
621 } else {
622 if (!v->noparens) {
623 localize_number(localized, str);
624 str = localized;
627 gtk_text_buffer_get_bounds(X->display_buffer, &start, &end);
628 text = gtk_text_buffer_get_text(X->display_buffer, &start, &end, TRUE);
629 diff = strcmp (text, str);
630 if (diff != 0) {
631 len1 = strlen(text);
632 len2 = strlen(str);
634 done = FALSE;
635 if (minimize_changes) {
636 if (len1 < len2 && strncmp(text, str, len1) == 0) {
637 /* Text insertion */
638 gtk_text_buffer_insert(X->display_buffer, &end, str + len1, -1);
639 done = TRUE;
640 } else if (len1 > len2 && strncmp(text, str, len2) == 0) {
641 /* Text deletion */
642 gtk_text_buffer_get_iter_at_offset (X->display_buffer, &start, len2);
643 gtk_text_buffer_delete(X->display_buffer, &start, &end);
644 done = TRUE;
648 if (!done) {
649 gtk_text_buffer_delete(X->display_buffer, &start, &end);
650 gtk_text_buffer_insert(X->display_buffer, &end, str, -1);
653 scroll_right();
654 g_free(text);
658 void
659 ui_write_display(char *str)
661 gchar *text;
662 GtkTextIter start, end;
664 if (str == NULL ) {
665 str = " ";
668 gtk_text_buffer_get_bounds(X->display_buffer, &start, &end);
669 text = gtk_text_buffer_get_text(X->display_buffer, &start, &end, TRUE);
671 gtk_text_buffer_delete(X->display_buffer, &start, &end);
673 gtk_text_buffer_insert(X->display_buffer, &end, str, -1);
674 scroll_right();
675 g_free(text);
679 /* When an error condition occurs:
681 * - make insensitive all buttons except Clr.
682 * - make all Scientific mode toggles and checkboxes insensitive.
683 * - make all menubar items insensitive except:
684 * Calculator->Quit
685 * Help->Contents
687 * When the error condition is cleared, resensitise everything, setting
688 * the numeric base buttons correctly.
691 void
692 ui_set_error_state(int error)
694 int i;
696 v->error = error;
698 for (i = 0; i < NBUTTONS; i++) {
699 gtk_widget_set_sensitive(X->buttons[i], !v->error);
701 /* Clr button always sensitive. */
702 gtk_widget_set_sensitive(X->clear_buttons[0], TRUE);
703 gtk_widget_set_sensitive(X->clear_buttons[1], TRUE);
705 if (!v->error) {
706 ui_set_base(v->base);
709 gtk_widget_set_sensitive(X->mode_panel, !v->error);
711 // FIXME: Isn't this missing a whole lot of widgets?
712 SET_MENUBAR_ITEM_STATE("copy_menu", !v->error);
713 SET_MENUBAR_ITEM_STATE("paste_menu", !v->error);
714 SET_MENUBAR_ITEM_STATE("insert_ascii_menu", !v->error);
715 SET_MENUBAR_ITEM_STATE("view_basic_menu", !v->error);
716 SET_MENUBAR_ITEM_STATE("view_advanced_menu", !v->error);
717 SET_MENUBAR_ITEM_STATE("view_financial_menu", !v->error);
718 SET_MENUBAR_ITEM_STATE("view_scientific_menu", !v->error);
719 SET_MENUBAR_ITEM_STATE("show_trailing_zeroes_menu",
720 !v->error && (v->modetype == SCIENTIFIC));
721 SET_MENUBAR_ITEM_STATE("show_thousands_separator_menu", !v->error);
722 SET_MENUBAR_ITEM_STATE("show_registers_menu", !v->error);
723 SET_MENUBAR_ITEM_STATE("arithmetic_precedence_menu", !v->error);
724 SET_MENUBAR_ITEM_STATE("about_menu", !v->error);
728 void
729 ui_set_hyperbolic_state(int state)
731 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(X->hyp), state);
735 void
736 ui_set_inverse_state(int state)
738 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(X->inv), state);
742 static void
743 set_memory_toggle(int state)
745 GtkWidget *radio = GET_WIDGET("show_registers_menu");
747 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(radio), state);
751 static char *
752 make_hostname()
754 Display *dpy = GDK_DISPLAY();
755 char client_hostname[MAXHOSTNAMELEN + 4];
756 char hostname[MAXHOSTNAMELEN];
757 char *display = DisplayString(dpy);
758 char *scanner = display;
760 GETHOSTNAME(hostname, MAXHOSTNAMELEN);
762 while (*scanner) {
763 scanner++;
766 while (*scanner != ':') {
767 scanner--;
770 *scanner = '\0';
772 if (strcmp(display, hostname) &&
773 strcmp(display, "localhost") &&
774 strcmp(display, "unix") &&
775 strcmp(display, "")) {
776 SPRINTF(client_hostname, " [%s] ", hostname);
777 } else {
778 STRCPY(client_hostname, "");
781 *scanner = ':';
783 if (client_hostname[0] == '\0')
784 return NULL;
785 else
786 return(strdup(client_hostname));
790 void
791 ui_set_mode(enum mode_type mode)
793 GtkRequisition *r;
794 gint w, h;
795 char *hostname, title[MAXLINE];
796 GtkWidget *radio;
798 switch (mode) {
799 case BASIC:
800 gtk_widget_show(X->bas_panel);
801 gtk_widget_hide(X->adv_panel);
802 gtk_widget_hide(X->fin_panel);
803 gtk_widget_hide(X->mode_panel);
804 gtk_widget_hide(X->bit_panel);
805 gtk_widget_hide(X->sci_panel);
806 radio = GET_WIDGET("view_basic_menu");
807 break;
809 case ADVANCED:
810 gtk_widget_hide(X->bas_panel);
811 gtk_widget_show(X->adv_panel);
812 gtk_widget_hide(X->fin_panel);
813 gtk_widget_hide(X->mode_panel);
814 gtk_widget_hide(X->bit_panel);
815 gtk_widget_hide(X->sci_panel);
816 radio = GET_WIDGET("view_advanced_menu");
817 break;
819 case FINANCIAL:
820 gtk_widget_hide(X->bas_panel);
821 gtk_widget_show(X->adv_panel);
822 gtk_widget_show(X->fin_panel);
823 gtk_widget_hide(X->mode_panel);
824 gtk_widget_hide(X->bit_panel);
825 gtk_widget_hide(X->sci_panel);
826 radio = GET_WIDGET("view_financial_menu");
827 break;
829 case SCIENTIFIC:
830 gtk_widget_hide(X->bas_panel);
831 gtk_widget_show(X->adv_panel);
832 gtk_widget_hide(X->fin_panel);
833 gtk_widget_show_all(X->mode_panel);
834 if (v->bitcalculating_mode) {
835 gtk_widget_show_all(X->bit_panel);
836 } else {
837 gtk_widget_hide(X->bit_panel);
839 gtk_widget_show(X->sci_panel);
840 radio = GET_WIDGET("view_scientific_menu");
841 break;
843 default:
844 assert(FALSE);
845 return;
848 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(radio), TRUE);
850 /* Disable widgets not applicable in this mode */
851 radio = GET_WIDGET("show_trailing_zeroes_menu");
852 gtk_widget_set_sensitive(radio, v->modetype == SCIENTIFIC);
853 radio = GET_WIDGET("show_bitcalculating_menu");
854 gtk_widget_set_sensitive(radio, v->modetype == SCIENTIFIC);
855 radio = GET_WIDGET("show_registers_menu");
856 gtk_widget_set_sensitive(radio, v->modetype != BASIC);
857 if (v->modetype == BASIC) {
858 gtk_dialog_response(GTK_DIALOG(X->rframe), GTK_RESPONSE_CLOSE);
861 r = g_new0(GtkRequisition, 1);
862 gtk_widget_size_request(X->menubar, r);
863 w = r->width;
864 h = r->height;
865 gtk_widget_size_request(X->display_item, r);
866 w = MAX(w, r->width);
867 h += r->height;
869 if (GTK_WIDGET_VISIBLE(X->fin_panel)) {
870 gtk_widget_size_request(X->fin_panel, r);
871 w = MAX(w, r->width);
872 h += r->height;
875 if (GTK_WIDGET_VISIBLE(X->mode_panel)) {
876 gtk_widget_size_request(X->mode_panel, r);
877 w = MAX(w, r->width);
878 h += r->height;
881 if (GTK_WIDGET_VISIBLE(X->sci_panel)) {
882 gtk_widget_size_request(X->sci_panel, r);
883 w = MAX(w, r->width);
884 h += r->height;
887 /* For initial display. */
888 gtk_window_set_default_size(GTK_WINDOW(X->kframe), w, h);
889 gtk_window_resize(GTK_WINDOW(X->kframe), w, h);
891 g_free(r);
893 if((hostname = make_hostname())) {
894 SNPRINTF(title, MAXLINE, hostname_titles[mode], hostname);
895 g_free(hostname);
896 } else {
897 SNPRINTF(title, MAXLINE, titles[mode]);
899 gtk_window_set_title(GTK_WINDOW(X->kframe), title);
903 static void
904 set_item(enum item_type itemtype, int val)
906 if (!v->started) {
907 return;
910 switch (itemtype) {
911 case BASEITEM:
912 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(X->base[val]), 1);
913 break;
915 case NUMITEM:
916 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(X->disp[val]), 1);
917 break;
919 case TTYPEITEM:
920 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(X->trig[val]), 1);
921 break;
923 default:
924 break;
929 /*ARGSUSED*/
930 static void
931 about_cb(GtkWidget *widget)
933 const gchar *authors[] = {
934 "Rich Burridge <rich.burridge@sun.com>",
935 "Sami Pietila <sampie@ariana-dsl.utu.fi>",
936 "Robert Ancell <robert.ancell@gmail.com>",
937 NULL
939 const gchar *documenters[] = {
940 "Sun Microsystems",
941 NULL
943 const gchar *translator_credits = _("translator-credits");
945 const char *license[] = {
946 N_("Gcalctool is free software; you can redistribute it and/or modify\n"
947 "it under the terms of the GNU General Public License as published by\n"
948 "the Free Software Foundation; either version 2 of the License, or\n"
949 "(at your option) any later version.\n"),
950 N_("Gcalctool is distributed in the hope that it will be useful,\n"
951 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
952 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
953 "GNU General Public License for more details.\n"),
954 N_("You should have received a copy of the GNU General Public License\n"
955 "along with Gcalctool; if not, write to the Free Software Foundation, Inc.,\n"
956 "51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA\n")
959 char *license_trans = g_strconcat(_(license[0]), "\n",
960 _(license[1]), "\n",
961 _(license[2]), "\n",
962 NULL);
964 gtk_show_about_dialog(GTK_WINDOW(X->kframe),
965 "name",_("Gcalctool"),
966 "version", VERSION,
967 "copyright", _("\xc2\xa9 1986-2007 The Gcalctool authors"),
968 "license", license_trans,
969 "comments", _("Calculator with financial and scientific modes."),
970 "authors", authors,
971 "documenters", documenters,
972 "translator_credits", translator_credits,
973 "logo-icon-name", "gnome-calculator",
974 NULL);
978 static void
979 cell_edited(GtkCellRendererText *cell, const gchar *path_string,
980 const gchar *new_text, gpointer data)
982 GtkTreeModel *model = (GtkTreeModel *) data;
983 GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
984 GtkTreeIter iter;
985 gchar *old_text;
986 gint *column;
988 column = g_object_get_data(G_OBJECT(cell), "column");
990 gtk_tree_model_get_iter(model, &iter, path);
992 switch (GPOINTER_TO_INT(column)) {
993 case COLUMN_VALUE:
994 gtk_tree_model_get(model, &iter, column, &old_text, -1);
995 g_free(old_text);
996 gtk_list_store_set(GTK_LIST_STORE(model), &iter, column,
997 g_strdup(new_text), -1);
998 break;
1000 case COLUMN_DESCRIPTION:
1001 gtk_tree_model_get(model, &iter, column, &old_text, -1);
1002 g_free(old_text);
1003 gtk_list_store_set(GTK_LIST_STORE(model), &iter, column,
1004 g_strdup(new_text), -1);
1005 break;
1008 gtk_tree_path_free(path);
1012 static void
1013 add_cf_column(GtkTreeView *treeview, gchar *name, gint colno, gboolean editable)
1015 GtkCellRenderer *renderer;
1016 GtkTreeModel *model = gtk_tree_view_get_model(treeview);
1018 renderer = gtk_cell_renderer_text_new();
1019 if (editable) {
1020 g_signal_connect(G_OBJECT(renderer), "edited",
1021 G_CALLBACK(cell_edited), model);
1023 g_object_set_data(G_OBJECT(renderer), "column", GINT_TO_POINTER(colno));
1025 if (editable) {
1026 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(treeview),
1027 -1, name, renderer,
1028 "text", colno,
1029 "editable", COLUMN_EDITABLE,
1030 NULL);
1031 } else {
1032 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(treeview),
1033 -1, name, renderer,
1034 "text", colno,
1035 NULL);
1040 /*ARGSUSED*/
1041 static void
1042 aframe_cancel_cb(GtkButton *button, gpointer user_data)
1044 gtk_widget_hide(X->aframe);
1048 /*ARGSUSED*/
1049 static gboolean
1050 aframe_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer data)
1052 g_return_val_if_fail(GTK_IS_WIDGET(widget), FALSE);
1054 if (event->keyval == GDK_Escape) {
1055 gtk_widget_hide(X->aframe);
1058 return(FALSE);
1062 /*ARGSUSED*/
1063 static void
1064 aframe_ok_cb(GtkButton *button, gpointer user_data)
1066 char *ch;
1067 int val;
1069 ch = (char *) gtk_entry_get_text(GTK_ENTRY(X->aframe_ch));
1070 val = ch[0];
1071 mpcim(&val, v->MPdisp_val);
1072 show_display(v->MPdisp_val);
1073 gtk_widget_hide(X->aframe);
1077 /*ARGSUSED*/
1078 void
1079 base_cb(GtkWidget *widget)
1081 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1082 do_base((enum base_type) g_object_get_data(G_OBJECT(widget),
1083 "response_id"));
1087 void
1088 ui_beep()
1090 gdk_beep();
1093 static void do_button(struct button *n, int arg)
1095 struct exprm_state *e;
1097 switch (v->syntax) {
1098 case npa:
1099 process_item(n, arg);
1100 set_bit_panel();
1101 if (v->new_input && v->dtype == FIX) {
1102 STRNCPY(v->fnum, v->display, MAX_DIGITS - 1);
1103 ui_set_display(v->fnum, TRUE);
1105 break;
1107 case exprs:
1108 e = get_state();
1109 e->value = arg;
1110 MEMCPY(&(e->button), n, sizeof(struct button));
1111 new_state();
1112 do_expression();
1113 set_bit_panel();
1114 break;
1116 default:
1117 assert(0);
1122 static void
1123 help_display(void)
1125 GError *error = NULL;
1126 char *command;
1127 const char *lang;
1128 char *uri = NULL;
1129 GdkScreen *gscreen;
1131 int i;
1133 const char * const * langs = g_get_language_names ();
1135 for (i = 0; langs[i]; i++) {
1136 lang = langs[i];
1137 if (strchr (lang, '.')) {
1138 continue;
1141 uri = g_build_filename(PACKAGE_DATA_DIR,
1142 "/gnome/help/gcalctool/",
1143 lang,
1144 "/gcalctool.xml",
1145 NULL);
1147 if (g_file_test (uri, G_FILE_TEST_EXISTS)) {
1148 break;
1152 command = g_strconcat ("gnome-open ghelp://", uri, NULL);
1153 gscreen = gdk_screen_get_default();
1154 gdk_spawn_command_line_on_screen (gscreen, command, &error);
1155 if (error) {
1156 GtkWidget *d;
1158 d = gtk_message_dialog_new(NULL,
1159 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1160 GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
1161 error->message);
1162 gtk_dialog_run(GTK_DIALOG(d));
1163 gtk_widget_destroy(d);
1164 g_error_free(error);
1165 error = NULL;
1168 g_free (command);
1169 g_free (uri);
1173 static void
1174 put_constant(int n, char *con_value, char *con_name)
1176 char key[MAXLINE];
1177 char *cstr = g_strdup(con_value);
1179 /* Constants are written out with no thousands seaparator and with a radix
1180 * character of ".".
1183 SNPRINTF(key, MAXLINE, "constant%1dvalue", n);
1184 set_resource(key, cstr);
1185 g_free(cstr);
1187 SNPRINTF(key, MAXLINE, "constant%1dname", n);
1188 set_resource(key, con_name);
1192 static void
1193 put_function(int n, char *fun_value, char *fun_name)
1195 char key[MAXLINE];
1197 SNPRINTF(key, MAXLINE, "function%1dvalue", n);
1198 set_resource(key, fun_value);
1200 SNPRINTF(key, MAXLINE, "function%1dname", n);
1201 set_resource(key, fun_name);
1205 /*ARGSUSED*/
1206 static void
1207 menu_proc_cb(GtkMenuItem *mi, gpointer user_data)
1209 struct button *n = (struct button *) g_object_get_data(G_OBJECT(mi), "button");
1210 do_button(n, GPOINTER_TO_INT(user_data));
1214 /* Create popup window for editing constants/functions. */
1216 static void
1217 update_popup_label(GtkWidget *menu_item, gchar *text)
1219 GtkWidget *label;
1220 label = (GtkWidget *)gtk_container_get_children(GTK_CONTAINER(menu_item))->data;
1221 gtk_label_set_markup_with_mnemonic(GTK_LABEL(label), text);
1224 static void
1225 update_constants_menu(void)
1227 char mline[MAXLINE];
1228 int i;
1230 for (i = 0; i < MAXCONFUN; i++) {
1231 SNPRINTF(mline, MAXLINE,
1232 "<span weight=\"bold\">%s_%1d:</span> %s [%s]", _("C"), i,
1233 make_number(v->MPcon_vals[i], DEC, TRUE),
1234 v->con_names[i]);
1235 update_popup_label(X->constant_menu_items[i], mline);
1240 static void
1241 update_functions_menu(void)
1243 char mline[MAXLINE];
1244 int i;
1246 for (i = 0; i < MAXCONFUN; i++) {
1247 if (strlen(v->fun_vals[i]) != 0) {
1248 SNPRINTF(mline, MAXLINE,
1249 "<span weight=\"bold\">%s_%1d:</span> %s [%s]",
1250 _("F"), i, v->fun_vals[i], v->fun_names[i]);
1251 gtk_widget_show(X->function_menu_items[i]);
1252 update_popup_label(X->function_menu_items[i], mline);
1254 else
1255 gtk_widget_hide(X->function_menu_items[i]);
1260 static void
1261 edit_constants_response_cb(GtkDialog *dialog, gint id)
1263 GtkTreeIter iter;
1264 gint number;
1265 gchar *value;
1266 gchar *description;
1268 if (id == GTK_RESPONSE_HELP) {
1269 help_display();
1272 if (id == GTK_RESPONSE_ACCEPT) {
1273 if (gtk_tree_model_get_iter_first(X->constants_model, &iter)) {
1274 do {
1275 gtk_tree_model_get(X->constants_model, &iter,
1276 COLUMN_NUMBER, &number,
1277 COLUMN_VALUE, &value,
1278 COLUMN_DESCRIPTION, &description, -1);
1279 MPstr_to_num(value, DEC, v->MPcon_vals[number]);
1280 STRNCPY(v->con_names[number], description, MAXLINE - 1);
1281 put_constant(number, value, description);
1282 } while (gtk_tree_model_iter_next(X->constants_model, &iter));
1286 gtk_widget_hide(GTK_WIDGET(dialog));
1290 static void
1291 edit_functions_response_cb(GtkDialog *dialog, gint id)
1293 GtkTreeIter iter;
1294 gint number;
1295 gchar *value;
1296 gchar *description;
1298 if (id == GTK_RESPONSE_HELP) {
1299 help_display();
1302 if (id == GTK_RESPONSE_ACCEPT) {
1303 if (gtk_tree_model_get_iter_first(X->functions_model, &iter)) {
1304 do {
1305 gtk_tree_model_get(X->functions_model, &iter,
1306 COLUMN_NUMBER, &number,
1307 COLUMN_VALUE, &value,
1308 COLUMN_DESCRIPTION, &description, -1);
1309 STRNCPY(v->fun_vals[number], convert(value), MAXLINE - 1);
1310 STRNCPY(v->fun_names[number], description, MAXLINE - 1);
1311 put_function(number, value, description);
1312 } while (gtk_tree_model_iter_next(X->functions_model, &iter));
1316 gtk_widget_hide(GTK_WIDGET(dialog));
1320 /*ARGSUSED*/
1321 static GtkTreeModel *
1322 create_cf_model(enum menu_type mtype, GtkWidget *dialog)
1324 gint i = 0;
1325 GtkListStore *model;
1326 GtkTreeIter iter;
1327 gchar *value, *description;
1329 model = gtk_list_store_new(NUM_COLUMNS, G_TYPE_INT, G_TYPE_STRING,
1330 G_TYPE_STRING, G_TYPE_BOOLEAN);
1331 for (i = 0; i < MAXCONFUN; i++) {
1332 gtk_list_store_append(model, &iter);
1334 if (mtype == M_CON) {
1335 value = g_strdup(make_number(v->MPcon_vals[i], DEC, TRUE));
1336 description = g_strdup(v->con_names[i]);
1337 } else {
1338 value = g_strdup(v->fun_vals[i]);
1339 description = g_strdup(v->fun_names[i]);
1341 gtk_list_store_set(model, &iter,
1342 COLUMN_NUMBER, i,
1343 COLUMN_VALUE, value,
1344 COLUMN_DESCRIPTION, description,
1345 COLUMN_EDITABLE, TRUE,
1346 -1);
1349 return(GTK_TREE_MODEL(model));
1353 void
1354 ui_set_accuracy(int accuracy)
1356 GtkWidget *label;
1357 char text[MAXLINE];
1358 char *desc, *current, *tooltip;
1360 SNPRINTF(text, MAXLINE, _("Other (%d) ..."), accuracy);
1361 label = gtk_bin_get_child(GTK_BIN(GET_WIDGET("acc_item_other")));
1362 gtk_label_set_text(GTK_LABEL(label), text);
1364 desc = g_strdup_printf(ngettext("Set accuracy from 0 to %d numeric places.",
1365 "Set accuracy from 0 to %d numeric places.",
1366 MAXACC),
1367 MAXACC);
1369 /* Translator: This refers to the current accuracy setting */
1370 current = g_strdup_printf(ngettext("Currently set to %d places.",
1371 "Currently set to %d places.",
1372 accuracy),
1373 accuracy);
1374 tooltip = g_strdup_printf ("%s %s [A]", desc, current);
1375 gtk_widget_set_tooltip_text (GET_WIDGET("calc_accuracy_button"), tooltip);
1376 g_free(desc);
1377 g_free(current);
1378 g_free(tooltip);
1382 static void
1383 set_accuracy_toggle(int val)
1385 char name[MAXLINE];
1386 GtkWidget *radio;
1388 if (val >= 0 && val <= 9) {
1389 SNPRINTF(name, MAXLINE, "acc_item%d", val);
1390 radio = GET_WIDGET(name);
1391 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(radio), TRUE);
1396 static void
1397 set_show_tsep_toggle(int state)
1399 GtkWidget *mi;
1401 mi = GET_WIDGET("show_thousands_separator_menu");
1402 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mi), state);
1406 static void
1407 set_show_bitcalculating_toggle(int state)
1409 GtkWidget *mi;
1411 mi = GET_WIDGET("show_bitcalculating_menu");
1412 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mi), state);
1416 static void
1417 set_show_zeroes_toggle(int state)
1419 GtkWidget *menu;
1421 v->doing_mi = 1; /* Hack to get mstz_proc() to just return. */
1422 menu = GET_WIDGET("show_trailing_zeroes_menu");
1423 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), state);
1424 menu = GET_WIDGET("acc_trailing_zeroes_item");
1425 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), state);
1426 v->doing_mi = 0;
1430 void
1431 ui_make_registers() /* Calculate memory register frame values. */
1433 char *mval, key[MAXLINE];
1434 int n;
1436 for (n = 0; n < MAXREGS; n++) {
1437 mval = make_number(v->MPmvals[n], v->base, TRUE);
1438 gtk_entry_set_width_chars(GTK_ENTRY(X->regs[n]), strlen(mval));
1439 gtk_entry_set_text(GTK_ENTRY(X->regs[n]), mval);
1440 SNPRINTF(key, MAXLINE, "register%d", n);
1441 set_resource(key, mval);
1446 static void
1447 reset_mode_display(void)
1449 switch (v->syntax) {
1450 case npa:
1451 show_display(v->MPdisp_val);
1452 break;
1454 case exprs:
1455 refresh_display();
1456 break;
1458 ui_make_registers();
1462 static void
1463 save_win_position()
1465 int x, y;
1467 (void) gdk_window_get_origin(X->kframe->window, &x, &y);
1468 set_int_resource(R_XPOS, x);
1469 set_int_resource(R_YPOS, y);
1473 /*ARGSUSED*/
1474 static void
1475 cm_response_cb(GtkDialog *dialog, int response)
1477 if (response == GTK_RESPONSE_ACCEPT) {
1478 X->mode = mode;
1479 v->modetype = mode;
1480 set_item(BASEITEM, DEC);
1481 ui_set_base(v->base);
1482 set_item(NUMITEM, FIX);
1483 v->accuracy = 9;
1484 set_accuracy_toggle(v->accuracy);
1486 v->show_tsep = FALSE;
1487 set_show_tsep_toggle(v->show_tsep);
1488 set_boolean_resource(R_TSEP, v->show_tsep == TRUE);
1490 v->show_zeroes = FALSE;
1491 set_show_zeroes_toggle(v->show_zeroes);
1492 set_boolean_resource(R_ZEROES, v->show_zeroes == TRUE);
1494 reset_mode_display();
1495 do_mode(TRUE);
1496 } else {
1497 ui_set_mode(v->modetype);
1500 gtk_widget_destroy(X->cm_dialog);
1501 X->cm_dialog = NULL;
1505 /*ARGSUSED*/
1506 static void
1507 cm_warning_cb(GtkWidget *button)
1509 v->warn_change_mode = !gtk_toggle_button_get_active(
1510 GTK_TOGGLE_BUTTON(button));
1514 static void
1515 create_change_mode_dialog()
1517 GtkWidget *check, *button;
1519 X->cm_dialog = gtk_message_dialog_new(GTK_WINDOW(X->kframe),
1520 GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
1521 GTK_MESSAGE_WARNING,
1522 GTK_BUTTONS_CANCEL,
1523 "%s",
1524 _("Changing Modes Clears Calculation"));
1525 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(X->cm_dialog),
1526 "%s",
1527 _("When you change modes, the current calculation "
1528 "will be cleared, and the base will be reset to "
1529 "decimal."));
1531 check = gtk_check_button_new_with_mnemonic(_("_Do not warn me again"));
1532 gtk_box_pack_end(GTK_BOX(GTK_MESSAGE_DIALOG(X->cm_dialog)->label->parent),
1533 check, FALSE, FALSE, 0);
1534 gtk_widget_show(check);
1536 button = gtk_dialog_add_button(GTK_DIALOG(X->cm_dialog),
1537 _("C_hange Mode"), GTK_RESPONSE_ACCEPT);
1538 gtk_button_set_image(GTK_BUTTON(button),
1539 gtk_image_new_from_stock(GTK_STOCK_REFRESH,
1540 GTK_ICON_SIZE_BUTTON));
1541 /* Set default focus on affirmative button */
1542 gtk_widget_grab_focus(button);
1544 gtk_dialog_set_alternative_button_order(GTK_DIALOG(X->cm_dialog),
1545 GTK_RESPONSE_ACCEPT,
1546 GTK_RESPONSE_CANCEL,
1547 -1);
1549 g_signal_connect((gpointer) check, "toggled",
1550 G_CALLBACK(cm_warning_cb), NULL);
1551 g_signal_connect(X->cm_dialog, "response",
1552 G_CALLBACK(cm_response_cb), NULL);
1554 gtk_window_set_position(GTK_WINDOW(X->cm_dialog),
1555 GTK_WIN_POS_CENTER_ON_PARENT);
1559 static void
1560 show_change_mode_dialog()
1562 if (X->cm_dialog == NULL) {
1563 create_change_mode_dialog();
1566 gtk_window_present(GTK_WINDOW(X->cm_dialog));
1570 /*ARGSUSED*/
1571 static gboolean
1572 bit_toggled(GtkWidget *event_box, GdkEventButton *event)
1574 double number;
1575 unsigned long long lval;
1576 int n, MP1[MP_SIZE], index;
1578 index = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(event_box),
1579 "widget_index"));
1580 n = MAXBITS - index - 1;
1581 MPstr_to_num(v->display, v->base, MP1);
1582 mpcmd(MP1, &number);
1583 lval = (long long) number;
1585 if (lval & (1LL << n)) {
1586 lval &= ~(1LL << n);
1587 gtk_label_set_text(GTK_LABEL(X->bits[index]), " 0");
1588 } else {
1589 lval |= (1LL << n);
1590 gtk_label_set_text(GTK_LABEL(X->bits[index]), " 1");
1593 number = (double) lval;
1594 mpcdm(&number, v->MPdisp_val);
1595 show_display(v->MPdisp_val);
1596 v->toclear = 0;
1598 return(TRUE);
1602 void
1603 ui_set_undo_enabled(int undo, int redo)
1605 gtk_widget_set_sensitive(X->undo, undo);
1606 gtk_widget_set_sensitive(X->redo, redo);
1610 static void
1611 menu_item_select_cb(GtkWidget *widget)
1613 GtkStatusbar *statusbar = GTK_STATUSBAR(X->statusbar);
1614 gchar *tooltip;
1615 guint context_id;
1617 context_id = gtk_statusbar_get_context_id(statusbar, "menuhelp");
1619 tooltip = (gchar *)g_object_get_data(G_OBJECT(widget), "tooltip");
1620 if (tooltip) {
1621 gtk_statusbar_push(statusbar, context_id, tooltip);
1626 /*ARGSUSED*/
1627 static void
1628 menu_item_deselect_cb(GtkWidget *widget)
1630 GtkStatusbar *statusbar = GTK_STATUSBAR(X->statusbar);
1631 guint context_id;
1633 context_id = gtk_statusbar_get_context_id(statusbar, "menuhelp");
1634 gtk_statusbar_pop(statusbar, context_id);
1638 static void
1639 update_copy_paste_status()
1641 gboolean can_paste;
1642 gboolean can_copy;
1644 can_copy = gtk_text_buffer_get_has_selection(X->display_buffer);
1645 can_paste = gtk_clipboard_wait_is_text_available(
1646 gtk_clipboard_get(X->clipboard_atom));
1648 gtk_widget_set_sensitive(GTK_WIDGET(X->copy), can_copy);
1649 gtk_widget_set_sensitive(GTK_WIDGET(X->paste), can_paste);
1653 static void
1654 set_menubar_tooltip(gchar *menu_name)
1656 GtkWidget *menu;
1657 gchar *tooltip;
1659 menu = GET_WIDGET(menu_name);
1660 tooltip = gtk_widget_get_tooltip_text(menu);
1661 g_object_set_data(G_OBJECT(menu), "tooltip", tooltip);
1662 gtk_widget_set_tooltip_text(menu, NULL);
1666 static void
1667 update_memory_menus()
1669 char mstr[MAXLINE];
1670 int i;
1672 for (i = 0; i < MAXREGS; i++) {
1673 SNPRINTF(mstr, MAXLINE, "<span weight=\"bold\">%s_%d:</span> %s",
1674 /* translators: R is the short form of register used inter alia
1675 in popup menus */
1676 _("R"), i, make_number(v->MPmvals[i], v->base, TRUE));
1677 update_popup_label(X->memory_store_items[i], mstr);
1678 update_popup_label(X->memory_recall_items[i], mstr);
1679 update_popup_label(X->memory_exchange_items[i], mstr);
1684 /*ARGSUSED*/
1685 static void
1686 mem_response(GtkDialog *dialog, int response)
1688 set_memory_toggle(FALSE);
1689 set_boolean_resource(R_REGS, FALSE);
1690 gtk_widget_hide(X->rframe);
1694 /*ARGSUSED*/
1695 static gboolean
1696 dismiss_aframe(GtkWidget *widget, GdkEvent *event, gpointer user_data)
1698 gtk_widget_hide(widget);
1700 return(TRUE);
1704 /*ARGSUSED*/
1705 static gboolean
1706 dismiss_rframe(GtkWidget *widget, GdkEvent *event, gpointer user_data)
1708 gtk_dialog_response(GTK_DIALOG(widget), GTK_RESPONSE_DELETE_EVENT);
1710 return(TRUE);
1714 /*ARGSUSED*/
1715 static gboolean
1716 dismiss_spframe(GtkWidget *widget, GdkEvent *event, gpointer user_data)
1718 gtk_widget_hide(X->spframe);
1720 return(TRUE);
1724 /*ARGSUSED*/
1725 void
1726 disp_cb(GtkWidget *widget)
1728 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1729 do_numtype((enum num_type) g_object_get_data(G_OBJECT(widget), "response_id"));
1733 static void
1734 get_constant(int n)
1736 char nkey[MAXLINE], *nline;
1737 char vkey[MAXLINE], *vline;
1739 SNPRINTF(nkey, MAXLINE, "constant%1dname", n);
1740 if ((nline = get_resource(nkey)) == NULL) {
1741 return;
1744 SNPRINTF(vkey, MAXLINE, "constant%1dvalue", n);
1745 if ((vline = get_resource(vkey)) == NULL) {
1746 return;
1749 MPstr_to_num(vline, DEC, v->MPcon_vals[n]);
1750 STRNCPY(v->con_names[n], nline, MAXLINE - 1);
1754 static void
1755 get_display() /* The Copy function key has been pressed. */
1757 gchar *string = NULL;
1758 GtkTextIter start, end;
1760 if (gtk_text_buffer_get_selection_bounds(X->display_buffer, &start, &end) == TRUE) {
1761 string = gtk_text_buffer_get_text(X->display_buffer, &start, &end, FALSE);
1762 } else {
1763 gtk_text_buffer_get_bounds(X->display_buffer, &start, &end);
1764 string = gtk_text_buffer_get_text(X->display_buffer, &start, &end, FALSE);
1767 if (v->shelf != NULL) {
1768 free(v->shelf);
1770 v->shelf = g_locale_from_utf8(string, strlen(string), NULL, NULL, NULL);
1771 g_free(string);
1773 gtk_clipboard_set_text(gtk_clipboard_get(X->clipboard_atom), v->shelf, -1);
1777 static void
1778 get_function(int n)
1780 char nkey[MAXLINE], *nline;
1781 char vkey[MAXLINE], *vline;
1783 SNPRINTF(nkey, MAXLINE, "function%1dname", n);
1784 if ((nline = get_resource(nkey)) == NULL) {
1785 return;
1788 SNPRINTF(vkey, MAXLINE, "function%1dvalue", n);
1789 if ((vline = get_resource(vkey)) == NULL) {
1790 return;
1793 STRNCPY(v->fun_vals[n], convert(vline), MAXLINE - 1);
1794 STRNCPY(v->fun_names[n], nline, MAXLINE - 1);
1798 char *
1799 ui_get_localized_numeric_point(void)
1801 const char *decimal_point;
1803 decimal_point = localeconv()->decimal_point;
1805 return(g_locale_to_utf8(decimal_point, -1, NULL, NULL, NULL));
1810 get_menu_entry(enum menu_type mtype, int offset)
1812 switch (mtype) {
1813 case M_ACC :
1814 return(offset + '0');
1816 case M_LSHF :
1817 case M_RSHF :
1818 return((offset < 10) ? offset + '0' : offset + 'A' - 10);
1820 default:
1821 FPRINTF(stderr, "need to handle menu type %d\n", mtype);
1824 return(0);
1828 /*ARGSUSED*/
1829 static void
1830 get_proc(GtkClipboard *clipboard, const gchar *buffer, gpointer data)
1832 gchar *dstp, *end_buffer, *srcp, *text;
1834 if (buffer == NULL) {
1835 return;
1838 end_buffer = (gchar *) (buffer + strlen(buffer));
1839 text = malloc(strlen(buffer)+1);
1841 srcp = (gchar *) buffer;
1842 dstp = text;
1843 while (srcp < end_buffer) {
1845 /* If the clipboard buffer contains any occurances of the "thousands
1846 * separator", remove them.
1848 if (*srcp == v->tsep[0]) {
1849 if (strstr(srcp, v->tsep) == srcp) {
1850 srcp += strlen(v->tsep);
1851 } else {
1852 *dstp++ = *srcp++;
1854 } else {
1856 /* If an "A", "B", "C", "D" or "F" character is encountered, it
1857 * will be converted to its lowercase equivalent. If an "E" is
1858 * found, and the next character is a "-" or a "+", then it
1859 * remains as an upper case "E" (it's assumed to be a possible
1860 * exponential number), otherwise its converted to a lower case
1861 * "e". See bugs #455889 and #469245 for more details.
1863 switch (*srcp) {
1864 case 'A':
1865 case 'B':
1866 case 'C':
1867 case 'D':
1868 case 'F': *dstp++ = tolower(*srcp);
1869 srcp++;
1870 break;
1872 case 'E': if (srcp < (end_buffer-1)) {
1873 if (*(srcp+1) != '-' &&
1874 *(srcp+1) != '+') {
1875 *dstp++ = tolower(*srcp);
1876 srcp++;
1877 break;
1880 /*FALLTHROUGH*/
1882 default: *dstp++ = *srcp++;
1886 *dstp++ = '\0';
1888 switch (v->syntax) {
1889 case npa: {
1890 int ret = lr_parse((char *) text, v->MPdisp_val);
1892 if (!ret) {
1893 show_display(v->MPdisp_val);
1894 } else {
1895 ui_set_statusbar(_("Clipboard contained malformed calculation"),
1896 "gtk-dialog-error");
1898 break;
1901 case exprs:
1902 exp_append((char *) text);
1903 refresh_display();
1904 break;
1906 default:
1907 assert(0);
1909 free(text);
1913 void
1914 ui_set_base(enum base_type base)
1916 int i, baseval = basevals[(int) base];
1918 for (i = 0; i < 16; i++) {
1919 gtk_widget_set_sensitive(X->digit_buttons[i], i < baseval);
1924 static void
1925 handle_selection() /* Handle the GET function key being pressed. */
1927 gtk_clipboard_request_text(gtk_clipboard_get(X->clipboard_atom),
1928 get_proc, NULL);
1932 /*ARGSUSED*/
1933 static void
1934 popup_paste_cb(GtkMenuItem *menuitem)
1936 handle_selection();
1940 /*ARGSUSED*/
1941 static void
1942 for_each_menu(GtkWidget *widget, gpointer data)
1944 /* Find the "Paste" entry and activate it (see bug #317786). */
1945 if (strcmp(G_OBJECT_TYPE_NAME(widget), "GtkImageMenuItem") == 0) {
1946 GtkWidget *label = gtk_bin_get_child(GTK_BIN(widget));
1948 if (strcmp(gtk_label_get_text(GTK_LABEL(label)), _("Paste")) == 0) {
1949 if (gtk_clipboard_wait_is_text_available(
1950 gtk_clipboard_get(X->clipboard_atom))) {
1951 gtk_widget_set_sensitive(GTK_WIDGET(widget), TRUE);
1952 g_signal_connect(GTK_OBJECT(widget), "activate",
1953 G_CALLBACK(popup_paste_cb), NULL);
1960 /*ARGSUSED*/
1961 static void
1962 buffer_populate_popup_cb(GtkTextView *textview, GtkMenu *menu)
1964 gtk_container_foreach(GTK_CONTAINER(menu), for_each_menu, NULL);
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 v->hyperbolic = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
1985 /*ARGSUSED*/
1986 void
1987 inv_cb(GtkWidget *button)
1989 v->inverse = !v->inverse;
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 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);
2024 void
2025 delete_from_cursor()
2027 GtkTextIter start, end, loc;
2028 gint pos;
2030 gtk_text_buffer_get_bounds(X->display_buffer, &start, &end);
2031 g_object_get(G_OBJECT(X->display_buffer), "cursor-position", &pos, NULL);
2033 gtk_text_buffer_get_iter_at_offset(X->display_buffer,
2034 &loc,
2035 pos);
2037 gtk_text_buffer_backspace(X->display_buffer, &loc, TRUE, TRUE);
2042 void
2043 ui_insert_display(char *text)
2045 gtk_text_buffer_insert_at_cursor(X->display_buffer,
2046 text,
2047 strlen(text));
2051 /*ARGSUSED*/
2052 static gboolean
2053 display_focus_out_cb(GtkWidget *widget, GdkEventKey *event)
2055 if (v->syntax == exprs) {
2056 ui_parse_display();
2059 return(FALSE);
2063 /*ARGSUSED*/
2064 static gboolean
2065 display_focus_in_cb(GtkWidget *widget, GdkEventKey *event)
2067 v->ghost_zero = 0;
2069 return(FALSE);
2073 /*ARGSUSED*/
2074 static void
2075 menu_pos_func(GtkMenu *menu, gint *x, gint *y,
2076 gboolean *push_in, gpointer user_data)
2078 GdkPoint *loc = (GdkPoint *) user_data;
2080 *x = loc->x;
2081 *y = loc->y;
2085 /*ARGSUSED*/
2086 static void
2087 button_cb(GtkWidget *widget, GdkEventButton *event)
2089 struct button *n;
2090 enum menu_type mtype;
2091 GtkWidget *menu;
2092 GdkPoint loc;
2094 n = (struct button *) g_object_get_data(G_OBJECT(widget), "button");
2095 mtype = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "mtype"));
2097 if (mtype == M_NONE) {
2098 do_button(n, 0);
2099 } else {
2100 /* If gcalctool is being driven by gok, the on-screen keyboard
2101 * assistive technology, it's possible that the event returned by
2102 * gtk_get_current_event() is NULL. If this is the case, we need
2103 * to fudge the popping up on the menu associated with this menu
2104 * button.
2107 update_constants_menu();
2108 update_functions_menu();
2109 update_memory_menus();
2111 menu = X->menus[mtype];
2112 if (event == NULL) {
2113 gdk_window_get_origin(widget->window, &loc.x, &loc.y);
2114 loc.x += widget->allocation.x;
2115 loc.y += widget->allocation.y;
2116 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, menu_pos_func,
2117 (gpointer) &loc, 0, gtk_get_current_event_time());
2118 } else if (event->button == 1) {
2119 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
2120 event->button, event->time);
2126 /*ARGSUSED*/
2127 static void
2128 select_display_entry(int offset)
2130 GtkTextIter iter;
2132 gtk_text_buffer_get_iter_at_offset(X->display_buffer, &iter, offset);
2133 gtk_text_buffer_place_cursor(X->display_buffer, &iter);
2134 gtk_widget_grab_focus(X->display_item);
2138 /*ARGSUSED*/
2139 static gboolean
2140 kframe_key_press_cb(GtkWidget *widget, GdkEventKey *event)
2142 int i, j, state;
2143 GtkWidget *button;
2145 if (check_for_localized_numeric_point(event->keyval) == TRUE) {
2146 event->state = 0;
2147 event->keyval = GDK_KP_Decimal;
2150 state = event->state & (GDK_CONTROL_MASK | GDK_MOD1_MASK);
2152 /* Accuracy shortcuts */
2153 if (state == GDK_CONTROL_MASK && v->modetype == SCIENTIFIC)
2155 switch (event->keyval) {
2156 case GDK_0:
2157 do_accuracy(0);
2158 return (TRUE);
2159 case GDK_1:
2160 do_accuracy(1);
2161 return (TRUE);
2162 case GDK_2:
2163 do_accuracy(2);
2164 return (TRUE);
2165 case GDK_3:
2166 do_accuracy(3);
2167 return (TRUE);
2168 case GDK_4:
2169 do_accuracy(4);
2170 return (TRUE);
2171 case GDK_5:
2172 do_accuracy(5);
2173 return (TRUE);
2174 case GDK_6:
2175 do_accuracy(6);
2176 return (TRUE);
2177 case GDK_7:
2178 do_accuracy(7);
2179 return (TRUE);
2180 case GDK_8:
2181 do_accuracy(8);
2182 return (TRUE);
2183 case GDK_9:
2184 do_accuracy(9);
2185 return (TRUE);
2189 /* Connect home and end keys to move into the display entry */
2190 if (event->keyval == GDK_Home)
2192 select_display_entry(0);
2193 return (TRUE);
2194 } else if (event->keyval == GDK_End)
2196 select_display_entry(-1);
2197 return (TRUE);
2200 for (i = 0; i < NBUTTONS; i++) {
2201 button = X->buttons[i];
2203 /* Check any parent widgets are visible */
2204 if (!GTK_WIDGET_VISIBLE(gtk_widget_get_parent(button)) ||
2205 !GTK_WIDGET_VISIBLE(button) || !GTK_WIDGET_IS_SENSITIVE(button)) {
2206 continue;
2209 j = 0;
2210 while (button_widgets[i].accelerator_keys[j] != 0) {
2211 if (button_widgets[i].accelerator_keys[j] == event->keyval &&
2212 (button_widgets[i].accelerator_mods[j] & ~GDK_SHIFT_MASK) == state) {
2213 button_cb(button, NULL);
2214 return(TRUE);
2216 j++;
2220 return(FALSE);
2224 /*ARGSUSED*/
2225 static gboolean
2226 mouse_button_cb(GtkWidget *widget, GdkEventButton *event)
2228 if (event->button == 2) {
2229 gtk_clipboard_request_text(gtk_clipboard_get(X->primary_atom),
2230 get_proc, NULL);
2233 return(FALSE);
2237 static void
2238 set_win_position()
2240 int intval, screen_height, screen_width;
2241 int x = 0, y = 0;
2243 screen_width = gdk_screen_get_width(gdk_screen_get_default());
2244 screen_height = gdk_screen_get_height(gdk_screen_get_default());
2246 if (get_int_resource(R_XPOS, &intval)) {
2247 x = intval;
2248 if (x < 0 || x > screen_width) {
2249 x = 0;
2253 if (get_int_resource(R_YPOS, &intval)) {
2254 y = intval;
2255 if (y < 0 || y > screen_height) {
2256 y = 0;
2260 gtk_window_move(GTK_WINDOW(X->kframe), x, y);
2263 static void
2264 show_ascii_frame() /* Display ASCII popup. */
2266 if (!GTK_WIDGET_VISIBLE(X->aframe)) {
2267 ds_position_popup(X->kframe, X->aframe, DS_POPUP_LEFT);
2269 gtk_window_set_focus(GTK_WINDOW(X->kframe), GTK_WIDGET(X->aframe_ch));
2270 gtk_widget_show(X->aframe);
2274 static void
2275 show_precision_frame() /* Display Set Precision popup. */
2277 if (!GTK_WIDGET_VISIBLE(X->spframe)) {
2278 ds_position_popup(X->kframe, X->spframe, DS_POPUP_LEFT);
2280 gtk_window_set_focus(GTK_WINDOW(X->spframe), GTK_WIDGET(X->spframe_val));
2281 gtk_widget_show(X->spframe);
2285 /* Handle menu bar menu selection. */
2287 /*ARGSUSED*/
2288 static void
2289 edit_cb(GtkWidget *widget)
2291 if (v->started) {
2292 update_copy_paste_status();
2297 /*ARGSUSED*/
2298 static void
2299 copy_cb(GtkWidget *widget)
2301 if (v->started) {
2302 get_display();
2307 /*ARGSUSED*/
2308 static void
2309 paste_cb(GtkWidget *widget)
2311 if (v->started) {
2312 handle_selection();
2317 /*ARGSUSED*/
2318 static void
2319 undo_cb(GtkWidget *widget)
2321 if (v->started) {
2322 perform_undo();
2323 refresh_display();
2328 /*ARGSUSED*/
2329 static void
2330 redo_cb(GtkWidget *widget)
2332 if (v->started) {
2333 perform_redo();
2334 refresh_display();
2339 /*ARGSUSED*/
2340 static void
2341 insert_ascii_cb(GtkWidget *widget)
2343 if (v->started) {
2344 show_ascii_frame();
2349 static void
2350 shift_left_cb(GtkWidget *widget)
2352 int count = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget),
2353 "shiftcount"));
2355 if (v->started) {
2356 do_button(&buttons[KEY_LEFT_SHIFT], count);
2361 static void
2362 shift_right_cb(GtkWidget *widget)
2364 int count = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget),
2365 "shiftcount"));
2367 if (v->started) {
2368 do_button(&buttons[KEY_RIGHT_SHIFT], count);
2372 /*ARGSUSED*/
2373 static void
2374 show_bitcalculating_cb(GtkWidget *widget)
2376 if (v->started) {
2377 v->bitcalculating_mode = v->bitcalculating_mode ^ 1;
2378 ui_set_mode(v->modetype);
2379 set_resource(R_BITCALC, Rcstr[v->bitcalculating_mode]);
2384 /*ARGSUSED*/
2385 static void
2386 show_registers_cb(GtkWidget *widget)
2388 if (v->started) {
2389 v->rstate = !v->rstate;
2390 do_memory();
2395 /*ARGSUSED*/
2396 static void
2397 arithmetic_mode_cb(GtkWidget *widget)
2399 if (!v->started) {
2400 return;
2403 /* TODO: Always do clear things when mode is changed. */
2405 v->syntax = v->syntax ^ 1;
2406 switch (v->syntax) {
2407 case npa:
2408 v->noparens = 0;
2409 MPstr_to_num("0", DEC, v->MPdisp_val);
2410 show_display(v->MPdisp_val);
2411 ui_set_statusbar(_("Activated no operator precedence mode"), "");
2412 clear_undo_history();
2413 break;
2415 case exprs: {
2416 struct exprm_state *e = get_state();
2418 MPstr_to_num("0", DEC, e->ans);
2419 exp_del();
2420 show_display(e->ans);
2421 ui_set_statusbar(
2422 _("Activated expression mode with operator precedence"), "");
2424 break;
2426 default:
2427 assert(0);
2429 set_resource(R_SYNTAX, Rsstr[v->syntax]);
2430 ui_set_mode(v->modetype);
2431 // FIXME: We can't allow the display to be editable. See bug #326938
2432 gtk_text_view_set_editable(GTK_TEXT_VIEW(X->display_item),
2433 (v->syntax == exprs));
2437 /*ARGSUSED*/
2438 static void
2439 mode_radio_cb(GtkWidget *radio)
2441 int immediate = 0; /* Set if we can change mode without warning user. */
2442 int complete = 0; /* Set if the user has completed a calculation. */
2444 if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(radio))) {
2445 return;
2448 if (!v->started) {
2449 return;
2452 X->mode = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(radio), "calcmode"));
2454 /* If the user has completed a calculation and we are going to a
2455 * new mode that is "compatible" with this one, then just change
2456 * modes. Otherwise display a dialog warning the user that the
2457 * current calculation will be cleared.
2459 * Incompatible modes are:
2461 * Scientific -> Basic
2462 * Scientific -> Advanced
2463 * Scientific -> Financial
2465 * (unless we are in Scientific mode with Decimal numeric base and Fixed).
2468 switch (v->syntax) {
2469 case npa:
2470 if (v->old_cal_value < 0 ||
2471 v->old_cal_value == KEY_CALCULATE) {
2472 complete = 1; /* Calculation is complete. */
2474 break;
2476 case exprs: {
2477 struct exprm_state *e = get_state();
2478 if (!e->expression || !strcmp(e->expression, "Ans")) {
2479 complete = 1; /* Calculation is complete. */
2484 if (complete) {
2485 if ((v->modetype != SCIENTIFIC) ||
2486 (v->dtype == FIX && v->base == DEC)) {
2487 immediate = 1;
2491 if (immediate) {
2492 v->modetype = X->mode;
2493 reset_mode_display();
2494 do_mode(FALSE);
2495 } else {
2496 if (v->warn_change_mode) {
2497 show_change_mode_dialog();
2498 } else {
2499 change_mode(X->mode);
2505 /*ARGSUSED*/
2506 static void
2507 accuracy_radio_cb(GtkWidget *widget)
2509 int count;
2511 count = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "accuracy"));
2513 if (v->started &&
2514 gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) {
2515 do_accuracy(count);
2520 /*ARGSUSED*/
2521 static void
2522 accuracy_other_cb(GtkWidget *widget)
2524 if (v->started) {
2525 show_precision_frame();
2530 /*ARGSUSED*/
2531 static void
2532 show_trailing_zeroes_cb(GtkWidget *widget)
2534 if (!v->doing_mi) {
2535 v->show_zeroes = gtk_check_menu_item_get_active(
2536 GTK_CHECK_MENU_ITEM(widget));
2538 syntaxdep_show_display();
2539 set_boolean_resource(R_ZEROES, v->show_zeroes == TRUE);
2540 ui_make_registers();
2542 set_show_zeroes_toggle(v->show_zeroes);
2547 /*ARGSUSED*/
2548 static void
2549 quit_cb(GtkWidget *widget)
2551 save_win_position();
2552 gtk_main_quit();
2556 /*ARGSUSED*/
2557 static void
2558 spframe_cancel_cb(GtkButton *button)
2560 gtk_widget_hide(X->spframe);
2564 /*ARGSUSED*/
2565 static gboolean
2566 spframe_key_cb(GtkWidget *widget, GdkEventKey *event)
2568 if (event->keyval == GDK_minus) {
2569 ui_set_statusbar(_("Accuracy value out of range"),
2570 "gtk-dialog-error");
2571 ui_beep();
2572 } else if (event->keyval == GDK_Escape) {
2573 gtk_widget_hide(X->spframe);
2576 return(FALSE);
2580 /*ARGSUSED*/
2581 static void
2582 spframe_ok_cb(GtkButton *button)
2584 int val = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(X->spframe_val));
2586 v->accuracy = val;
2588 set_int_resource(R_ACCURACY, v->accuracy);
2590 ui_set_accuracy(v->accuracy);
2591 set_accuracy_toggle(v->accuracy);
2593 ui_make_registers();
2594 refresh_display();
2596 gtk_widget_hide(X->spframe);
2600 /*ARGSUSED*/
2601 void
2602 trig_cb(GtkWidget *widget)
2604 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
2605 do_trigtype((enum trig_type) g_object_get_data(G_OBJECT(widget),
2606 "response_id"));
2610 void
2611 ui_start()
2613 v->started = 1;
2614 set_item(BASEITEM, v->base);
2615 set_item(TTYPEITEM, v->ttype);
2616 set_item(NUMITEM, v->dtype);
2618 gtk_widget_show(X->kframe);
2620 switch (v->syntax) {
2621 case npa:
2622 break;
2624 case exprs: {
2625 /* Init expression mode.
2626 * This must be executed after do_base is called at init.
2627 * FIXME: The init code here is duplicated elsewhere.
2629 struct exprm_state *e = get_state();
2631 MPstr_to_num("0", DEC, e->ans);
2632 exp_del();
2633 show_display(e->ans);
2635 break;
2637 default:
2638 assert(0);
2641 gtk_main();
2645 /*ARGSUSED*/
2646 static void
2647 show_thousands_separator_cb(GtkWidget *widget)
2649 if (!v->started) {
2650 return;
2653 v->show_tsep = !v->show_tsep;
2655 syntaxdep_show_display();
2656 set_boolean_resource(R_TSEP, v->show_tsep == TRUE);
2657 ui_make_registers();
2661 void
2662 ui_set_registers_visible(int state)
2664 ui_make_registers();
2665 v->rstate = state;
2666 gtk_widget_realize(X->rframe);
2667 if (state && gdk_window_is_visible(X->rframe->window)) {
2668 gdk_window_raise(X->rframe->window);
2669 return;
2672 if (state) {
2673 ds_position_popup(X->kframe, X->rframe, DS_POPUP_ABOVE);
2674 gtk_widget_show(X->rframe);
2675 } else {
2676 gtk_widget_hide(X->rframe);
2681 /*ARGSUSED*/
2682 static void
2683 edit_constants_cb(GtkMenuItem *item)
2685 gtk_widget_show(X->con_dialog);
2689 /*ARGSUSED*/
2690 static void
2691 edit_functions_cb(GtkMenuItem *item)
2693 gtk_widget_show(X->fun_dialog);
2697 static void
2698 create_kframe()
2700 int i;
2701 char name[MAXLINE];
2702 GtkWidget *widget;
2703 PangoFontDescription *font_desc;
2704 GtkSizeGroup *size_group;
2705 GtkAccelGroup *accel_group;
2706 GdkGeometry geometry;
2707 GtkWidget *treeview;
2709 X->ui = glade_xml_new(UI_FILE, NULL, NULL);
2710 if (X->ui == NULL) {
2711 GtkWidget *dialog;
2713 dialog = gtk_message_dialog_new(NULL, 0,
2714 GTK_MESSAGE_ERROR,
2715 GTK_BUTTONS_NONE,
2716 N_("Error loading user interface"));
2717 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
2718 N_("The user interace file %s is missing or unable to be loaded. Please check your installation."), UI_FILE);
2719 gtk_dialog_add_buttons(GTK_DIALOG(dialog), GTK_STOCK_QUIT, GTK_RESPONSE_ACCEPT, NULL);
2721 gtk_dialog_run(GTK_DIALOG(dialog));
2722 exit(0);
2725 X->kframe = GET_WIDGET("calc_window");
2727 X->aframe = GET_WIDGET("ascii_window");
2728 gtk_window_set_transient_for(GTK_WINDOW(X->aframe), GTK_WINDOW(X->kframe));
2729 X->aframe_ch = GET_WIDGET("ascii_entry");
2731 X->spframe = GET_WIDGET("precision_dialog");
2732 X->spframe_val = GET_WIDGET("spframe_spin");
2733 gtk_window_set_transient_for(GTK_WINDOW(X->spframe), GTK_WINDOW(X->kframe));
2734 gtk_spin_button_set_value(GTK_SPIN_BUTTON(X->spframe_val),
2735 (double) v->accuracy);
2736 gtk_entry_set_max_length(GTK_ENTRY(X->spframe_val), 2);
2738 X->rframe = GET_WIDGET("register_dialog");
2739 g_object_set_data(G_OBJECT(X->rframe), "rframe", X->rframe);
2740 gtk_window_set_transient_for(GTK_WINDOW(X->rframe), GTK_WINDOW(X->kframe));
2742 for (i = 0; i < MAXREGS; i++) {
2743 SNPRINTF(name, MAXLINE, "register_entry_%d", i);
2744 X->regs[i] = GET_WIDGET(name);
2745 gtk_entry_set_text(GTK_ENTRY(X->regs[i]),
2746 make_number(v->MPmvals[i], v->base, TRUE));
2749 X->con_dialog = GET_WIDGET("edit_constants_dialog");
2750 treeview = GET_WIDGET("edit_constants_treeview");
2751 gtk_dialog_set_default_response(GTK_DIALOG(X->con_dialog),
2752 GTK_RESPONSE_ACCEPT);
2753 gtk_window_set_transient_for(GTK_WINDOW(X->con_dialog),
2754 GTK_WINDOW(X->kframe));
2755 gtk_window_set_geometry_hints(GTK_WINDOW(X->con_dialog), X->con_dialog,
2756 &geometry, GDK_HINT_MIN_SIZE);
2757 X->constants_model = create_cf_model(M_CON, X->con_dialog);
2758 gtk_tree_view_set_model(GTK_TREE_VIEW(treeview), X->constants_model);
2759 gtk_tree_selection_set_mode(
2760 gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)),
2761 GTK_SELECTION_SINGLE);
2762 add_cf_column(GTK_TREE_VIEW(treeview), _("No."),
2763 COLUMN_NUMBER, FALSE);
2764 add_cf_column(GTK_TREE_VIEW(treeview), _("Value"),
2765 COLUMN_VALUE, TRUE);
2766 add_cf_column(GTK_TREE_VIEW(treeview), _("Description"),
2767 COLUMN_DESCRIPTION, TRUE);
2769 X->fun_dialog = GET_WIDGET("edit_functions_dialog");
2770 treeview = GET_WIDGET("edit_functions_treeview");
2771 gtk_dialog_set_default_response(GTK_DIALOG(X->fun_dialog),
2772 GTK_RESPONSE_ACCEPT);
2773 gtk_window_set_transient_for(GTK_WINDOW(X->fun_dialog),
2774 GTK_WINDOW(X->kframe));
2775 gtk_window_set_geometry_hints(GTK_WINDOW(X->fun_dialog), X->fun_dialog,
2776 &geometry, GDK_HINT_MIN_SIZE);
2777 X->functions_model = create_cf_model(M_FUN, X->fun_dialog);
2778 gtk_tree_view_set_model(GTK_TREE_VIEW(treeview), X->functions_model);
2779 gtk_tree_selection_set_mode(
2780 gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)),
2781 GTK_SELECTION_SINGLE);
2782 add_cf_column(GTK_TREE_VIEW(treeview), _("No."),
2783 COLUMN_NUMBER, FALSE);
2784 add_cf_column(GTK_TREE_VIEW(treeview), _("Value"),
2785 COLUMN_VALUE, TRUE);
2786 add_cf_column(GTK_TREE_VIEW(treeview), _("Description"),
2787 COLUMN_DESCRIPTION, TRUE);
2789 /* When connecting up signals, would ideally use autoconnect but not
2790 * sure how to get the build process working.
2791 * See http://library.gnome.org/devel/libglade/unstable and
2792 * http://www.jamesh.id.au/software/libglade/
2793 * for some information on how to get this to work
2794 * glade_xml_signal_autoconnect(X->ui);
2796 CONNECT_SIGNAL(kframe_key_press_cb);
2797 CONNECT_SIGNAL(button_cb);
2798 CONNECT_SIGNAL(menu_item_select_cb);
2799 CONNECT_SIGNAL(menu_item_deselect_cb);
2800 CONNECT_SIGNAL(mode_radio_cb);
2801 CONNECT_SIGNAL(inv_cb);
2802 CONNECT_SIGNAL(hyp_cb);
2803 CONNECT_SIGNAL(trig_cb);
2804 CONNECT_SIGNAL(base_cb);
2805 CONNECT_SIGNAL(disp_cb);
2806 CONNECT_SIGNAL(quit_cb);
2807 CONNECT_SIGNAL(edit_cb);
2808 CONNECT_SIGNAL(copy_cb);
2809 CONNECT_SIGNAL(paste_cb);
2810 CONNECT_SIGNAL(insert_ascii_cb);
2811 CONNECT_SIGNAL(undo_cb);
2812 CONNECT_SIGNAL(redo_cb);
2813 CONNECT_SIGNAL(help_cb);
2814 CONNECT_SIGNAL(about_cb);
2815 CONNECT_SIGNAL(show_trailing_zeroes_cb);
2816 CONNECT_SIGNAL(show_thousands_separator_cb);
2817 CONNECT_SIGNAL(show_bitcalculating_cb);
2818 CONNECT_SIGNAL(show_registers_cb);
2819 CONNECT_SIGNAL(accuracy_radio_cb);
2820 CONNECT_SIGNAL(accuracy_other_cb);
2821 CONNECT_SIGNAL(arithmetic_mode_cb);
2822 CONNECT_SIGNAL(mouse_button_cb);
2823 CONNECT_SIGNAL(display_focus_in_cb);
2824 CONNECT_SIGNAL(display_focus_out_cb);
2825 /* Detect when populating the right-click menu to enable pasting */
2826 CONNECT_SIGNAL(buffer_populate_popup_cb);
2827 CONNECT_SIGNAL(shift_left_cb);
2828 CONNECT_SIGNAL(shift_right_cb);
2829 CONNECT_SIGNAL(bit_toggled);
2830 CONNECT_SIGNAL(dismiss_aframe);
2831 CONNECT_SIGNAL(aframe_ok_cb);
2832 CONNECT_SIGNAL(aframe_cancel_cb);
2833 CONNECT_SIGNAL(aframe_key_cb);
2834 CONNECT_SIGNAL(dismiss_spframe);
2835 CONNECT_SIGNAL(spframe_ok_cb);
2836 CONNECT_SIGNAL(spframe_cancel_cb);
2837 CONNECT_SIGNAL(spframe_key_cb);
2838 CONNECT_SIGNAL(dismiss_rframe);
2839 CONNECT_SIGNAL(mem_response);
2840 CONNECT_SIGNAL(edit_constants_cb);
2841 CONNECT_SIGNAL(edit_functions_cb);
2842 CONNECT_SIGNAL(edit_constants_response_cb);
2843 CONNECT_SIGNAL(edit_functions_response_cb);
2845 widget = GET_WIDGET("kvbox");
2846 gtk_widget_set_direction(widget, GTK_TEXT_DIR_LTR );
2848 X->menubar = GET_WIDGET("menubar");
2850 gtk_widget_set_sensitive(GET_WIDGET("show_registers_menu"),
2851 (v->modetype != BASIC));
2853 X->scrolledwindow = GET_WIDGET("display_scroll"),
2855 X->display_item = GET_WIDGET("displayitem"),
2856 X->display_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(X->display_item));
2857 gtk_widget_ensure_style(X->display_item);
2858 font_desc = pango_font_description_copy(X->display_item->style->font_desc);
2859 pango_font_description_set_size(font_desc, 16 * PANGO_SCALE);
2860 gtk_widget_modify_font(X->display_item, font_desc);
2861 pango_font_description_free(font_desc);
2862 gtk_widget_set_name(X->display_item, "displayitem");
2863 // FIXME: We can't allow the display to be editable. See bug #326938
2864 gtk_text_view_set_editable(GTK_TEXT_VIEW(X->display_item),
2865 (v->syntax == exprs));
2867 atk_object_set_role(gtk_widget_get_accessible(X->display_item),
2868 ATK_ROLE_EDITBAR);
2869 ui_set_display("0.00", FALSE);
2871 gtk_widget_realize(X->kframe);
2872 set_win_position();
2874 X->bas_panel = GET_WIDGET("basic_panel");
2875 X->sci_panel = GET_WIDGET("scientific_panel");
2876 X->adv_panel = GET_WIDGET("advanced_panel");
2877 X->fin_panel = GET_WIDGET("financial_panel");
2878 gtk_widget_set_direction(X->fin_panel, GTK_TEXT_DIR_LTR);
2880 size_group = gtk_size_group_new(GTK_SIZE_GROUP_BOTH);
2881 for (i = 0; i < NBUTTONS; i++) {
2882 SNPRINTF(name, MAXLINE, "calc_%s_button",
2883 button_widgets[i].widget_name);
2884 X->buttons[i] = GET_WIDGET(name);
2885 assert(X->buttons[i] != NULL);
2887 gtk_size_group_add_widget(size_group, X->buttons[i]);
2889 g_object_set_data(G_OBJECT(X->buttons[i]), "button",
2890 &buttons[button_widgets[i].key]);
2891 g_object_set_data(G_OBJECT(X->buttons[i]), "mtype",
2892 GINT_TO_POINTER(button_widgets[i].mtype));
2895 for (i = 0; i < 16; i++) {
2896 SNPRINTF(name, MAXLINE, "calc_%x_button", i);
2897 X->digit_buttons[i] = GET_WIDGET(name);
2900 SNPRINTF(name, MAXLINE, "calc_%d_button", i);
2901 X->clear_buttons[0] = GET_WIDGET("calc_clear_simple_button");
2902 X->clear_buttons[1] = GET_WIDGET("calc_clear_advanced_button");
2904 X->mode_panel = GET_WIDGET("mode_panel");
2905 X->trig[0] = GET_WIDGET("degrees_radio");
2906 X->trig[1] = GET_WIDGET("gradians_radio");
2907 X->trig[2] = GET_WIDGET("radians_radio");
2908 X->base[0] = GET_WIDGET("binary_radio");
2909 X->base[1] = GET_WIDGET("octal_radio");
2910 X->base[2] = GET_WIDGET("decimal_radio");
2911 X->base[3] = GET_WIDGET("hexadecimal_radio");
2912 X->disp[0] = GET_WIDGET("engineering_radio");
2913 X->disp[1] = GET_WIDGET("fixed_point_radio");
2914 X->disp[2] = GET_WIDGET("scientific_radio");
2915 X->inv = GET_WIDGET("inverse_check");
2916 X->hyp = GET_WIDGET("hyperbolic_check");
2917 for (i = 0; i < 3; i++)
2918 g_object_set_data(G_OBJECT(X->trig[i]),
2919 "response_id", GINT_TO_POINTER(i));
2920 for (i = 0; i < 4; i++)
2921 g_object_set_data(G_OBJECT(X->base[i]),
2922 "response_id", GINT_TO_POINTER(i));
2923 for (i = 0; i < 3; i++)
2924 g_object_set_data(G_OBJECT(X->disp[i]),
2925 "response_id", GINT_TO_POINTER(i));
2927 X->bit_panel = GET_WIDGET("bit_panel");
2928 //gtk_widget_set_direction(table, GTK_TEXT_DIR_LTR);
2929 for (i = 0; i < MAXBITS; i++)
2931 SNPRINTF(name, MAXLINE, "bit_label_%d", i);
2932 X->bits[i] = GET_WIDGET(name);
2933 SNPRINTF(name, MAXLINE, "bit_eventbox_%d", i);
2934 g_object_set_data(G_OBJECT(GET_WIDGET(name)),
2935 "widget_index", GINT_TO_POINTER(i));
2938 ui_set_base(v->base);
2939 if (v->modetype == BASIC) {
2940 gtk_window_set_focus(GTK_WINDOW(X->kframe),
2941 GTK_WIDGET(X->clear_buttons[0]));
2942 } else {
2943 gtk_window_set_focus(GTK_WINDOW(X->kframe),
2944 GTK_WIDGET(X->clear_buttons[1]));
2947 X->statusbar = GET_WIDGET("statusbar");
2948 X->status_image = gtk_image_new_from_stock("", GTK_ICON_SIZE_BUTTON);
2949 gtk_widget_show(X->status_image);
2950 gtk_box_pack_start(GTK_BOX(X->statusbar), X->status_image, FALSE, TRUE, 0);
2952 /* Use loaded Arithmetic Precedence mode setting. */
2953 if (v->syntax == exprs) {
2954 widget = GET_WIDGET("arithmetic_precedence_menu");
2955 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget), TRUE);
2956 } else {
2957 widget = GET_WIDGET("ltr_precedence_menu");
2958 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget), TRUE);
2961 X->undo = GET_WIDGET("undo_menu");
2962 X->redo = GET_WIDGET("redo_menu");
2963 X->copy = GET_WIDGET("copy_menu");
2964 X->paste = GET_WIDGET("paste_menu");
2966 /* Make menu tooltips displayed in the status bar */
2967 set_menubar_tooltip("quit_menu");
2968 set_menubar_tooltip("copy_menu");
2969 set_menubar_tooltip("paste_menu");
2970 set_menubar_tooltip("insert_ascii_menu");
2971 set_menubar_tooltip("undo_menu");
2972 set_menubar_tooltip("redo_menu");
2973 set_menubar_tooltip("view_basic_menu");
2974 set_menubar_tooltip("view_advanced_menu");
2975 set_menubar_tooltip("view_financial_menu");
2976 set_menubar_tooltip("view_scientific_menu");
2977 set_menubar_tooltip("show_trailing_zeroes_menu");
2978 set_menubar_tooltip("show_thousands_separator_menu");
2979 set_menubar_tooltip("show_bitcalculating_menu");
2980 set_menubar_tooltip("show_registers_menu");
2981 set_menubar_tooltip("ltr_precedence_menu");
2982 set_menubar_tooltip("arithmetic_precedence_menu");
2983 set_menubar_tooltip("help_menu");
2984 set_menubar_tooltip("about_menu");
2986 ui_set_undo_enabled(FALSE, FALSE);
2988 /* Connect up menu callbacks */
2989 for (i = 1; i < 16; i++) {
2990 SNPRINTF(name, MAXLINE, "shift_left%d_menu", i);
2991 g_object_set_data(G_OBJECT(GET_WIDGET(name)),
2992 "shiftcount", GINT_TO_POINTER(i));
2993 SNPRINTF(name, MAXLINE, "shift_right%d_menu", i);
2994 g_object_set_data(G_OBJECT(GET_WIDGET(name)),
2995 "shiftcount", GINT_TO_POINTER(i));
2997 g_object_set_data(G_OBJECT(GET_WIDGET("view_basic_menu")),
2998 "calcmode", GINT_TO_POINTER(BASIC));
2999 g_object_set_data(G_OBJECT(GET_WIDGET("view_advanced_menu")),
3000 "calcmode", GINT_TO_POINTER(ADVANCED));
3001 g_object_set_data(G_OBJECT(GET_WIDGET("view_financial_menu")),
3002 "calcmode", GINT_TO_POINTER(FINANCIAL));
3003 g_object_set_data(G_OBJECT(GET_WIDGET("view_scientific_menu")),
3004 "calcmode", GINT_TO_POINTER(SCIENTIFIC));
3006 /* Make shortcuts for accuracy menus */
3007 accel_group = gtk_accel_group_new();
3008 gtk_window_add_accel_group(GTK_WINDOW(X->kframe), accel_group);
3009 for (i = 0; i < 10; i++) {
3010 SNPRINTF(name, MAXLINE, "acc_item%d", i);
3011 widget = GET_WIDGET(name);
3012 g_object_set_data(G_OBJECT(widget), "accuracy", GINT_TO_POINTER(i));
3017 static GtkWidget *
3018 create_menu_item_with_markup(char *label, int menu_no, int index)
3020 GtkWidget *accel_label;
3021 GtkWidget *menu_item;
3023 accel_label = gtk_label_new(NULL);
3024 gtk_label_set_markup_with_mnemonic(GTK_LABEL(accel_label), label);
3025 gtk_misc_set_alignment(GTK_MISC(accel_label), 0.0, 0.5);
3026 menu_item = gtk_menu_item_new();
3027 gtk_container_add(GTK_CONTAINER(menu_item), accel_label);
3028 gtk_widget_show(accel_label);
3029 gtk_widget_show(menu_item);
3031 g_object_set_data(G_OBJECT(menu_item), "button", X->mrec[menu_no]);
3032 gtk_menu_shell_append(GTK_MENU_SHELL(X->menus[menu_no]), menu_item);
3034 g_signal_connect(G_OBJECT(menu_item), "activate",
3035 G_CALLBACK(menu_proc_cb), GINT_TO_POINTER(index));
3037 return menu_item;
3041 static void
3042 read_cfdefs() /* Read constant/function definitions. */
3044 int n;
3046 for (n = 0; n < MAXCONFUN; n++) {
3047 get_constant(n);
3048 STRCPY(v->fun_vals[n], ""); /* Initially empty function strings. */
3049 get_function(n);
3054 void
3055 ui_init(int *argc, char ***argv)
3057 X = (XVars) LINT_CAST(calloc(1, sizeof(struct Xobject)));
3059 gtk_init(argc, argv);
3061 X->lnp = ui_get_localized_numeric_point();
3063 gtk_rc_get_default_files();
3065 v->home = (char *) g_get_home_dir();
3066 gtk_rc_parse(g_build_path(v->home, RCNAME, NULL));
3068 gtk_window_set_default_icon_name("gnome-calculator");
3071 void
3072 ui_load()
3074 int i;
3076 read_cfdefs();
3078 X->clipboard_atom = gdk_atom_intern("CLIPBOARD", FALSE);
3079 X->primary_atom = gdk_atom_intern("PRIMARY", FALSE);
3080 create_kframe(); /* Create main gcalctool window. */
3081 ui_set_mode(v->modetype);
3083 X->menus[M_ACC] = GET_WIDGET("accuracy_popup");
3084 X->mrec[M_ACC] = &buttons[KEY_SET_ACCURACY];
3085 ui_set_accuracy(v->accuracy);
3086 X->menus[M_LSHF] = GET_WIDGET("left_shift_popup");
3087 X->mrec[M_LSHF] = &buttons[KEY_LEFT_SHIFT];
3088 X->menus[M_RSHF] = GET_WIDGET("right_shift_popup");
3089 X->mrec[M_RSHF] = &buttons[KEY_RIGHT_SHIFT];
3091 X->menus[M_CON] = GET_WIDGET("constants_popup");
3092 X->mrec[M_CON] = &buttons[KEY_CONSTANT];
3093 X->menus[M_FUN] = GET_WIDGET("functions_popup");
3094 X->mrec[M_FUN] = &buttons[KEY_FUNCTION];
3095 for (i = 0; i < MAXCONFUN; i++) {
3096 X->constant_menu_items[i] = create_menu_item_with_markup("", M_CON, i);
3097 X->function_menu_items[i] = create_menu_item_with_markup("", M_FUN, i);
3100 X->menus[M_STO] = GET_WIDGET("memory_store_popup");
3101 X->mrec[M_STO] = &buttons[KEY_STORE];
3102 X->menus[M_RCL] = GET_WIDGET("memory_recall_popup");
3103 X->mrec[M_RCL] = &buttons[KEY_RECALL];
3104 X->menus[M_EXCH] = GET_WIDGET("memory_exchange_popup");
3105 X->mrec[M_EXCH] = &buttons[KEY_EXCHANGE];
3106 for (i = 0; i < MAXREGS; i++) {
3107 // FIXME: These labels should be replaced with GtkTreeModel labels
3108 X->memory_store_items[i] = create_menu_item_with_markup("", M_STO, i);
3109 X->memory_recall_items[i] = create_menu_item_with_markup("", M_RCL, i);
3110 X->memory_exchange_items[i] = create_menu_item_with_markup("", M_EXCH, i);
3113 // This matches existing behaviour we can't do in Glade. But is it needed?
3114 gtk_container_set_border_width(GTK_CONTAINER(X->menus[M_ACC]), 1);
3115 gtk_container_set_border_width(GTK_CONTAINER(X->menus[M_LSHF]), 1);
3116 gtk_container_set_border_width(GTK_CONTAINER(X->menus[M_RSHF]), 1);
3117 gtk_container_set_border_width(GTK_CONTAINER(X->menus[M_CON]), 1);
3118 gtk_container_set_border_width(GTK_CONTAINER(X->menus[M_FUN]), 1);
3119 gtk_container_set_border_width(GTK_CONTAINER(X->menus[M_STO]), 1);
3120 gtk_container_set_border_width(GTK_CONTAINER(X->menus[M_RCL]), 1);
3121 gtk_container_set_border_width(GTK_CONTAINER(X->menus[M_EXCH]), 1);
3123 set_accuracy_toggle(v->accuracy);
3124 set_show_tsep_toggle(v->show_tsep);
3125 set_show_zeroes_toggle(v->show_zeroes);
3126 set_show_bitcalculating_toggle(v->bitcalculating_mode);
3127 set_memory_toggle(v->rstate);
3129 ui_set_mode(v->modetype);
3131 /* Show the memory register window? */
3132 if (v->rstate == TRUE && !v->iconic) {
3133 ui_set_registers_visible(TRUE);