4 * Copyright (c) 1987-2007 Sun Microsystems, Inc. All Rights Reserved.
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)
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
27 #include <sys/param.h>
33 #include "functions.h"
34 #include "lr_parser.h"
37 #include <gdk/gdkkeysyms.h>
38 #include <glade/glade.h>
39 #include <gconf/gconf-client.h>
40 #include "ce_parser.h"
43 /* Popup menu types. */
44 /* FIXME: This enum could be removed */
45 enum menu_type
{ M_ACC
, M_CON
, M_EXCH
, M_FUN
, M_LSHF
,
46 M_RCL
, M_RSHF
, M_STO
, M_NONE
};
47 #define MAXMENUS 9 /* Maximum number of popup menus. */
49 #define MAX_ACCELERATORS 8
50 struct button_widget
{
54 guint accelerator_mods
[MAX_ACCELERATORS
];
55 guint accelerator_keys
[MAX_ACCELERATORS
];
58 /* This table shows the keyboard values that are currently being used:
60 * | 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
61 *-----------+-----------------------------------------------------
62 * Lower: | a b c d e f i l m n p r s t u v x
63 * Upper: | A C D E F G J K L M N P R S T X Y
64 * Numeric: | 0 1 2 3 4 5 6 7 8 9
65 * Other: | @ . + - * / = % ( ) # < > [ ] { } | & ~ ^ ? ! :
66 * | BackSpace Delete Return
67 *-----------+-----------------------------------------------------
70 static struct button_widget button_widgets
[] = {
72 { 0, GDK_SHIFT_MASK
, 0, 0, 0 },
73 { GDK_0
, GDK_0
, GDK_KP_0
, GDK_KP_Insert
, 0 }},
76 { 0, GDK_SHIFT_MASK
, 0, 0, 0, 0 },
77 { GDK_1
, GDK_1
, GDK_KP_1
, GDK_KP_End
, GDK_R13
, 0 }},
80 { 0, GDK_SHIFT_MASK
, 0, 0, 0 },
81 { GDK_2
, GDK_2
, GDK_KP_2
, GDK_KP_Down
, 0 }},
84 { 0, GDK_SHIFT_MASK
, 0, 0, 0, 0 },
85 { GDK_3
, GDK_3
, GDK_KP_3
, GDK_KP_Page_Down
, GDK_R15
, 0 }},
88 { 0, GDK_SHIFT_MASK
, 0, 0, 0 },
89 { GDK_4
, GDK_4
, GDK_KP_4
, GDK_KP_Left
, 0 }},
92 { 0, GDK_SHIFT_MASK
, 0, 0, 0, 0 },
93 { GDK_5
, GDK_5
, GDK_KP_5
, GDK_KP_Begin
, GDK_R11
, 0 }},
96 { 0, GDK_SHIFT_MASK
, 0, 0, 0 },
97 { GDK_6
, GDK_6
, GDK_KP_6
, GDK_KP_Right
, 0 }},
100 { 0, GDK_SHIFT_MASK
, 0, 0, 0, 0 },
101 { GDK_7
, GDK_7
, GDK_KP_7
, GDK_KP_Home
, GDK_R7
, 0 }},
104 { 0, GDK_SHIFT_MASK
, 0, 0, 0 },
105 { GDK_8
, GDK_8
, GDK_KP_8
, GDK_KP_Up
, 0 }},
108 { 0, GDK_SHIFT_MASK
, 0, 0, 0, 0 },
109 { GDK_9
, GDK_9
, GDK_KP_9
, GDK_KP_Page_Up
, GDK_R9
, 0 }},
135 {KEY_CLEAR
, "clear_simple", M_NONE
,
139 {KEY_CLEAR
, "clear_advanced", M_NONE
,
143 {KEY_LEFT_SHIFT
, "shift_left", M_LSHF
,
144 { GDK_SHIFT_MASK
, 0 },
147 {KEY_RIGHT_SHIFT
, "shift_right", M_RSHF
,
148 { GDK_SHIFT_MASK
, 0 },
151 {KEY_SET_ACCURACY
, "accuracy", M_ACC
,
152 { GDK_SHIFT_MASK
, 0 },
155 {KEY_CONSTANT
, "constants", M_CON
,
156 { GDK_SHIFT_MASK
, 0, 0 },
157 { GDK_numbersign
, GDK_numbersign
, 0 }},
159 {KEY_FUNCTION
, "functions", M_FUN
,
160 { GDK_SHIFT_MASK
, 0 },
163 {KEY_STORE
, "store", M_STO
,
164 { GDK_SHIFT_MASK
, 0 },
167 {KEY_RECALL
, "recall", M_RCL
,
168 { GDK_SHIFT_MASK
, 0 },
171 {KEY_EXCHANGE
, "exchange", M_EXCH
,
172 { GDK_SHIFT_MASK
, 0 },
175 {KEY_CLEAR_ENTRY
, "clear_entry_simple", M_NONE
,
176 { GDK_CONTROL_MASK
, 0, 0 },
177 { GDK_BackSpace
, GDK_Escape
, 0 }},
179 {KEY_CLEAR_ENTRY
, "clear_entry_advanced", M_NONE
,
180 { GDK_CONTROL_MASK
, 0, 0 },
181 { GDK_BackSpace
, GDK_Escape
, 0 }},
183 {KEY_BACKSPACE
, "backspace_simple", M_NONE
,
185 { GDK_BackSpace
, 0 }},
187 {KEY_BACKSPACE
, "backspace_advanced", M_NONE
,
189 { GDK_BackSpace
, 0 }},
191 {KEY_NUMERIC_POINT
, "numeric_point", M_NONE
,
193 { GDK_period
, GDK_KP_Decimal
, GDK_KP_Delete
, GDK_KP_Separator
, 0 }},
195 {KEY_CALCULATE
, "result", M_NONE
,
196 { 0, 0, 0, GDK_SHIFT_MASK
, 0 },
197 { GDK_equal
, GDK_KP_Enter
, GDK_Return
, GDK_equal
, 0 }},
199 {KEY_START_BLOCK
, "start_group", M_NONE
,
200 { GDK_SHIFT_MASK
, 0 },
201 { GDK_parenleft
, 0 }},
203 {KEY_END_BLOCK
, "end_group", M_NONE
,
204 { GDK_SHIFT_MASK
, 0 },
205 { GDK_parenright
, 0 }},
207 {KEY_ADD
, "add", M_NONE
,
208 { GDK_SHIFT_MASK
, 0, 0, 0 },
209 { GDK_plus
, GDK_plus
, GDK_KP_Add
, 0 }},
211 {KEY_SUBTRACT
, "subtract", M_NONE
,
213 { GDK_minus
, GDK_KP_Subtract
, GDK_R4
, 0 }},
215 {KEY_MULTIPLY
, "multiply", M_NONE
,
216 { GDK_SHIFT_MASK
, 0, 0, 0, 0 },
217 { GDK_asterisk
, GDK_KP_Multiply
, GDK_x
, GDK_R6
, 0 }},
219 {KEY_DIVIDE
, "divide", M_NONE
,
220 { 0, GDK_SHIFT_MASK
, 0, 0, GDK_SHIFT_MASK
, 0 },
221 { GDK_slash
, GDK_slash
, GDK_KP_Divide
, GDK_R5
, GDK_slash
, 0 }},
223 {KEY_CHANGE_SIGN
, "change_sign_simple", M_NONE
,
224 { GDK_SHIFT_MASK
, 0 },
227 {KEY_CHANGE_SIGN
, "change_sign_advanced", M_NONE
,
228 { GDK_SHIFT_MASK
, 0 },
231 {KEY_INTEGER
, "integer_portion", M_NONE
,
235 {KEY_FRACTION
, "fractional_portion", M_NONE
,
236 { GDK_SHIFT_MASK
, 0 },
239 {KEY_PERCENTAGE
, "percentage", M_NONE
,
240 { GDK_SHIFT_MASK
, 0 },
243 {KEY_SQUARE
, "square", M_NONE
,
244 { GDK_SHIFT_MASK
, 0 },
247 {KEY_SQUARE_ROOT
, "sqrt", M_NONE
,
251 {KEY_RECIPROCAL
, "reciprocal", M_NONE
,
255 {KEY_ABSOLUTE_VALUE
, "abs", M_NONE
,
259 {KEY_MASK_16
, "mask_16", M_NONE
,
261 { GDK_bracketright
, 0 }},
263 {KEY_MASK_32
, "mask_32", M_NONE
,
265 { GDK_bracketleft
, 0 }},
267 {KEY_MODULUS_DIVIDE
, "modulus_divide", M_NONE
,
268 { GDK_SHIFT_MASK
, 0 },
271 {KEY_EXPONENTIAL
, "exponential", M_NONE
,
272 { GDK_SHIFT_MASK
, 0 },
275 {KEY_E_POW_X
, "pow_e", M_NONE
,
276 { GDK_SHIFT_MASK
, 0 },
277 { GDK_braceleft
, 0 }},
279 {KEY_10_POW_X
, "pow_10", M_NONE
,
280 { GDK_SHIFT_MASK
, 0 },
281 { GDK_braceright
, 0 }},
283 {KEY_X_POW_Y
, "x_pow_y", M_NONE
,
284 { GDK_SHIFT_MASK
, GDK_SHIFT_MASK
, 0 },
285 { GDK_caret
, GDK_asciicircum
, 0 }},
287 {KEY_NATURAL_LOGARITHM
, "natural_logarithm", M_NONE
,
288 { GDK_SHIFT_MASK
, 0 },
291 {KEY_LOGARITHM
, "logarithm", M_NONE
,
292 { GDK_SHIFT_MASK
, 0 },
295 {KEY_FACTORIAL
, "factorial", M_NONE
,
296 { GDK_SHIFT_MASK
, 0 },
299 {KEY_RANDOM
, "random", M_NONE
,
300 { GDK_SHIFT_MASK
, 0 },
301 { GDK_question
, 0 }},
303 {KEY_SINE
, "sine", M_NONE
,
304 { GDK_SHIFT_MASK
, 0 },
307 {KEY_COSINE
, "cosine", M_NONE
,
308 { GDK_SHIFT_MASK
, 0 },
311 {KEY_TANGENT
, "tangent", M_NONE
,
312 { GDK_SHIFT_MASK
, 0 },
315 {KEY_NOT
, "not", M_NONE
,
316 { GDK_SHIFT_MASK
, 0 },
317 { GDK_asciitilde
, 0 }},
319 {KEY_OR
, "or", M_NONE
,
320 { GDK_SHIFT_MASK
, 0 },
323 {KEY_AND
, "and", M_NONE
,
324 { GDK_SHIFT_MASK
, 0 },
325 { GDK_ampersand
, 0 }},
327 {KEY_XOR
, "xor", M_NONE
,
331 {KEY_XNOR
, "xnor", M_NONE
,
335 {KEY_FINC_CTRM
, "finc_compounding_term", M_NONE
,
339 {KEY_FINC_DDB
, "finc_double_declining_depreciation", M_NONE
,
340 { GDK_SHIFT_MASK
, 0 },
343 {KEY_FINC_FV
, "finc_future_value", M_NONE
,
347 {KEY_FINC_PMT
, "finc_periodic_payment", M_NONE
,
348 { GDK_SHIFT_MASK
, 0 },
351 {KEY_FINC_PV
, "finc_present_value", M_NONE
,
355 {KEY_FINC_RATE
, "finc_periodic_interest_rate", M_NONE
,
356 { GDK_SHIFT_MASK
, 0 },
359 {KEY_FINC_SLN
, "finc_straight_line_depreciation", M_NONE
,
363 {KEY_FINC_SYD
, "finc_sum_of_the_years_digits_depreciation", M_NONE
,
367 {KEY_FINC_TERM
, "finc_term", M_NONE
,
371 #define NBUTTONS (sizeof(button_widgets) / sizeof(struct button_widget))
373 #define UI_FILE PACKAGE_GLADE_DIR "/gcalctool.glade"
375 #define MAXBITS 64 /* Bit panel: number of bit fields. */
377 #define GET_WIDGET(name) \
378 glade_xml_get_widget(X->ui, (name))
380 #define SET_MENUBAR_ITEM_STATE(name, state) \
381 g_object_set_data(G_OBJECT(GET_WIDGET(name)), "sensitive", \
382 GINT_TO_POINTER(state));
384 #define CONNECT_SIGNAL(name) glade_xml_signal_connect(X->ui, #name, \
387 struct Xobject
{ /* Gtk+/Xlib graphics object. */
388 GdkAtom clipboard_atom
;
389 GdkAtom primary_atom
;
394 GtkWidget
*kframe
; /* Main window. */
396 GtkWidget
*cm_dialog
; /* Change Mode dialog. */
397 GtkTreeModel
*constants_model
;
398 GtkWidget
*con_dialog
; /* Edit constants dialog. */
400 GtkTreeModel
*functions_model
;
401 GtkWidget
*fun_dialog
; /* Edit functions dialog. */
402 GtkWidget
*menubar
; // FIXME: Why is this needed?
404 GtkWidget
*bit_panel
;
405 GtkWidget
*bits
[MAXBITS
]; /* The 0/1 labels in the bit panel. */
407 GtkWidget
*status_image
; /* Statusbar image */
408 GtkWidget
*statusbar
;
410 GtkWidget
*undo
; /* Undo menuitem */
411 GtkWidget
*redo
; /* Redo menuitem */
412 GtkWidget
*copy
; /* Copy menuitem */
413 GtkWidget
*paste
; /* Paste menuitem */
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
[MAXREGS
]; /* Memory registers. */
425 GtkWidget
*spframe
; /* Set Precision window. */
426 GtkWidget
*spframe_val
;
427 GtkWidget
*menus
[MAXMENUS
];
429 GtkWidget
*buttons
[NBUTTONS
];
430 GtkWidget
*digit_buttons
[16];
431 GtkWidget
*clear_buttons
[2];
433 GtkWidget
*bas_panel
; /* Panel containing basic mode widgets. */
434 GtkWidget
*adv_panel
; /* Panel containing advanced mode widgets. */
435 GtkWidget
*fin_panel
; /* Panel containing financial mode widgets. */
436 GtkWidget
*sci_panel
; /* Panel containing scientific mode widgets. */
437 GtkWidget
*mode_panel
; /* Panel containing scientific mode widgets. */
439 /* Labels for popup menus */
440 GtkWidget
*constant_menu_items
[MAXCONFUN
];
441 GtkWidget
*function_menu_items
[MAXCONFUN
];
442 GtkWidget
*memory_store_items
[MAXREGS
];
443 GtkWidget
*memory_recall_items
[MAXREGS
];
444 GtkWidget
*memory_exchange_items
[MAXREGS
];
446 /* Scientific mode widgets */
447 GtkWidget
*hyp
; /* Hyperbolic mode. */
448 GtkWidget
*inv
; /* Inverse mode. */
449 GtkWidget
*base
[MAXBASES
]; /* Numeric base radio buttons. */
450 GtkWidget
*disp
[MAXDISPMODES
]; /* Numeric display mode. */
451 GtkWidget
*trig
[MAXTRIGMODES
]; /* Trigonometric mode. */
453 int mode
; /* The new mode. */
454 int menuval
; /* Index to button array at menu time. */
455 char *lnp
; /* Localized numerical point (UTF8 format) */
456 struct button
*mrec
[MAXMENUS
];
459 typedef struct Xobject
*XVars
;
472 main(int argc
, char **argv
)
474 v
= (Vars
) LINT_CAST(calloc(1, sizeof(struct calcVars
)));
475 X
= (XVars
) LINT_CAST(calloc(1, sizeof(struct Xobject
)));
477 bindtextdomain(GETTEXT_PACKAGE
, PACKAGE_LOCALE_DIR
);
478 bind_textdomain_codeset(GETTEXT_PACKAGE
, "UTF-8");
479 textdomain(GETTEXT_PACKAGE
);
481 gtk_init(&argc
, &argv
);
483 X
->lnp
= get_localized_numeric_point();
485 gtk_rc_get_default_files();
487 v
->home
= (char *) g_get_home_dir();
488 gtk_rc_parse(g_build_path(v
->home
, RCNAME
, NULL
));
490 gtk_window_set_default_icon_name("gnome-calculator");
492 do_calctool(argc
, argv
);
499 update_statusbar(gchar
*text
, const gchar
*imagename
)
501 GtkImage
*image
= GTK_IMAGE(X
->status_image
);
507 gtk_image_set_from_stock(image
, imagename
, GTK_ICON_SIZE_BUTTON
);
508 gtk_statusbar_pop(GTK_STATUSBAR(X
->statusbar
), 0);
509 gtk_statusbar_push(GTK_STATUSBAR(X
->statusbar
), 0, text
);
514 bin_str(int MP_value
[MP_SIZE
], char *str
, int maxbits
)
516 int i
, MP0
[MP_SIZE
], MP1
[MP_SIZE
], MP2
[MP_SIZE
], MP3
[MP_SIZE
];
519 MPstr_to_num("0", DEC
, MP0
);
520 MPstr_to_num("1", DEC
, MP1
);
521 MPstr_to_num("2", DEC
, MP2
);
523 if (mplt(MP_value
, MP0
)) {
524 mpcmim(MP_value
, MP0
);
525 mpadd(MP0
, MP1
, MP0
);
528 mpcmim(MP_value
, MP0
);
531 for (i
= 0; i
< maxbits
; i
++) {
532 double lsb
; /* Least significant bit. */
533 calc_and(MP3
, MP0
, MP1
);
537 str
[maxbits
- i
-1] = (neg
) ? '1' : '0';
539 str
[maxbits
- i
-1] = (neg
) ? '0' : '1';
542 mpdiv(MP0
, MP2
, MP3
);
550 /* Set new title for a window. */
553 set_title(enum fcp_type fcptype
, char *str
)
557 if (fcptype
== FCP_KEY
) {
559 } else if (fcptype
== FCP_REG
) {
562 gtk_window_set_title(GTK_WINDOW(f
), _(str
));
569 int bit_str_len
, i
, MP1
[MP_SIZE
], MP2
[MP_SIZE
];
571 char str
[64], label
[3];
572 int ret
= usable_num(MP
);
576 MPstr_to_num(v
->display
, v
->base
, MP1
);
578 if (mpeq(MP1
, MP2
)) {
579 char *bit_str
, label
[3], tmp
[MAXLINE
];
580 int toclear
= (v
->current
== KEY_CLEAR_ENTRY
)
583 bit_str
= make_fixed(MP1
, tmp
, BIN
, MAXLINE
, toclear
);
584 bit_str_len
= strlen(bit_str
);
585 if (bit_str_len
<= MAXBITS
) {
586 gtk_widget_set_sensitive(X
->bit_panel
, TRUE
);
589 for (i
= 0; i
< MAXBITS
; i
++) {
590 label
[1] = (i
< bit_str_len
) ? bit_str
[bit_str_len
-i
-1] : '0';
591 gtk_label_set_text(GTK_LABEL(X
->bits
[MAXBITS
- i
- 1]), label
);
597 gtk_widget_set_sensitive(X
->bit_panel
, FALSE
);
601 if (ret
|| !is_integer(MP
)) {
602 gtk_widget_set_sensitive(X
->bit_panel
, FALSE
);
605 bin_str(MP
, str
, 64);
606 gtk_widget_set_sensitive(X
->bit_panel
, TRUE
);
609 for (i
= 0; i
< 64; i
++) {
610 label
[1] = str
[64 - i
- 1];
611 gtk_label_set_text(GTK_LABEL(X
->bits
[64 - i
- 1]), label
);
625 if (GTK_WIDGET_VISIBLE(
626 GTK_SCROLLED_WINDOW(X
->scrolledwindow
)->hscrollbar
)) {
629 set
= gtk_scrolled_window_get_hadjustment(
630 GTK_SCROLLED_WINDOW(X
->scrolledwindow
));
631 gtk_adjustment_set_value(set
, set
->upper
);
632 gtk_scrolled_window_set_hadjustment(
633 GTK_SCROLLED_WINDOW(X
->scrolledwindow
), set
);
639 set_display(char *str
, int minimize_changes
)
641 char localized
[MAX_LOCALIZED
];
642 GtkTextIter start
, end
;
648 if (str
== NULL
|| *str
== 0) {
652 localize_number(localized
, str
);
656 gtk_text_buffer_get_bounds(X
->display_buffer
, &start
, &end
);
657 text
= gtk_text_buffer_get_text(X
->display_buffer
, &start
, &end
, TRUE
);
658 diff
= strcmp (text
, str
);
664 if (minimize_changes
) {
665 if (len1
< len2
&& strncmp(text
, str
, len1
) == 0) {
667 gtk_text_buffer_insert(X
->display_buffer
, &end
, str
+ len1
, -1);
669 } else if (len1
> len2
&& strncmp(text
, str
, len2
) == 0) {
671 gtk_text_buffer_get_iter_at_offset (X
->display_buffer
, &start
, len2
);
672 gtk_text_buffer_delete(X
->display_buffer
, &start
, &end
);
678 gtk_text_buffer_delete(X
->display_buffer
, &start
, &end
);
679 gtk_text_buffer_insert(X
->display_buffer
, &end
, str
, -1);
688 write_display(char *str
)
691 GtkTextIter start
, end
;
697 gtk_text_buffer_get_bounds(X
->display_buffer
, &start
, &end
);
698 text
= gtk_text_buffer_get_text(X
->display_buffer
, &start
, &end
, TRUE
);
700 gtk_text_buffer_delete(X
->display_buffer
, &start
, &end
);
702 gtk_text_buffer_insert(X
->display_buffer
, &end
, str
, -1);
708 /* When an error condition occurs:
710 * - make insensitive all buttons except Clr.
711 * - make all Scientific mode toggles and checkboxes insensitive.
712 * - make all menubar items insensitive except:
716 * When the error condition is cleared, resensitise everything, setting
717 * the numeric base buttons correctly.
721 set_error_state(int error
)
727 for (i
= 0; i
< NBUTTONS
; i
++) {
728 gtk_widget_set_sensitive(X
->buttons
[i
], !v
->error
);
730 /* Clr button always sensitive. */
731 gtk_widget_set_sensitive(X
->clear_buttons
[0], TRUE
);
732 gtk_widget_set_sensitive(X
->clear_buttons
[1], TRUE
);
735 grey_buttons(v
->base
);
738 gtk_widget_set_sensitive(X
->mode_panel
, !v
->error
);
740 // FIXME: Isn't this missing a whole lot of widgets?
741 SET_MENUBAR_ITEM_STATE("copy_menu", !v
->error
);
742 SET_MENUBAR_ITEM_STATE("paste_menu", !v
->error
);
743 SET_MENUBAR_ITEM_STATE("insert_ascii_menu", !v
->error
);
744 SET_MENUBAR_ITEM_STATE("view_basic_menu", !v
->error
);
745 SET_MENUBAR_ITEM_STATE("view_advanced_menu", !v
->error
);
746 SET_MENUBAR_ITEM_STATE("view_financial_menu", !v
->error
);
747 SET_MENUBAR_ITEM_STATE("view_scientific_menu", !v
->error
);
748 SET_MENUBAR_ITEM_STATE("show_trailing_zeroes_menu",
749 !v
->error
&& (v
->modetype
== SCIENTIFIC
));
750 SET_MENUBAR_ITEM_STATE("show_thousands_separator_menu", !v
->error
);
751 SET_MENUBAR_ITEM_STATE("show_registers_menu", !v
->error
);
752 SET_MENUBAR_ITEM_STATE("arithmetic_precedence_menu", !v
->error
);
753 SET_MENUBAR_ITEM_STATE("about_menu", !v
->error
);
758 set_hyp_item(int state
)
760 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(X
->hyp
), state
);
765 set_inv_item(int state
)
767 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(X
->inv
), state
);
772 set_memory_toggle(int state
)
774 GtkWidget
*radio
= GET_WIDGET("show_registers_menu");
776 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(radio
), state
);
781 set_mode(enum mode_type mode
)
788 gtk_widget_show(X
->bas_panel
);
789 gtk_widget_hide(X
->adv_panel
);
790 gtk_widget_hide(X
->fin_panel
);
791 gtk_widget_hide(X
->mode_panel
);
792 gtk_widget_hide(X
->bit_panel
);
793 gtk_widget_hide(X
->sci_panel
);
797 gtk_widget_hide(X
->bas_panel
);
798 gtk_widget_show(X
->adv_panel
);
799 gtk_widget_hide(X
->fin_panel
);
800 gtk_widget_hide(X
->mode_panel
);
801 gtk_widget_hide(X
->bit_panel
);
802 gtk_widget_hide(X
->sci_panel
);
806 gtk_widget_hide(X
->bas_panel
);
807 gtk_widget_show(X
->adv_panel
);
808 gtk_widget_show(X
->fin_panel
);
809 gtk_widget_hide(X
->mode_panel
);
810 gtk_widget_hide(X
->bit_panel
);
811 gtk_widget_hide(X
->sci_panel
);
815 gtk_widget_hide(X
->bas_panel
);
816 gtk_widget_show(X
->adv_panel
);
817 gtk_widget_hide(X
->fin_panel
);
818 gtk_widget_show_all(X
->mode_panel
);
819 if (v
->bitcalculating_mode
) {
820 gtk_widget_show_all(X
->bit_panel
);
822 gtk_widget_hide(X
->bit_panel
);
824 gtk_widget_show(X
->sci_panel
);
828 r
= g_new0(GtkRequisition
, 1);
829 gtk_widget_size_request(X
->menubar
, r
);
832 gtk_widget_size_request(X
->display_item
, r
);
833 w
= MAX(w
, r
->width
);
836 if (GTK_WIDGET_VISIBLE(X
->fin_panel
)) {
837 gtk_widget_size_request(X
->fin_panel
, r
);
838 w
= MAX(w
, r
->width
);
842 if (GTK_WIDGET_VISIBLE(X
->mode_panel
)) {
843 gtk_widget_size_request(X
->mode_panel
, r
);
844 w
= MAX(w
, r
->width
);
848 if (GTK_WIDGET_VISIBLE(X
->sci_panel
)) {
849 gtk_widget_size_request(X
->sci_panel
, r
);
850 w
= MAX(w
, r
->width
);
854 /* For initial display. */
855 gtk_window_set_default_size(GTK_WINDOW(X
->kframe
), w
, h
);
856 gtk_window_resize(GTK_WINDOW(X
->kframe
), w
, h
);
863 set_item(enum item_type itemtype
, int val
)
871 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(X
->base
[val
]), 1);
875 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(X
->disp
[val
]), 1);
879 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(X
->trig
[val
]), 1);
890 about_cb(GtkWidget
*widget
)
892 const gchar
*authors
[] = {
893 "Rich Burridge <rich.burridge@sun.com>",
894 "Sami Pietila <sampie@ariana-dsl.utu.fi>",
895 "Robert Ancell <robert.ancell@gmail.com>",
898 const gchar
*documenters
[] = {
902 const gchar
*translator_credits
= _("translator-credits");
904 const char *license
[] = {
905 N_("Gcalctool is free software; you can redistribute it and/or modify\n"
906 "it under the terms of the GNU General Public License as published by\n"
907 "the Free Software Foundation; either version 2 of the License, or\n"
908 "(at your option) any later version.\n"),
909 N_("Gcalctool is distributed in the hope that it will be useful,\n"
910 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
911 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
912 "GNU General Public License for more details.\n"),
913 N_("You should have received a copy of the GNU General Public License\n"
914 "along with Gcalctool; if not, write to the Free Software Foundation, Inc.,\n"
915 "51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA\n")
918 char *license_trans
= g_strconcat(_(license
[0]), "\n",
923 gtk_show_about_dialog(GTK_WINDOW(X
->kframe
),
924 "name",_("Gcalctool"),
926 "copyright", _("\xc2\xa9 1986-2007 The Gcalctool authors"),
927 "license", license_trans
,
928 "comments", _("Calculator with financial and scientific modes."),
930 "documenters", documenters
,
931 "translator_credits", translator_credits
,
932 "logo-icon-name", "gnome-calculator",
938 cell_edited(GtkCellRendererText
*cell
, const gchar
*path_string
,
939 const gchar
*new_text
, gpointer data
)
941 GtkTreeModel
*model
= (GtkTreeModel
*) data
;
942 GtkTreePath
*path
= gtk_tree_path_new_from_string(path_string
);
947 column
= g_object_get_data(G_OBJECT(cell
), "column");
949 gtk_tree_model_get_iter(model
, &iter
, path
);
951 switch (GPOINTER_TO_INT(column
)) {
953 gtk_tree_model_get(model
, &iter
, column
, &old_text
, -1);
955 gtk_list_store_set(GTK_LIST_STORE(model
), &iter
, column
,
956 g_strdup(new_text
), -1);
959 case COLUMN_DESCRIPTION
:
960 gtk_tree_model_get(model
, &iter
, column
, &old_text
, -1);
962 gtk_list_store_set(GTK_LIST_STORE(model
), &iter
, column
,
963 g_strdup(new_text
), -1);
967 gtk_tree_path_free(path
);
972 add_cf_column(GtkTreeView
*treeview
, gchar
*name
, gint colno
, gboolean editable
)
974 GtkCellRenderer
*renderer
;
975 GtkTreeModel
*model
= gtk_tree_view_get_model(treeview
);
977 renderer
= gtk_cell_renderer_text_new();
979 g_signal_connect(G_OBJECT(renderer
), "edited",
980 G_CALLBACK(cell_edited
), model
);
982 g_object_set_data(G_OBJECT(renderer
), "column", GINT_TO_POINTER(colno
));
985 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(treeview
),
988 "editable", COLUMN_EDITABLE
,
991 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(treeview
),
1001 aframe_cancel_cb(GtkButton
*button
, gpointer user_data
)
1003 gtk_widget_hide(X
->aframe
);
1009 aframe_key_cb(GtkWidget
*widget
, GdkEventKey
*event
, gpointer data
)
1011 g_return_val_if_fail(GTK_IS_WIDGET(widget
), FALSE
);
1013 if (event
->keyval
== GDK_Escape
) {
1014 gtk_widget_hide(X
->aframe
);
1023 aframe_ok_cb(GtkButton
*button
, gpointer user_data
)
1028 ch
= (char *) gtk_entry_get_text(GTK_ENTRY(X
->aframe_ch
));
1030 mpcim(&val
, v
->MPdisp_val
);
1031 show_display(v
->MPdisp_val
);
1032 gtk_widget_hide(X
->aframe
);
1038 base_cb(GtkWidget
*widget
)
1040 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget
)))
1041 do_base((enum base_type
) g_object_get_data(G_OBJECT(widget
),
1052 static void do_button(struct button
*n
, int arg
)
1054 struct exprm_state
*e
;
1056 switch (v
->syntax
) {
1058 process_item(n
, arg
);
1060 if (v
->new_input
&& v
->dtype
== FIX
) {
1061 STRNCPY(v
->fnum
, v
->display
, MAX_DIGITS
- 1);
1062 set_display(v
->fnum
, TRUE
);
1069 MEMCPY(&(e
->button
), n
, sizeof(struct button
));
1084 GError
*error
= NULL
;
1092 const char * const * langs
= g_get_language_names ();
1094 for (i
= 0; langs
[i
]; i
++) {
1096 if (strchr (lang
, '.')) {
1100 uri
= g_build_filename(PACKAGE_DATA_DIR
,
1101 "/gnome/help/gcalctool/",
1106 if (g_file_test (uri
, G_FILE_TEST_EXISTS
)) {
1111 command
= g_strconcat ("gnome-open ghelp://", uri
, NULL
);
1112 gscreen
= gdk_screen_get_default();
1113 gdk_spawn_command_line_on_screen (gscreen
, command
, &error
);
1117 d
= gtk_message_dialog_new(NULL
,
1118 GTK_DIALOG_MODAL
| GTK_DIALOG_DESTROY_WITH_PARENT
,
1119 GTK_MESSAGE_ERROR
, GTK_BUTTONS_OK
,
1121 gtk_dialog_run(GTK_DIALOG(d
));
1122 gtk_widget_destroy(d
);
1123 g_error_free(error
);
1133 put_constant(int n
, char *con_value
, char *con_name
)
1136 char *cstr
= g_strdup(con_value
);
1138 /* Constants are written out with no thousands seaparator and with a radix
1142 SNPRINTF(key
, MAXLINE
, "/apps/%s/constant%1dvalue", v
->appname
, n
);
1143 gconf_client_set_string(X
->client
, key
, cstr
, NULL
);
1146 SNPRINTF(key
, MAXLINE
, "/apps/%s/constant%1dname", v
->appname
, n
);
1147 gconf_client_set_string(X
->client
, key
, con_name
, NULL
);
1152 put_function(int n
, char *fun_value
, char *fun_name
)
1156 SNPRINTF(key
, MAXLINE
, "/apps/%s/function%1dvalue", v
->appname
, n
);
1157 gconf_client_set_string(X
->client
, key
, fun_value
, NULL
);
1159 SNPRINTF(key
, MAXLINE
, "/apps/%s/function%1dname", v
->appname
, n
);
1160 gconf_client_set_string(X
->client
, key
, fun_name
, NULL
);
1166 menu_proc_cb(GtkMenuItem
*mi
, gpointer user_data
)
1168 struct button
*n
= (struct button
*) g_object_get_data(G_OBJECT(mi
), "button");
1169 do_button(n
, GPOINTER_TO_INT(user_data
));
1173 /* Put gcalctool resource into deskset database. */
1176 put_resource(enum res_type rtype
, char *value
)
1178 char cstr
[MAXLINE
], key
[MAXLINE
];
1180 STRNCPY(key
, calc_res
[(int) rtype
], MAXLINE
- 1);
1181 SNPRINTF(cstr
, MAXLINE
, "/apps/%s/%s", v
->appname
, key
);
1182 gconf_client_set_string(X
->client
, cstr
, value
, NULL
);
1186 /* Create popup window for editing constants/functions. */
1189 update_popup_label(GtkWidget
*menu_item
, gchar
*text
)
1192 label
= (GtkWidget
*)gtk_container_get_children(GTK_CONTAINER(menu_item
))->data
;
1193 gtk_label_set_markup_with_mnemonic(GTK_LABEL(label
), text
);
1197 update_constants_menu(void)
1199 char mline
[MAXLINE
];
1202 for (i
= 0; i
< MAXCONFUN
; i
++) {
1203 SNPRINTF(mline
, MAXLINE
,
1204 "<span weight=\"bold\">%s_%1d:</span> %s [%s]", _("C"), i
,
1205 make_number(v
->MPcon_vals
[i
], DEC
, TRUE
),
1207 update_popup_label(X
->constant_menu_items
[i
], mline
);
1213 update_functions_menu(void)
1215 char mline
[MAXLINE
];
1218 for (i
= 0; i
< MAXCONFUN
; i
++) {
1219 if (strlen(v
->fun_vals
[i
]) != 0) {
1220 SNPRINTF(mline
, MAXLINE
,
1221 "<span weight=\"bold\">%s_%1d:</span> %s [%s]",
1222 _("F"), i
, v
->fun_vals
[i
], v
->fun_names
[i
]);
1223 gtk_widget_show(X
->function_menu_items
[i
]);
1224 update_popup_label(X
->function_menu_items
[i
], mline
);
1227 gtk_widget_hide(X
->function_menu_items
[i
]);
1233 edit_constants_response_cb(GtkDialog
*dialog
, gint id
)
1240 if (id
== GTK_RESPONSE_HELP
) {
1244 if (id
== GTK_RESPONSE_ACCEPT
) {
1245 if (gtk_tree_model_get_iter_first(X
->constants_model
, &iter
)) {
1247 gtk_tree_model_get(X
->constants_model
, &iter
,
1248 COLUMN_NUMBER
, &number
,
1249 COLUMN_VALUE
, &value
,
1250 COLUMN_DESCRIPTION
, &description
, -1);
1251 MPstr_to_num(value
, DEC
, v
->MPcon_vals
[number
]);
1252 STRNCPY(v
->con_names
[number
], description
, MAXLINE
- 1);
1253 put_constant(number
, value
, description
);
1254 } while (gtk_tree_model_iter_next(X
->constants_model
, &iter
));
1258 gtk_widget_hide(GTK_WIDGET(dialog
));
1263 edit_functions_response_cb(GtkDialog
*dialog
, gint id
)
1270 if (id
== GTK_RESPONSE_HELP
) {
1274 if (id
== GTK_RESPONSE_ACCEPT
) {
1275 if (gtk_tree_model_get_iter_first(X
->functions_model
, &iter
)) {
1277 gtk_tree_model_get(X
->functions_model
, &iter
,
1278 COLUMN_NUMBER
, &number
,
1279 COLUMN_VALUE
, &value
,
1280 COLUMN_DESCRIPTION
, &description
, -1);
1281 STRNCPY(v
->fun_vals
[number
], convert(value
), MAXLINE
- 1);
1282 STRNCPY(v
->fun_names
[number
], description
, MAXLINE
- 1);
1283 put_function(number
, value
, description
);
1284 } while (gtk_tree_model_iter_next(X
->functions_model
, &iter
));
1288 gtk_widget_hide(GTK_WIDGET(dialog
));
1293 static GtkTreeModel
*
1294 create_cf_model(enum menu_type mtype
, GtkWidget
*dialog
)
1297 GtkListStore
*model
;
1299 gchar
*value
, *description
;
1301 model
= gtk_list_store_new(NUM_COLUMNS
, G_TYPE_INT
, G_TYPE_STRING
,
1302 G_TYPE_STRING
, G_TYPE_BOOLEAN
);
1303 for (i
= 0; i
< MAXCONFUN
; i
++) {
1304 gtk_list_store_append(model
, &iter
);
1306 if (mtype
== M_CON
) {
1307 value
= g_strdup(make_number(v
->MPcon_vals
[i
], DEC
, TRUE
));
1308 description
= g_strdup(v
->con_names
[i
]);
1310 value
= g_strdup(v
->fun_vals
[i
]);
1311 description
= g_strdup(v
->fun_names
[i
]);
1313 gtk_list_store_set(model
, &iter
,
1315 COLUMN_VALUE
, value
,
1316 COLUMN_DESCRIPTION
, description
,
1317 COLUMN_EDITABLE
, TRUE
,
1321 return(GTK_TREE_MODEL(model
));
1326 update_mode_widgets(int mode
)
1332 widget
= GET_WIDGET("view_financial_menu");
1336 widget
= GET_WIDGET("view_scientific_menu");
1340 widget
= GET_WIDGET("view_advanced_menu");
1344 widget
= GET_WIDGET("view_advanced_menu");
1347 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget
), TRUE
);
1352 update_accuracy(int accuracy
)
1356 char *desc
, *current
, *tooltip
;
1358 SNPRINTF(text
, MAXLINE
, _("Other (%d) ..."), accuracy
);
1359 label
= gtk_bin_get_child(GTK_BIN(GET_WIDGET("acc_item_other")));
1360 gtk_label_set_text(GTK_LABEL(label
), text
);
1362 desc
= g_strdup_printf(ngettext("Set accuracy from 0 to %d numeric places.",
1363 "Set accuracy from 0 to %d numeric places.",
1367 /* Translator: This refers to the current accuracy setting */
1368 current
= g_strdup_printf(ngettext("Currently set to %d places.",
1369 "Currently set to %d places.",
1372 tooltip
= g_strdup_printf ("%s %s [A]", desc
, current
);
1373 gtk_widget_set_tooltip_text (GET_WIDGET("calc_accuracy_button"), tooltip
);
1381 set_accuracy_toggle(int val
)
1386 if (val
>= 0 && val
<= 9) {
1387 SNPRINTF(name
, MAXLINE
, "acc_item%d", val
);
1388 radio
= GET_WIDGET(name
);
1389 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(radio
), TRUE
);
1395 set_show_tsep_toggle(int state
)
1399 mi
= GET_WIDGET("show_thousands_separator_menu");
1400 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mi
), state
);
1405 set_show_bitcalculating_toggle(int state
)
1409 mi
= GET_WIDGET("show_bitcalculating_menu");
1410 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mi
), state
);
1415 set_show_zeroes_toggle(int state
)
1419 v
->doing_mi
= 1; /* Hack to get mstz_proc() to just return. */
1420 menu
= GET_WIDGET("show_trailing_zeroes_menu");
1421 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu
), state
);
1422 menu
= GET_WIDGET("acc_trailing_zeroes_item");
1423 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu
), state
);
1429 reset_mode_display(int toclear
)
1433 /* If the new mode is BASIC, then we need to dismiss the memory register
1434 * window (if it's being displayed), as there is no way to interact with it.
1437 radio
= GET_WIDGET("show_trailing_zeroes_menu");
1438 gtk_widget_set_sensitive(radio
, v
->modetype
== SCIENTIFIC
);
1439 radio
= GET_WIDGET("show_registers_menu");
1440 gtk_widget_set_sensitive(radio
, v
->modetype
!= BASIC
);
1442 if (v
->modetype
== BASIC
) {
1443 gtk_dialog_response(GTK_DIALOG(X
->rframe
), GTK_RESPONSE_CLOSE
);
1446 switch (v
->syntax
) {
1448 show_display(v
->MPdisp_val
);
1464 char intval
[MAXLINE
];
1467 (void) gdk_window_get_origin(X
->kframe
->window
, &x
, &y
);
1468 SNPRINTF(intval
, MAXLINE
, "%d", x
);
1469 put_resource(R_XPOS
, intval
);
1470 SNPRINTF(intval
, MAXLINE
, "%d", y
);
1471 put_resource(R_YPOS
, intval
);
1476 change_mode(int mode
)
1480 set_item(BASEITEM
, DEC
);
1481 grey_buttons(v
->base
);
1482 set_item(NUMITEM
, FIX
);
1484 set_accuracy_toggle(v
->accuracy
);
1486 v
->show_tsep
= FALSE
;
1487 set_show_tsep_toggle(v
->show_tsep
);
1488 put_resource(R_TSEP
, set_bool(v
->show_tsep
== TRUE
));
1490 v
->show_zeroes
= FALSE
;
1491 set_show_zeroes_toggle(v
->show_zeroes
);
1492 put_resource(R_ZEROES
, set_bool(v
->show_zeroes
== TRUE
));
1494 reset_mode_display(TRUE
);
1500 cm_response_cb(GtkDialog
*dialog
, int response
)
1502 if (response
== GTK_RESPONSE_ACCEPT
) {
1503 change_mode(X
->mode
);
1505 update_mode_widgets(v
->modetype
);
1508 gtk_widget_destroy(X
->cm_dialog
);
1509 X
->cm_dialog
= NULL
;
1515 cm_warning_cb(GtkWidget
*button
)
1517 v
->warn_change_mode
= !gtk_toggle_button_get_active(
1518 GTK_TOGGLE_BUTTON(button
));
1523 create_change_mode_dialog()
1525 GtkWidget
*check
, *button
;
1527 X
->cm_dialog
= gtk_message_dialog_new(GTK_WINDOW(X
->kframe
),
1528 GTK_DIALOG_MODAL
|GTK_DIALOG_DESTROY_WITH_PARENT
,
1529 GTK_MESSAGE_WARNING
,
1532 _("Changing Modes Clears Calculation"));
1533 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(X
->cm_dialog
),
1535 _("When you change modes, the current calculation "
1536 "will be cleared, and the base will be reset to "
1539 check
= gtk_check_button_new_with_mnemonic(_("_Do not warn me again"));
1540 gtk_box_pack_end(GTK_BOX(GTK_MESSAGE_DIALOG(X
->cm_dialog
)->label
->parent
),
1541 check
, FALSE
, FALSE
, 0);
1542 gtk_widget_show(check
);
1544 button
= gtk_dialog_add_button(GTK_DIALOG(X
->cm_dialog
),
1545 _("C_hange Mode"), GTK_RESPONSE_ACCEPT
);
1546 gtk_button_set_image(GTK_BUTTON(button
),
1547 gtk_image_new_from_stock(GTK_STOCK_REFRESH
,
1548 GTK_ICON_SIZE_BUTTON
));
1549 /* Set default focus on affirmative button */
1550 gtk_widget_grab_focus(button
);
1552 gtk_dialog_set_alternative_button_order(GTK_DIALOG(X
->cm_dialog
),
1553 GTK_RESPONSE_ACCEPT
,
1554 GTK_RESPONSE_CANCEL
,
1557 g_signal_connect((gpointer
) check
, "toggled",
1558 G_CALLBACK(cm_warning_cb
), NULL
);
1559 g_signal_connect(X
->cm_dialog
, "response",
1560 G_CALLBACK(cm_response_cb
), NULL
);
1562 gtk_window_set_position(GTK_WINDOW(X
->cm_dialog
),
1563 GTK_WIN_POS_CENTER_ON_PARENT
);
1568 show_change_mode_dialog()
1570 if (X
->cm_dialog
== NULL
) {
1571 create_change_mode_dialog();
1574 gtk_window_present(GTK_WINDOW(X
->cm_dialog
));
1580 bit_toggled(GtkWidget
*event_box
, GdkEventButton
*event
)
1583 unsigned long long lval
;
1584 int n
, MP1
[MP_SIZE
], index
;
1586 index
= GPOINTER_TO_INT(g_object_get_data(G_OBJECT(event_box
),
1588 n
= MAXBITS
- index
- 1;
1589 MPstr_to_num(v
->display
, v
->base
, MP1
);
1590 mpcmd(MP1
, &number
);
1591 lval
= (long long) number
;
1593 if (lval
& (1LL << n
)) {
1594 lval
&= ~(1LL << n
);
1595 gtk_label_set_text(GTK_LABEL(X
->bits
[index
]), " 0");
1598 gtk_label_set_text(GTK_LABEL(X
->bits
[index
]), " 1");
1601 number
= (double) lval
;
1602 mpcdm(&number
, v
->MPdisp_val
);
1603 show_display(v
->MPdisp_val
);
1611 set_redo_and_undo_button_sensitivity(int undo
, int redo
)
1613 gtk_widget_set_sensitive(X
->undo
, undo
);
1614 gtk_widget_set_sensitive(X
->redo
, redo
);
1619 menu_item_select_cb(GtkWidget
*widget
)
1621 GtkStatusbar
*statusbar
= GTK_STATUSBAR(X
->statusbar
);
1625 context_id
= gtk_statusbar_get_context_id(statusbar
, "menuhelp");
1627 tooltip
= (gchar
*)g_object_get_data(G_OBJECT(widget
), "tooltip");
1629 gtk_statusbar_push(statusbar
, context_id
, tooltip
);
1636 menu_item_deselect_cb(GtkWidget
*widget
)
1638 GtkStatusbar
*statusbar
= GTK_STATUSBAR(X
->statusbar
);
1641 context_id
= gtk_statusbar_get_context_id(statusbar
, "menuhelp");
1642 gtk_statusbar_pop(statusbar
, context_id
);
1647 update_copy_paste_status()
1652 can_copy
= gtk_text_buffer_get_has_selection(X
->display_buffer
);
1653 can_paste
= gtk_clipboard_wait_is_text_available(
1654 gtk_clipboard_get(X
->clipboard_atom
));
1656 gtk_widget_set_sensitive(GTK_WIDGET(X
->copy
), can_copy
);
1657 gtk_widget_set_sensitive(GTK_WIDGET(X
->paste
), can_paste
);
1662 set_menubar_tooltip(gchar
*menu_name
)
1667 menu
= GET_WIDGET(menu_name
);
1668 tooltip
= gtk_widget_get_tooltip_text(menu
);
1669 g_object_set_data(G_OBJECT(menu
), "tooltip", tooltip
);
1670 gtk_widget_set_tooltip_text(menu
, NULL
);
1675 update_memory_menus()
1680 for (i
= 0; i
< MAXREGS
; i
++) {
1681 SNPRINTF(mstr
, MAXLINE
, "<span weight=\"bold\">%s_%d:</span> %s",
1682 /* translators: R is the short form of register used inter alia
1684 _("R"), i
, make_number(v
->MPmvals
[i
], v
->base
, TRUE
));
1685 update_popup_label(X
->memory_store_items
[i
], mstr
);
1686 update_popup_label(X
->memory_recall_items
[i
], mstr
);
1687 update_popup_label(X
->memory_exchange_items
[i
], mstr
);
1694 mem_response(GtkDialog
*dialog
, int response
)
1696 set_memory_toggle(FALSE
);
1697 put_resource(R_REGS
, "false");
1698 gtk_widget_hide(X
->rframe
);
1704 dismiss_aframe(GtkWidget
*widget
, GdkEvent
*event
, gpointer user_data
)
1706 gtk_widget_hide(widget
);
1714 dismiss_rframe(GtkWidget
*widget
, GdkEvent
*event
, gpointer user_data
)
1716 gtk_dialog_response(GTK_DIALOG(widget
), GTK_RESPONSE_DELETE_EVENT
);
1724 dismiss_spframe(GtkWidget
*widget
, GdkEvent
*event
, gpointer user_data
)
1726 gtk_widget_hide(X
->spframe
);
1734 disp_cb(GtkWidget
*widget
)
1736 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget
)))
1737 do_numtype((enum num_type
) g_object_get_data(G_OBJECT(widget
), "response_id"));
1744 char nkey
[MAXLINE
], *nline
;
1745 char vkey
[MAXLINE
], *vline
;
1747 SNPRINTF(nkey
, MAXLINE
, "/apps/%s/constant%1dname", v
->appname
, n
);
1748 if ((nline
= gconf_client_get_string(X
->client
, nkey
, NULL
)) == NULL
) {
1752 SNPRINTF(vkey
, MAXLINE
, "/apps/%s/constant%1dvalue", v
->appname
, n
);
1753 if ((vline
= gconf_client_get_string(X
->client
, vkey
, NULL
)) == NULL
) {
1757 MPstr_to_num(vline
, DEC
, v
->MPcon_vals
[n
]);
1758 STRNCPY(v
->con_names
[n
], nline
, MAXLINE
- 1);
1763 get_display() /* The Copy function key has been pressed. */
1765 gchar
*string
= NULL
;
1766 GtkTextIter start
, end
;
1768 if (gtk_text_buffer_get_selection_bounds(X
->display_buffer
, &start
, &end
) == TRUE
) {
1769 string
= gtk_text_buffer_get_text(X
->display_buffer
, &start
, &end
, FALSE
);
1771 gtk_text_buffer_get_bounds(X
->display_buffer
, &start
, &end
);
1772 string
= gtk_text_buffer_get_text(X
->display_buffer
, &start
, &end
, FALSE
);
1775 if (v
->shelf
!= NULL
) {
1778 v
->shelf
= g_locale_from_utf8(string
, strlen(string
), NULL
, NULL
, NULL
);
1781 gtk_clipboard_set_text(gtk_clipboard_get(X
->clipboard_atom
), v
->shelf
, -1);
1788 char nkey
[MAXLINE
], *nline
;
1789 char vkey
[MAXLINE
], *vline
;
1791 SNPRINTF(nkey
, MAXLINE
, "/apps/%s/function%1dname", v
->appname
, n
);
1792 if ((nline
= gconf_client_get_string(X
->client
, nkey
, NULL
)) == NULL
) {
1796 SNPRINTF(vkey
, MAXLINE
, "/apps/%s/function%1dvalue", v
->appname
, n
);
1797 if ((vline
= gconf_client_get_string(X
->client
, vkey
, NULL
)) == NULL
) {
1801 STRNCPY(v
->fun_vals
[n
], convert(vline
), MAXLINE
- 1);
1802 STRNCPY(v
->fun_names
[n
], nline
, MAXLINE
- 1);
1807 get_localized_numeric_point(void)
1809 const char *decimal_point
;
1811 decimal_point
= localeconv()->decimal_point
;
1813 return(g_locale_to_utf8(decimal_point
, -1, NULL
, NULL
, NULL
));
1818 get_menu_entry(enum menu_type mtype
, int offset
)
1822 return(offset
+ '0');
1826 return((offset
< 10) ? offset
+ '0' : offset
+ 'A' - 10);
1829 FPRINTF(stderr
, "need to handle menu type %d\n", mtype
);
1838 get_proc(GtkClipboard
*clipboard
, const gchar
*buffer
, gpointer data
)
1840 gchar
*dstp
, *end_buffer
, *srcp
, *text
;
1842 if (buffer
== NULL
) {
1846 end_buffer
= (gchar
*) (buffer
+ strlen(buffer
));
1847 text
= malloc(strlen(buffer
)+1);
1849 srcp
= (gchar
*) buffer
;
1851 while (srcp
< end_buffer
) {
1853 /* If the clipboard buffer contains any occurances of the "thousands
1854 * separator", remove them.
1856 if (*srcp
== v
->tsep
[0]) {
1857 if (strstr(srcp
, v
->tsep
) == srcp
) {
1858 srcp
+= strlen(v
->tsep
);
1864 /* If an "A", "B", "C", "D" or "F" character is encountered, it
1865 * will be converted to its lowercase equivalent. If an "E" is
1866 * found, and the next character is a "-" or a "+", then it
1867 * remains as an upper case "E" (it's assumed to be a possible
1868 * exponential number), otherwise its converted to a lower case
1869 * "e". See bugs #455889 and #469245 for more details.
1876 case 'F': *dstp
++ = tolower(*srcp
);
1880 case 'E': if (srcp
< (end_buffer
-1)) {
1881 if (*(srcp
+1) != '-' &&
1883 *dstp
++ = tolower(*srcp
);
1890 default: *dstp
++ = *srcp
++;
1896 switch (v
->syntax
) {
1898 int ret
= lr_parse((char *) text
, v
->MPdisp_val
);
1901 show_display(v
->MPdisp_val
);
1903 update_statusbar(_("Clipboard contained malformed calculation"),
1904 "gtk-dialog-error");
1910 exp_append((char *) text
);
1921 /* Get gcalctool resource from merged database. */
1924 get_resource(enum res_type rtype
)
1926 char cstr
[MAXLINE
], key
[MAXLINE
];
1928 STRNCPY(key
, calc_res
[(int) rtype
], MAXLINE
- 1);
1929 SNPRINTF(cstr
, MAXLINE
, "/apps/%s/%s", v
->appname
, key
);
1931 return(gconf_client_get_string(X
->client
, cstr
, NULL
));
1936 grey_buttons(enum base_type base
)
1938 int i
, baseval
= basevals
[(int) base
];
1940 for (i
= 0; i
< 16; i
++) {
1941 gtk_widget_set_sensitive(X
->digit_buttons
[i
], i
< baseval
);
1947 handle_selection() /* Handle the GET function key being pressed. */
1949 gtk_clipboard_request_text(gtk_clipboard_get(X
->clipboard_atom
),
1956 popup_paste_cb(GtkMenuItem
*menuitem
)
1964 for_each_menu(GtkWidget
*widget
, gpointer data
)
1966 /* Find the "Paste" entry and activate it (see bug #317786). */
1967 if (strcmp(G_OBJECT_TYPE_NAME(widget
), "GtkImageMenuItem") == 0) {
1968 GtkWidget
*label
= gtk_bin_get_child(GTK_BIN(widget
));
1970 if (strcmp(gtk_label_get_text(GTK_LABEL(label
)), _("Paste")) == 0) {
1971 if (gtk_clipboard_wait_is_text_available(
1972 gtk_clipboard_get(X
->clipboard_atom
))) {
1973 gtk_widget_set_sensitive(GTK_WIDGET(widget
), TRUE
);
1974 g_signal_connect(GTK_OBJECT(widget
), "activate",
1975 G_CALLBACK(popup_paste_cb
), NULL
);
1984 buffer_populate_popup_cb(GtkTextView
*textview
, GtkMenu
*menu
)
1986 gtk_container_foreach(GTK_CONTAINER(menu
), for_each_menu
, NULL
);
1992 help_cb(GtkWidget
*widget
)
2001 hyp_cb(GtkWidget
*widget
)
2003 v
->hyperbolic
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget
));
2009 inv_cb(GtkWidget
*button
)
2011 v
->inverse
= !v
->inverse
;
2016 check_for_localized_numeric_point(int keyval
)
2018 gchar outbuf
[10]; /* Minumum size 6. */
2021 ch
= gdk_keyval_to_unicode(keyval
);
2022 g_return_val_if_fail(g_unichar_validate(ch
), FALSE
);
2024 outbuf
[g_unichar_to_utf8(ch
, outbuf
)] = '\0';
2026 return(strcmp(outbuf
, X
->lnp
) == 0);
2031 get_expr_from_display()
2034 GtkTextIter start
, end
;
2036 gtk_text_buffer_get_bounds(X
->display_buffer
, &start
, &end
);
2038 text
= gtk_text_buffer_get_text(X
->display_buffer
,
2047 delete_from_cursor()
2049 GtkTextIter start
, end
, loc
;
2052 gtk_text_buffer_get_bounds(X
->display_buffer
, &start
, &end
);
2053 g_object_get(G_OBJECT(X
->display_buffer
), "cursor-position", &pos
, NULL
);
2055 gtk_text_buffer_get_iter_at_offset(X
->display_buffer
,
2059 gtk_text_buffer_backspace(X
->display_buffer
, &loc
, TRUE
, TRUE
);
2065 insert_to_cursor(char *text
)
2067 gtk_text_buffer_insert_at_cursor(X
->display_buffer
,
2075 display_focus_out_cb(GtkWidget
*widget
, GdkEventKey
*event
)
2077 if (v
->syntax
== exprs
) {
2078 get_expr_from_display();
2087 display_focus_in_cb(GtkWidget
*widget
, GdkEventKey
*event
)
2097 menu_pos_func(GtkMenu
*menu
, gint
*x
, gint
*y
,
2098 gboolean
*push_in
, gpointer user_data
)
2100 GdkPoint
*loc
= (GdkPoint
*) user_data
;
2109 button_cb(GtkWidget
*widget
, GdkEventButton
*event
)
2112 enum menu_type mtype
;
2116 n
= (struct button
*) g_object_get_data(G_OBJECT(widget
), "button");
2117 mtype
= GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget
), "mtype"));
2119 if (mtype
== M_NONE
) {
2122 /* If gcalctool is being driven by gok, the on-screen keyboard
2123 * assistive technology, it's possible that the event returned by
2124 * gtk_get_current_event() is NULL. If this is the case, we need
2125 * to fudge the popping up on the menu associated with this menu
2129 update_constants_menu();
2130 update_functions_menu();
2131 update_memory_menus();
2133 menu
= X
->menus
[mtype
];
2134 if (event
== NULL
) {
2135 gdk_window_get_origin(widget
->window
, &loc
.x
, &loc
.y
);
2136 loc
.x
+= widget
->allocation
.x
;
2137 loc
.y
+= widget
->allocation
.y
;
2138 gtk_menu_popup(GTK_MENU(menu
), NULL
, NULL
, menu_pos_func
,
2139 (gpointer
) &loc
, 0, gtk_get_current_event_time());
2140 } else if (event
->button
== 1) {
2141 gtk_menu_popup(GTK_MENU(menu
), NULL
, NULL
, NULL
, NULL
,
2142 event
->button
, event
->time
);
2150 select_display_entry(int offset
)
2154 gtk_text_buffer_get_iter_at_offset(X
->display_buffer
, &iter
, offset
);
2155 gtk_text_buffer_place_cursor(X
->display_buffer
, &iter
);
2156 gtk_widget_grab_focus(X
->display_item
);
2162 kframe_key_press_cb(GtkWidget
*widget
, GdkEventKey
*event
)
2167 if (check_for_localized_numeric_point(event
->keyval
) == TRUE
) {
2169 event
->keyval
= GDK_KP_Decimal
;
2172 state
= event
->state
& (GDK_CONTROL_MASK
| GDK_MOD1_MASK
);
2174 /* Accuracy shortcuts */
2175 if (state
== GDK_CONTROL_MASK
&& v
->modetype
== SCIENTIFIC
)
2177 switch (event
->keyval
) {
2211 /* Connect home and end keys to move into the display entry */
2212 if (event
->keyval
== GDK_Home
)
2214 select_display_entry(0);
2216 } else if (event
->keyval
== GDK_End
)
2218 select_display_entry(-1);
2222 for (i
= 0; i
< NBUTTONS
; i
++) {
2223 button
= X
->buttons
[i
];
2225 /* Check any parent widgets are visible */
2226 if (!GTK_WIDGET_VISIBLE(gtk_widget_get_parent(button
)) ||
2227 !GTK_WIDGET_VISIBLE(button
) || !GTK_WIDGET_IS_SENSITIVE(button
)) {
2232 while (button_widgets
[i
].accelerator_keys
[j
] != 0) {
2233 if (button_widgets
[i
].accelerator_keys
[j
] == event
->keyval
&&
2234 (button_widgets
[i
].accelerator_mods
[j
] & ~GDK_SHIFT_MASK
) == state
) {
2235 button_cb(button
, NULL
);
2247 load_resources() /* Load gconf configuration database for gcalctool. */
2251 SNPRINTF(str
, MAXLINE
, "/apps/%s", v
->appname
);
2252 X
->client
= gconf_client_get_default();
2253 gconf_client_add_dir(X
->client
, str
, GCONF_CLIENT_PRELOAD_NONE
, NULL
);
2258 make_hostname(Display
*dpy
)
2260 char client_hostname
[MAXHOSTNAMELEN
+ 4];
2261 char hostname
[MAXHOSTNAMELEN
];
2262 char *display
= DisplayString(dpy
);
2263 char *scanner
= display
;
2265 GETHOSTNAME(hostname
, MAXHOSTNAMELEN
);
2271 while (*scanner
!= ':') {
2277 if (strcmp(display
, hostname
) &&
2278 strcmp(display
, "localhost") &&
2279 strcmp(display
, "unix") &&
2280 strcmp(display
, "")) {
2281 SPRINTF(client_hostname
, " [%s] ", hostname
);
2283 STRCPY(client_hostname
, "");
2288 return(strdup(client_hostname
));
2294 mouse_button_cb(GtkWidget
*widget
, GdkEventButton
*event
)
2296 if (event
->button
== 2) {
2297 gtk_clipboard_request_text(gtk_clipboard_get(X
->primary_atom
),
2308 int intval
, screen_height
, screen_width
;
2311 screen_width
= gdk_screen_get_width(gdk_screen_get_default());
2312 screen_height
= gdk_screen_get_height(gdk_screen_get_default());
2314 if (get_int_resource(R_XPOS
, &intval
)) {
2316 if (x
< 0 || x
> screen_width
) {
2321 if (get_int_resource(R_YPOS
, &intval
)) {
2323 if (y
< 0 || y
> screen_height
) {
2328 gtk_window_move(GTK_WINDOW(X
->kframe
), x
, y
);
2332 show_ascii_frame() /* Display ASCII popup. */
2334 if (!GTK_WIDGET_VISIBLE(X
->aframe
)) {
2335 ds_position_popup(X
->kframe
, X
->aframe
, DS_POPUP_LEFT
);
2337 gtk_window_set_focus(GTK_WINDOW(X
->kframe
), GTK_WIDGET(X
->aframe_ch
));
2338 gtk_widget_show(X
->aframe
);
2343 show_precision_frame() /* Display Set Precision popup. */
2345 if (!GTK_WIDGET_VISIBLE(X
->spframe
)) {
2346 ds_position_popup(X
->kframe
, X
->spframe
, DS_POPUP_LEFT
);
2348 gtk_window_set_focus(GTK_WINDOW(X
->spframe
), GTK_WIDGET(X
->spframe_val
));
2349 gtk_widget_show(X
->spframe
);
2354 make_reg(int n
, char *str
)
2356 gtk_entry_set_width_chars(GTK_ENTRY(X
->regs
[n
]), strlen(str
));
2357 gtk_entry_set_text(GTK_ENTRY(X
->regs
[n
]), str
);
2360 /* Handle menu bar menu selection. */
2364 edit_cb(GtkWidget
*widget
)
2367 update_copy_paste_status();
2374 copy_cb(GtkWidget
*widget
)
2384 paste_cb(GtkWidget
*widget
)
2394 undo_cb(GtkWidget
*widget
)
2405 redo_cb(GtkWidget
*widget
)
2416 insert_ascii_cb(GtkWidget
*widget
)
2425 shift_left_cb(GtkWidget
*widget
)
2427 int count
= GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget
),
2431 do_button(&buttons
[KEY_LEFT_SHIFT
], count
);
2437 shift_right_cb(GtkWidget
*widget
)
2439 int count
= GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget
),
2443 do_button(&buttons
[KEY_RIGHT_SHIFT
], count
);
2449 show_bitcalculating_cb(GtkWidget
*widget
)
2452 v
->bitcalculating_mode
= v
->bitcalculating_mode
^ 1;
2453 set_mode(v
->modetype
);
2454 put_resource(R_BITCALC
, Rcstr
[v
->bitcalculating_mode
]);
2461 show_registers_cb(GtkWidget
*widget
)
2464 v
->rstate
= !v
->rstate
;
2472 arithmetic_mode_cb(GtkWidget
*widget
)
2478 /* TODO: Always do clear things when mode is changed. */
2480 v
->syntax
= v
->syntax
^ 1;
2481 switch (v
->syntax
) {
2484 MPstr_to_num("0", DEC
, v
->MPdisp_val
);
2485 show_display(v
->MPdisp_val
);
2486 update_statusbar(_("Activated no operator precedence mode"), "");
2487 clear_undo_history();
2491 struct exprm_state
*e
= get_state();
2493 MPstr_to_num("0", DEC
, e
->ans
);
2495 show_display(e
->ans
);
2497 _("Activated expression mode with operator precedence"), "");
2504 put_resource(R_SYNTAX
, Rsstr
[v
->syntax
]);
2505 set_mode(v
->modetype
);
2506 gtk_text_view_set_editable(GTK_TEXT_VIEW(X
->display_item
),
2507 (v
->syntax
== exprs
));
2513 mode_radio_cb(GtkWidget
*radio
)
2515 int immediate
= 0; /* Set if we can change mode without warning user. */
2516 int complete
= 0; /* Set if the user has completed a calculation. */
2518 if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(radio
))) {
2526 X
->mode
= GPOINTER_TO_INT(g_object_get_data(G_OBJECT(radio
), "calcmode"));
2528 /* If the user has completed a calculation and we are going to a
2529 * new mode that is "compatible" with this one, then just change
2530 * modes. Otherwise display a dialog warning the user that the
2531 * current calculation will be cleared.
2533 * Incompatible modes are:
2535 * Scientific -> Basic
2536 * Scientific -> Advanced
2537 * Scientific -> Financial
2539 * (unless we are in Scientific mode with Decimal numeric base and Fixed).
2542 switch (v
->syntax
) {
2544 if (v
->old_cal_value
< 0 ||
2545 v
->old_cal_value
== KEY_CALCULATE
) {
2546 complete
= 1; /* Calculation is complete. */
2551 struct exprm_state
*e
= get_state();
2552 if (!e
->expression
|| !strcmp(e
->expression
, "Ans")) {
2553 complete
= 1; /* Calculation is complete. */
2559 if ((v
->modetype
!= SCIENTIFIC
) ||
2560 (v
->dtype
== FIX
&& v
->base
== DEC
)) {
2566 v
->modetype
= X
->mode
;
2567 reset_mode_display(FALSE
);
2570 if (v
->warn_change_mode
) {
2571 show_change_mode_dialog();
2573 change_mode(X
->mode
);
2581 accuracy_radio_cb(GtkWidget
*widget
)
2585 count
= GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget
), "accuracy"));
2588 gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget
))) {
2596 accuracy_other_cb(GtkWidget
*widget
)
2599 show_precision_frame();
2606 show_trailing_zeroes_cb(GtkWidget
*widget
)
2609 v
->show_zeroes
= gtk_check_menu_item_get_active(
2610 GTK_CHECK_MENU_ITEM(widget
));
2612 syntaxdep_show_display();
2613 put_resource(R_ZEROES
, set_bool(v
->show_zeroes
== TRUE
));
2616 set_show_zeroes_toggle(v
->show_zeroes
);
2623 quit_cb(GtkWidget
*widget
)
2625 save_win_position();
2632 spframe_cancel_cb(GtkButton
*button
)
2634 gtk_widget_hide(X
->spframe
);
2640 spframe_key_cb(GtkWidget
*widget
, GdkEventKey
*event
)
2642 if (event
->keyval
== GDK_minus
) {
2643 update_statusbar(_("Accuracy value out of range"),
2644 "gtk-dialog-error");
2646 } else if (event
->keyval
== GDK_Escape
) {
2647 gtk_widget_hide(X
->spframe
);
2656 spframe_ok_cb(GtkButton
*button
)
2658 char intval
[MAXLINE
];
2659 int val
= gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(X
->spframe_val
));
2663 SNPRINTF(intval
, MAXLINE
, "%d", v
->accuracy
);
2664 put_resource(R_ACCURACY
, intval
);
2666 update_accuracy(v
->accuracy
);
2667 set_accuracy_toggle(v
->accuracy
);
2672 gtk_widget_hide(X
->spframe
);
2678 trig_cb(GtkWidget
*widget
)
2680 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget
)))
2681 do_trigtype((enum trig_type
) g_object_get_data(G_OBJECT(widget
),
2690 set_item(BASEITEM
, v
->base
);
2691 set_item(TTYPEITEM
, v
->ttype
);
2692 set_item(NUMITEM
, v
->dtype
);
2694 gtk_widget_show(X
->kframe
);
2696 switch (v
->syntax
) {
2701 /* Init expression mode.
2702 * This must be executed after do_base is called at init.
2703 * FIXME: The init code here is duplicated elsewhere.
2705 struct exprm_state
*e
= get_state();
2707 MPstr_to_num("0", DEC
, e
->ans
);
2709 show_display(e
->ans
);
2723 show_thousands_separator_cb(GtkWidget
*widget
)
2729 v
->show_tsep
= !v
->show_tsep
;
2731 syntaxdep_show_display();
2732 put_resource(R_TSEP
, set_bool(v
->show_tsep
== TRUE
));
2738 win_display(enum fcp_type fcptype
, int state
)
2740 GtkWidget
*f
= NULL
;
2742 if (fcptype
== FCP_REG
) {
2747 gtk_widget_realize(f
);
2748 if (state
&& gdk_window_is_visible(f
->window
)) {
2749 gdk_window_raise(f
->window
);
2753 if (fcptype
== FCP_REG
) {
2754 ds_position_popup(X
->kframe
, f
, DS_POPUP_ABOVE
);
2767 edit_constants_cb(GtkMenuItem
*item
)
2769 gtk_widget_show(X
->con_dialog
);
2775 edit_functions_cb(GtkMenuItem
*item
)
2777 gtk_widget_show(X
->fun_dialog
);
2785 char *hn
, name
[MAXLINE
];
2787 PangoFontDescription
*font_desc
;
2788 GtkSizeGroup
*size_group
;
2789 GtkAccelGroup
*accel_group
;
2790 GdkGeometry geometry
;
2791 GtkWidget
*treeview
;
2793 v
->tool_label
= NULL
;
2794 if (v
->titleline
== NULL
) {
2795 hn
= make_hostname(GDK_DISPLAY());
2796 v
->tool_label
= malloc(MAXLINE
);
2798 SNPRINTF(v
->tool_label
, MAXLINE
, "%s %s", _("Calculator"), hn
);
2801 read_str(&v
->tool_label
, v
->titleline
);
2805 X
->ui
= glade_xml_new(UI_FILE
, NULL
, NULL
);
2806 if (X
->ui
== NULL
) {
2809 dialog
= gtk_message_dialog_new(NULL
, 0,
2812 N_("Error loading user interface"));
2813 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog
),
2814 N_("The user interace file %s is missing or unable to be loaded. Please check your installation."), UI_FILE
);
2815 gtk_dialog_add_buttons(GTK_DIALOG(dialog
), GTK_STOCK_QUIT
, GTK_RESPONSE_ACCEPT
, NULL
);
2817 gtk_dialog_run(GTK_DIALOG(dialog
));
2821 X
->kframe
= GET_WIDGET("calc_window");
2823 X
->aframe
= GET_WIDGET("ascii_window");
2824 gtk_window_set_transient_for(GTK_WINDOW(X
->aframe
), GTK_WINDOW(X
->kframe
));
2825 X
->aframe_ch
= GET_WIDGET("ascii_entry");
2827 X
->spframe
= GET_WIDGET("precision_dialog");
2828 X
->spframe_val
= GET_WIDGET("spframe_spin");
2829 gtk_window_set_transient_for(GTK_WINDOW(X
->spframe
), GTK_WINDOW(X
->kframe
));
2830 gtk_spin_button_set_value(GTK_SPIN_BUTTON(X
->spframe_val
),
2831 (double) v
->accuracy
);
2832 gtk_entry_set_max_length(GTK_ENTRY(X
->spframe_val
), 2);
2834 X
->rframe
= GET_WIDGET("register_dialog");
2835 g_object_set_data(G_OBJECT(X
->rframe
), "rframe", X
->rframe
);
2836 gtk_window_set_transient_for(GTK_WINDOW(X
->rframe
), GTK_WINDOW(X
->kframe
));
2838 for (i
= 0; i
< MAXREGS
; i
++) {
2839 SNPRINTF(name
, MAXLINE
, "register_entry_%d", i
);
2840 X
->regs
[i
] = GET_WIDGET(name
);
2841 gtk_entry_set_text(GTK_ENTRY(X
->regs
[i
]),
2842 make_number(v
->MPmvals
[i
], v
->base
, TRUE
));
2845 X
->con_dialog
= GET_WIDGET("edit_constants_dialog");
2846 treeview
= GET_WIDGET("edit_constants_treeview");
2847 gtk_dialog_set_default_response(GTK_DIALOG(X
->con_dialog
),
2848 GTK_RESPONSE_ACCEPT
);
2849 gtk_window_set_transient_for(GTK_WINDOW(X
->con_dialog
),
2850 GTK_WINDOW(X
->kframe
));
2851 gtk_window_set_geometry_hints(GTK_WINDOW(X
->con_dialog
), X
->con_dialog
,
2852 &geometry
, GDK_HINT_MIN_SIZE
);
2853 X
->constants_model
= create_cf_model(M_CON
, X
->con_dialog
);
2854 gtk_tree_view_set_model(GTK_TREE_VIEW(treeview
), X
->constants_model
);
2855 gtk_tree_selection_set_mode(
2856 gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview
)),
2857 GTK_SELECTION_SINGLE
);
2858 add_cf_column(GTK_TREE_VIEW(treeview
), _("No."),
2859 COLUMN_NUMBER
, FALSE
);
2860 add_cf_column(GTK_TREE_VIEW(treeview
), _("Value"),
2861 COLUMN_VALUE
, TRUE
);
2862 add_cf_column(GTK_TREE_VIEW(treeview
), _("Description"),
2863 COLUMN_DESCRIPTION
, TRUE
);
2865 X
->fun_dialog
= GET_WIDGET("edit_functions_dialog");
2866 treeview
= GET_WIDGET("edit_functions_treeview");
2867 gtk_dialog_set_default_response(GTK_DIALOG(X
->fun_dialog
),
2868 GTK_RESPONSE_ACCEPT
);
2869 gtk_window_set_transient_for(GTK_WINDOW(X
->fun_dialog
),
2870 GTK_WINDOW(X
->kframe
));
2871 gtk_window_set_geometry_hints(GTK_WINDOW(X
->fun_dialog
), X
->fun_dialog
,
2872 &geometry
, GDK_HINT_MIN_SIZE
);
2873 X
->functions_model
= create_cf_model(M_FUN
, X
->fun_dialog
);
2874 gtk_tree_view_set_model(GTK_TREE_VIEW(treeview
), X
->functions_model
);
2875 gtk_tree_selection_set_mode(
2876 gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview
)),
2877 GTK_SELECTION_SINGLE
);
2878 add_cf_column(GTK_TREE_VIEW(treeview
), _("No."),
2879 COLUMN_NUMBER
, FALSE
);
2880 add_cf_column(GTK_TREE_VIEW(treeview
), _("Value"),
2881 COLUMN_VALUE
, TRUE
);
2882 add_cf_column(GTK_TREE_VIEW(treeview
), _("Description"),
2883 COLUMN_DESCRIPTION
, TRUE
);
2885 /* When connecting up signals, would ideally use autoconnect but not
2886 * sure how to get the build process working.
2887 * See http://library.gnome.org/devel/libglade/unstable and
2888 * http://www.jamesh.id.au/software/libglade/
2889 * for some information on how to get this to work
2890 * glade_xml_signal_autoconnect(X->ui);
2892 CONNECT_SIGNAL(kframe_key_press_cb
);
2893 CONNECT_SIGNAL(button_cb
);
2894 CONNECT_SIGNAL(menu_item_select_cb
);
2895 CONNECT_SIGNAL(menu_item_deselect_cb
);
2896 CONNECT_SIGNAL(mode_radio_cb
);
2897 CONNECT_SIGNAL(inv_cb
);
2898 CONNECT_SIGNAL(hyp_cb
);
2899 CONNECT_SIGNAL(trig_cb
);
2900 CONNECT_SIGNAL(base_cb
);
2901 CONNECT_SIGNAL(disp_cb
);
2902 CONNECT_SIGNAL(quit_cb
);
2903 CONNECT_SIGNAL(edit_cb
);
2904 CONNECT_SIGNAL(copy_cb
);
2905 CONNECT_SIGNAL(paste_cb
);
2906 CONNECT_SIGNAL(insert_ascii_cb
);
2907 CONNECT_SIGNAL(undo_cb
);
2908 CONNECT_SIGNAL(redo_cb
);
2909 CONNECT_SIGNAL(help_cb
);
2910 CONNECT_SIGNAL(about_cb
);
2911 CONNECT_SIGNAL(show_trailing_zeroes_cb
);
2912 CONNECT_SIGNAL(show_thousands_separator_cb
);
2913 CONNECT_SIGNAL(show_bitcalculating_cb
);
2914 CONNECT_SIGNAL(show_registers_cb
);
2915 CONNECT_SIGNAL(accuracy_radio_cb
);
2916 CONNECT_SIGNAL(accuracy_other_cb
);
2917 CONNECT_SIGNAL(arithmetic_mode_cb
);
2918 CONNECT_SIGNAL(mouse_button_cb
);
2919 CONNECT_SIGNAL(display_focus_in_cb
);
2920 CONNECT_SIGNAL(display_focus_out_cb
);
2921 /* Detect when populating the right-click menu to enable pasting */
2922 CONNECT_SIGNAL(buffer_populate_popup_cb
);
2923 CONNECT_SIGNAL(shift_left_cb
);
2924 CONNECT_SIGNAL(shift_right_cb
);
2925 CONNECT_SIGNAL(bit_toggled
);
2926 CONNECT_SIGNAL(dismiss_aframe
);
2927 CONNECT_SIGNAL(aframe_ok_cb
);
2928 CONNECT_SIGNAL(aframe_cancel_cb
);
2929 CONNECT_SIGNAL(aframe_key_cb
);
2930 CONNECT_SIGNAL(dismiss_spframe
);
2931 CONNECT_SIGNAL(spframe_ok_cb
);
2932 CONNECT_SIGNAL(spframe_cancel_cb
);
2933 CONNECT_SIGNAL(spframe_key_cb
);
2934 CONNECT_SIGNAL(dismiss_rframe
);
2935 CONNECT_SIGNAL(mem_response
);
2936 CONNECT_SIGNAL(edit_constants_cb
);
2937 CONNECT_SIGNAL(edit_functions_cb
);
2938 CONNECT_SIGNAL(edit_constants_response_cb
);
2939 CONNECT_SIGNAL(edit_functions_response_cb
);
2941 widget
= GET_WIDGET("kvbox");
2942 gtk_widget_set_direction(widget
, GTK_TEXT_DIR_LTR
);
2944 X
->menubar
= GET_WIDGET("menubar");
2946 gtk_widget_set_sensitive(GET_WIDGET("show_registers_menu"),
2947 (v
->modetype
!= BASIC
));
2949 X
->scrolledwindow
= GET_WIDGET("display_scroll"),
2951 X
->display_item
= GET_WIDGET("displayitem"),
2952 X
->display_buffer
= gtk_text_view_get_buffer(GTK_TEXT_VIEW(X
->display_item
));
2953 gtk_widget_ensure_style(X
->display_item
);
2954 font_desc
= pango_font_description_copy(X
->display_item
->style
->font_desc
);
2955 pango_font_description_set_size(font_desc
, 16 * PANGO_SCALE
);
2956 gtk_widget_modify_font(X
->display_item
, font_desc
);
2957 pango_font_description_free(font_desc
);
2958 gtk_widget_set_name(X
->display_item
, "displayitem");
2959 gtk_text_view_set_editable(GTK_TEXT_VIEW(X
->display_item
),
2960 (v
->syntax
== exprs
));
2962 atk_object_set_role(gtk_widget_get_accessible(X
->display_item
),
2964 set_display("0.00", FALSE
);
2966 gtk_widget_realize(X
->kframe
);
2967 gtk_window_set_title(GTK_WINDOW(X
->kframe
), _(v
->tool_label
));
2970 X
->bas_panel
= GET_WIDGET("basic_panel");
2971 X
->sci_panel
= GET_WIDGET("scientific_panel");
2972 X
->adv_panel
= GET_WIDGET("advanced_panel");
2973 X
->fin_panel
= GET_WIDGET("financial_panel");
2974 gtk_widget_set_direction(X
->fin_panel
, GTK_TEXT_DIR_LTR
);
2976 size_group
= gtk_size_group_new(GTK_SIZE_GROUP_BOTH
);
2977 for (i
= 0; i
< NBUTTONS
; i
++) {
2978 SNPRINTF(name
, MAXLINE
, "calc_%s_button",
2979 button_widgets
[i
].widget_name
);
2980 X
->buttons
[i
] = GET_WIDGET(name
);
2981 assert(X
->buttons
[i
] != NULL
);
2983 gtk_size_group_add_widget(size_group
, X
->buttons
[i
]);
2985 g_object_set_data(G_OBJECT(X
->buttons
[i
]), "button",
2986 &buttons
[button_widgets
[i
].key
]);
2987 g_object_set_data(G_OBJECT(X
->buttons
[i
]), "mtype",
2988 GINT_TO_POINTER(button_widgets
[i
].mtype
));
2991 for (i
= 0; i
< 16; i
++) {
2992 SNPRINTF(name
, MAXLINE
, "calc_%x_button", i
);
2993 X
->digit_buttons
[i
] = GET_WIDGET(name
);
2996 SNPRINTF(name
, MAXLINE
, "calc_%d_button", i
);
2997 X
->clear_buttons
[0] = GET_WIDGET("calc_clear_simple_button");
2998 X
->clear_buttons
[1] = GET_WIDGET("calc_clear_advanced_button");
3000 X
->mode_panel
= GET_WIDGET("mode_panel");
3001 X
->trig
[0] = GET_WIDGET("degrees_radio");
3002 X
->trig
[1] = GET_WIDGET("gradians_radio");
3003 X
->trig
[2] = GET_WIDGET("radians_radio");
3004 X
->base
[0] = GET_WIDGET("binary_radio");
3005 X
->base
[1] = GET_WIDGET("octal_radio");
3006 X
->base
[2] = GET_WIDGET("decimal_radio");
3007 X
->base
[3] = GET_WIDGET("hexadecimal_radio");
3008 X
->disp
[0] = GET_WIDGET("engineering_radio");
3009 X
->disp
[1] = GET_WIDGET("fixed_point_radio");
3010 X
->disp
[2] = GET_WIDGET("scientific_radio");
3011 X
->inv
= GET_WIDGET("inverse_check");
3012 X
->hyp
= GET_WIDGET("hyperbolic_check");
3013 for (i
= 0; i
< 3; i
++)
3014 g_object_set_data(G_OBJECT(X
->trig
[i
]),
3015 "response_id", GINT_TO_POINTER(i
));
3016 for (i
= 0; i
< 4; i
++)
3017 g_object_set_data(G_OBJECT(X
->base
[i
]),
3018 "response_id", GINT_TO_POINTER(i
));
3019 for (i
= 0; i
< 3; i
++)
3020 g_object_set_data(G_OBJECT(X
->disp
[i
]),
3021 "response_id", GINT_TO_POINTER(i
));
3023 X
->bit_panel
= GET_WIDGET("bit_panel");
3024 //gtk_widget_set_direction(table, GTK_TEXT_DIR_LTR);
3025 for (i
= 0; i
< MAXBITS
; i
++)
3027 SNPRINTF(name
, MAXLINE
, "bit_label_%d", i
);
3028 X
->bits
[i
] = GET_WIDGET(name
);
3029 SNPRINTF(name
, MAXLINE
, "bit_eventbox_%d", i
);
3030 g_object_set_data(G_OBJECT(GET_WIDGET(name
)),
3031 "widget_index", GINT_TO_POINTER(i
));
3034 grey_buttons(v
->base
);
3035 if (v
->modetype
== BASIC
) {
3036 gtk_window_set_focus(GTK_WINDOW(X
->kframe
),
3037 GTK_WIDGET(X
->clear_buttons
[0]));
3039 gtk_window_set_focus(GTK_WINDOW(X
->kframe
),
3040 GTK_WIDGET(X
->clear_buttons
[1]));
3043 X
->statusbar
= GET_WIDGET("statusbar");
3044 X
->status_image
= gtk_image_new_from_stock("", GTK_ICON_SIZE_BUTTON
);
3045 gtk_widget_show(X
->status_image
);
3046 gtk_box_pack_start(GTK_BOX(X
->statusbar
), X
->status_image
, FALSE
, TRUE
, 0);
3048 update_mode_widgets(v
->modetype
);
3050 /* Use loaded Arithmetic Precedence mode setting. */
3051 if (v
->syntax
== exprs
) {
3052 widget
= GET_WIDGET("arithmetic_precedence_menu");
3053 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget
), TRUE
);
3055 widget
= GET_WIDGET("ltr_precedence_menu");
3056 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget
), TRUE
);
3059 X
->undo
= GET_WIDGET("undo_menu");
3060 X
->redo
= GET_WIDGET("redo_menu");
3061 X
->copy
= GET_WIDGET("copy_menu");
3062 X
->paste
= GET_WIDGET("paste_menu");
3064 /* Make menu tooltips displayed in the status bar */
3065 set_menubar_tooltip("quit_menu");
3066 set_menubar_tooltip("copy_menu");
3067 set_menubar_tooltip("paste_menu");
3068 set_menubar_tooltip("insert_ascii_menu");
3069 set_menubar_tooltip("undo_menu");
3070 set_menubar_tooltip("redo_menu");
3071 set_menubar_tooltip("view_basic_menu");
3072 set_menubar_tooltip("view_advanced_menu");
3073 set_menubar_tooltip("view_financial_menu");
3074 set_menubar_tooltip("view_scientific_menu");
3075 set_menubar_tooltip("show_trailing_zeroes_menu");
3076 set_menubar_tooltip("show_thousands_separator_menu");
3077 set_menubar_tooltip("show_bitcalculating_menu");
3078 set_menubar_tooltip("show_registers_menu");
3079 set_menubar_tooltip("ltr_precedence_menu");
3080 set_menubar_tooltip("arithmetic_precedence_menu");
3081 set_menubar_tooltip("help_menu");
3082 set_menubar_tooltip("about_menu");
3084 set_redo_and_undo_button_sensitivity(0, 0);
3086 /* Connect up menu callbacks */
3087 for (i
= 1; i
< 16; i
++) {
3088 SNPRINTF(name
, MAXLINE
, "shift_left%d_menu", i
);
3089 g_object_set_data(G_OBJECT(GET_WIDGET(name
)),
3090 "shiftcount", GINT_TO_POINTER(i
));
3091 SNPRINTF(name
, MAXLINE
, "shift_right%d_menu", i
);
3092 g_object_set_data(G_OBJECT(GET_WIDGET(name
)),
3093 "shiftcount", GINT_TO_POINTER(i
));
3095 g_object_set_data(G_OBJECT(GET_WIDGET("view_basic_menu")),
3096 "calcmode", GINT_TO_POINTER(BASIC
));
3097 g_object_set_data(G_OBJECT(GET_WIDGET("view_advanced_menu")),
3098 "calcmode", GINT_TO_POINTER(ADVANCED
));
3099 g_object_set_data(G_OBJECT(GET_WIDGET("view_financial_menu")),
3100 "calcmode", GINT_TO_POINTER(FINANCIAL
));
3101 g_object_set_data(G_OBJECT(GET_WIDGET("view_scientific_menu")),
3102 "calcmode", GINT_TO_POINTER(SCIENTIFIC
));
3104 /* Make shortcuts for accuracy menus */
3105 accel_group
= gtk_accel_group_new();
3106 gtk_window_add_accel_group(GTK_WINDOW(X
->kframe
), accel_group
);
3107 for (i
= 0; i
< 10; i
++) {
3108 SNPRINTF(name
, MAXLINE
, "acc_item%d", i
);
3109 widget
= GET_WIDGET(name
);
3110 g_object_set_data(G_OBJECT(widget
), "accuracy", GINT_TO_POINTER(i
));
3116 create_menu_item_with_markup(char *label
, int menu_no
, int index
)
3118 GtkWidget
*accel_label
;
3119 GtkWidget
*menu_item
;
3121 accel_label
= gtk_label_new(NULL
);
3122 gtk_label_set_markup_with_mnemonic(GTK_LABEL(accel_label
), label
);
3123 gtk_misc_set_alignment(GTK_MISC(accel_label
), 0.0, 0.5);
3124 menu_item
= gtk_menu_item_new();
3125 gtk_container_add(GTK_CONTAINER(menu_item
), accel_label
);
3126 gtk_widget_show(accel_label
);
3127 gtk_widget_show(menu_item
);
3129 g_object_set_data(G_OBJECT(menu_item
), "button", X
->mrec
[menu_no
]);
3130 gtk_menu_shell_append(GTK_MENU_SHELL(X
->menus
[menu_no
]), menu_item
);
3132 g_signal_connect(G_OBJECT(menu_item
), "activate",
3133 G_CALLBACK(menu_proc_cb
), GINT_TO_POINTER(index
));
3144 X
->clipboard_atom
= gdk_atom_intern("CLIPBOARD", FALSE
);
3145 X
->primary_atom
= gdk_atom_intern("PRIMARY", FALSE
);
3146 create_kframe(); /* Create main gcalctool window. */
3147 set_mode(v
->modetype
);
3149 X
->menus
[M_ACC
] = GET_WIDGET("accuracy_popup");
3150 X
->mrec
[M_ACC
] = &buttons
[KEY_SET_ACCURACY
];
3151 update_accuracy(v
->accuracy
);
3152 X
->menus
[M_LSHF
] = GET_WIDGET("left_shift_popup");
3153 X
->mrec
[M_LSHF
] = &buttons
[KEY_LEFT_SHIFT
];
3154 X
->menus
[M_RSHF
] = GET_WIDGET("right_shift_popup");
3155 X
->mrec
[M_RSHF
] = &buttons
[KEY_RIGHT_SHIFT
];
3157 X
->menus
[M_CON
] = GET_WIDGET("constants_popup");
3158 X
->mrec
[M_CON
] = &buttons
[KEY_CONSTANT
];
3159 X
->menus
[M_FUN
] = GET_WIDGET("functions_popup");
3160 X
->mrec
[M_FUN
] = &buttons
[KEY_FUNCTION
];
3161 for (i
= 0; i
< MAXCONFUN
; i
++) {
3162 X
->constant_menu_items
[i
] = create_menu_item_with_markup("", M_CON
, i
);
3163 X
->function_menu_items
[i
] = create_menu_item_with_markup("", M_FUN
, i
);
3166 X
->menus
[M_STO
] = GET_WIDGET("memory_store_popup");
3167 X
->mrec
[M_STO
] = &buttons
[KEY_STORE
];
3168 X
->menus
[M_RCL
] = GET_WIDGET("memory_recall_popup");
3169 X
->mrec
[M_RCL
] = &buttons
[KEY_RECALL
];
3170 X
->menus
[M_EXCH
] = GET_WIDGET("memory_exchange_popup");
3171 X
->mrec
[M_EXCH
] = &buttons
[KEY_EXCHANGE
];
3172 for (i
= 0; i
< MAXREGS
; i
++) {
3173 // FIXME: These labels should be replaced with GtkTreeModel labels
3174 X
->memory_store_items
[i
] = create_menu_item_with_markup("", M_STO
, i
);
3175 X
->memory_recall_items
[i
] = create_menu_item_with_markup("", M_RCL
, i
);
3176 X
->memory_exchange_items
[i
] = create_menu_item_with_markup("", M_EXCH
, i
);
3179 // This matches existing behaviour we can't do in Glade. But is it needed?
3180 gtk_container_set_border_width(GTK_CONTAINER(X
->menus
[M_ACC
]), 1);
3181 gtk_container_set_border_width(GTK_CONTAINER(X
->menus
[M_LSHF
]), 1);
3182 gtk_container_set_border_width(GTK_CONTAINER(X
->menus
[M_RSHF
]), 1);
3183 gtk_container_set_border_width(GTK_CONTAINER(X
->menus
[M_CON
]), 1);
3184 gtk_container_set_border_width(GTK_CONTAINER(X
->menus
[M_FUN
]), 1);
3185 gtk_container_set_border_width(GTK_CONTAINER(X
->menus
[M_STO
]), 1);
3186 gtk_container_set_border_width(GTK_CONTAINER(X
->menus
[M_RCL
]), 1);
3187 gtk_container_set_border_width(GTK_CONTAINER(X
->menus
[M_EXCH
]), 1);
3189 set_accuracy_toggle(v
->accuracy
);
3190 set_show_tsep_toggle(v
->show_tsep
);
3191 set_show_zeroes_toggle(v
->show_zeroes
);
3192 set_show_bitcalculating_toggle(v
->bitcalculating_mode
);
3193 set_memory_toggle(v
->rstate
);