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
26 #include <sys/param.h>
31 #include <gdk/gdkkeysyms.h>
32 #include <glade/glade.h>
38 #include "functions.h"
39 #include "lr_parser.h"
40 #include "ce_parser.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
{
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
[] = {
86 { 0, GDK_SHIFT_MASK
, 0, 0, 0 },
87 { GDK_0
, GDK_0
, GDK_KP_0
, GDK_KP_Insert
, 0 }},
90 { 0, GDK_SHIFT_MASK
, 0, 0, 0, 0 },
91 { GDK_1
, GDK_1
, GDK_KP_1
, GDK_KP_End
, GDK_R13
, 0 }},
94 { 0, GDK_SHIFT_MASK
, 0, 0, 0 },
95 { GDK_2
, GDK_2
, GDK_KP_2
, GDK_KP_Down
, 0 }},
98 { 0, GDK_SHIFT_MASK
, 0, 0, 0, 0 },
99 { GDK_3
, GDK_3
, GDK_KP_3
, GDK_KP_Page_Down
, GDK_R15
, 0 }},
102 { 0, GDK_SHIFT_MASK
, 0, 0, 0 },
103 { GDK_4
, GDK_4
, GDK_KP_4
, GDK_KP_Left
, 0 }},
106 { 0, GDK_SHIFT_MASK
, 0, 0, 0, 0 },
107 { GDK_5
, GDK_5
, GDK_KP_5
, GDK_KP_Begin
, GDK_R11
, 0 }},
110 { 0, GDK_SHIFT_MASK
, 0, 0, 0 },
111 { GDK_6
, GDK_6
, GDK_KP_6
, GDK_KP_Right
, 0 }},
114 { 0, GDK_SHIFT_MASK
, 0, 0, 0, 0 },
115 { GDK_7
, GDK_7
, GDK_KP_7
, GDK_KP_Home
, GDK_R7
, 0 }},
118 { 0, GDK_SHIFT_MASK
, 0, 0, 0 },
119 { GDK_8
, GDK_8
, GDK_KP_8
, GDK_KP_Up
, 0 }},
122 { 0, GDK_SHIFT_MASK
, 0, 0, 0, 0 },
123 { GDK_9
, GDK_9
, GDK_KP_9
, GDK_KP_Page_Up
, GDK_R9
, 0 }},
149 {KEY_CLEAR
, "clear_simple", M_NONE
,
153 {KEY_CLEAR
, "clear_advanced", M_NONE
,
157 {KEY_SHIFT
, "shift_left", M_LSHF
,
158 { GDK_SHIFT_MASK
, 0 },
161 {KEY_SHIFT
, "shift_right", M_RSHF
,
162 { GDK_SHIFT_MASK
, 0 },
165 {KEY_SET_ACCURACY
, "accuracy", M_ACC
,
166 { GDK_SHIFT_MASK
, 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 },
177 {KEY_STORE
, "store", M_STO
,
178 { GDK_SHIFT_MASK
, 0 },
181 {KEY_RECALL
, "recall", M_RCL
,
182 { GDK_SHIFT_MASK
, 0 },
185 {KEY_EXCHANGE
, "exchange", M_EXCH
,
186 { GDK_SHIFT_MASK
, 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
,
199 { GDK_BackSpace
, 0 }},
201 {KEY_BACKSPACE
, "backspace_advanced", M_NONE
,
203 { GDK_BackSpace
, 0 }},
205 {KEY_NUMERIC_POINT
, "numeric_point", M_NONE
,
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
,
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 },
241 {KEY_CHANGE_SIGN
, "change_sign_advanced", M_NONE
,
242 { GDK_SHIFT_MASK
, 0 },
245 {KEY_INTEGER
, "integer_portion", M_NONE
,
249 {KEY_FRACTION
, "fractional_portion", M_NONE
,
250 { GDK_SHIFT_MASK
, 0 },
253 {KEY_PERCENTAGE
, "percentage", M_NONE
,
254 { GDK_SHIFT_MASK
, 0 },
257 {KEY_SQUARE
, "square", M_NONE
,
258 { GDK_SHIFT_MASK
, 0 },
261 {KEY_SQUARE_ROOT
, "sqrt", M_NONE
,
265 {KEY_RECIPROCAL
, "reciprocal", M_NONE
,
269 {KEY_ABSOLUTE_VALUE
, "abs", M_NONE
,
273 {KEY_MASK_16
, "mask_16", M_NONE
,
275 { GDK_bracketright
, 0 }},
277 {KEY_MASK_32
, "mask_32", M_NONE
,
279 { GDK_bracketleft
, 0 }},
281 {KEY_MODULUS_DIVIDE
, "modulus_divide", M_NONE
,
282 { GDK_SHIFT_MASK
, 0 },
285 {KEY_EXPONENTIAL
, "exponential", M_NONE
,
286 { GDK_SHIFT_MASK
, 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 },
305 {KEY_LOGARITHM
, "logarithm", M_NONE
,
306 { GDK_SHIFT_MASK
, 0 },
309 {KEY_FACTORIAL
, "factorial", M_NONE
,
310 { GDK_SHIFT_MASK
, 0 },
313 {KEY_RANDOM
, "random", M_NONE
,
314 { GDK_SHIFT_MASK
, 0 },
315 { GDK_question
, 0 }},
317 {KEY_SIN
, "sine", M_NONE
,
318 { GDK_SHIFT_MASK
, 0 },
321 {KEY_COS
, "cosine", M_NONE
,
322 { GDK_SHIFT_MASK
, 0 },
325 {KEY_TAN
, "tangent", M_NONE
,
326 { GDK_SHIFT_MASK
, 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 },
337 {KEY_AND
, "and", M_NONE
,
338 { GDK_SHIFT_MASK
, 0 },
339 { GDK_ampersand
, 0 }},
341 {KEY_XOR
, "xor", M_NONE
,
345 {KEY_XNOR
, "xnor", M_NONE
,
349 {KEY_FINC_CTRM
, "finc_compounding_term", M_NONE
,
353 {KEY_FINC_DDB
, "finc_double_declining_depreciation", M_NONE
,
354 { GDK_SHIFT_MASK
, 0 },
357 {KEY_FINC_FV
, "finc_future_value", M_NONE
,
361 {KEY_FINC_PMT
, "finc_periodic_payment", M_NONE
,
362 { GDK_SHIFT_MASK
, 0 },
365 {KEY_FINC_PV
, "finc_present_value", M_NONE
,
369 {KEY_FINC_RATE
, "finc_periodic_interest_rate", M_NONE
,
370 { GDK_SHIFT_MASK
, 0 },
373 {KEY_FINC_SLN
, "finc_straight_line_depreciation", M_NONE
,
377 {KEY_FINC_SYD
, "finc_sum_of_the_years_digits_depreciation", M_NONE
,
381 {KEY_FINC_TERM
, "finc_term", M_NONE
,
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, \
401 struct Xobject
{ /* Gtk+/Xlib graphics object. */
402 GdkAtom clipboard_atom
;
403 GdkAtom primary_atom
;
407 GtkWidget
*kframe
; /* Main window. */
409 GtkTreeModel
*constants_model
;
410 GtkWidget
*con_dialog
; /* Edit constants dialog. */
412 GtkTreeModel
*functions_model
;
413 GtkWidget
*fun_dialog
; /* Edit functions dialog. */
414 GtkWidget
*menubar
; // FIXME: Why is this needed?
416 GtkWidget
*bit_panel
;
417 GtkWidget
*bits
[MAXBITS
]; /* The 0/1 labels in the bit panel. */
419 GtkWidget
*status_image
; /* Statusbar image */
420 GtkWidget
*statusbar
;
422 GtkWidget
*undo
; /* Undo menuitem */
423 GtkWidget
*redo
; /* Redo menuitem */
424 GtkWidget
*copy
; /* Copy menuitem */
425 GtkWidget
*paste
; /* Paste menuitem */
427 GtkWidget
*aframe
; /* ASCII window. */
428 GtkWidget
*aframe_ch
;
430 GtkWidget
*display_item
; /* Calculator display. */
431 GtkTextBuffer
*display_buffer
; /* Buffer used in display */
432 GtkWidget
*scrolledwindow
; /* Scrolled window for display_item. */
434 GtkWidget
*rframe
; /* Register window. */
435 GtkWidget
*regs
[MAXREGS
]; /* Memory registers. */
437 GtkWidget
*spframe
; /* Set Precision window. */
438 GtkWidget
*spframe_val
;
439 GtkWidget
*menus
[MAXMENUS
];
441 GtkWidget
*buttons
[NBUTTONS
];
442 GtkWidget
*digit_buttons
[16];
443 GtkWidget
*clear_buttons
[2];
445 GtkWidget
*bas_panel
; /* Panel containing basic mode widgets. */
446 GtkWidget
*adv_panel
; /* Panel containing advanced mode widgets. */
447 GtkWidget
*fin_panel
; /* Panel containing financial mode widgets. */
448 GtkWidget
*sci_panel
; /* Panel containing scientific mode widgets. */
449 GtkWidget
*mode_panel
; /* Panel containing scientific mode widgets. */
451 /* Labels for popup menus */
452 GtkWidget
*constant_menu_items
[MAXCONFUN
];
453 GtkWidget
*function_menu_items
[MAXCONFUN
];
454 GtkWidget
*memory_store_items
[MAXREGS
];
455 GtkWidget
*memory_recall_items
[MAXREGS
];
456 GtkWidget
*memory_exchange_items
[MAXREGS
];
458 /* Scientific mode widgets */
459 GtkWidget
*hyp
; /* Hyperbolic mode. */
460 GtkWidget
*inv
; /* Inverse mode. */
461 GtkWidget
*base
[MAXBASES
]; /* Numeric base radio buttons. */
462 GtkWidget
*disp
[MAXDISPMODES
]; /* Numeric display mode. */
463 GtkWidget
*trig
[MAXTRIGMODES
]; /* Trigonometric mode. */
465 int mode
; /* The new mode. */
466 int menuval
; /* Index to button array at menu time. */
467 char *lnp
; /* Localized numerical point (UTF8 format) */
468 struct button
*mrec
[MAXMENUS
];
471 typedef struct Xobject
*XVars
;
485 ui_set_accuracy(int accuracy
)
489 char *desc
, *current
, *tooltip
;
491 SNPRINTF(text
, MAXLINE
, _("Other (%d) ..."), accuracy
);
492 widget
= gtk_bin_get_child(GTK_BIN(GET_WIDGET("acc_item_other")));
493 gtk_label_set_text(GTK_LABEL(widget
), text
);
495 desc
= g_strdup_printf(ngettext("Set accuracy from 0 to %d numeric places.",
496 "Set accuracy from 0 to %d numeric places.",
500 /* Translator: This refers to the current accuracy setting */
501 current
= g_strdup_printf(ngettext("Currently set to %d places.",
502 "Currently set to %d places.",
505 tooltip
= g_strdup_printf ("%s %s [A]", desc
, current
);
506 gtk_widget_set_tooltip_text (GET_WIDGET("calc_accuracy_button"), tooltip
);
511 if (accuracy
>= 0 && accuracy
<= 9) {
512 SNPRINTF(text
, MAXLINE
, "acc_item%d", accuracy
);
513 widget
= GET_WIDGET(text
);
514 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget
), TRUE
);
520 ui_update_trig_mode()
522 static char *sine_labels
[] = {N_("Sin"), N_("Sinh"),
523 N_("Sin<sup>-1</sup>"),
524 N_("Sinh<sup>-1</sup>")};
525 static int sine_functions
[] = {KEY_SIN
, KEY_SINH
, KEY_ASIN
, KEY_ASINH
};
526 static char *cosine_labels
[] = {N_("Cos"), N_("Cosh"),
527 N_("Cos<sup>-1</sup>"),
528 N_("Cosh<sup>-1</sup>")};
529 static int cosine_functions
[] = {KEY_COS
, KEY_COSH
, KEY_ACOS
, KEY_ACOSH
};
530 static char *tangent_labels
[] = {N_("Tan"), N_("Tanh"),
531 N_("Tan<sup>-1</sup>"),
532 N_("Tanh<sup>-1</sup>")};
533 static int tangent_functions
[] = {KEY_TAN
, KEY_TANH
, KEY_ATAN
, KEY_ATANH
};
536 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(X
->hyp
))) {
539 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(X
->inv
))) {
543 gtk_label_set_markup(GTK_LABEL(GET_WIDGET("sine_label")),
545 g_object_set_data(G_OBJECT(GET_WIDGET("calc_sine_button")), "button",
546 &buttons
[sine_functions
[index
]]);
548 gtk_label_set_markup(GTK_LABEL(GET_WIDGET("cosine_label")),
549 cosine_labels
[index
]);
550 g_object_set_data(G_OBJECT(GET_WIDGET("calc_cosine_button")), "button",
551 &buttons
[cosine_functions
[index
]]);
553 gtk_label_set_markup(GTK_LABEL(GET_WIDGET("tangent_label")),
554 tangent_labels
[index
]);
555 g_object_set_data(G_OBJECT(GET_WIDGET("calc_tangent_button")), "button",
556 &buttons
[tangent_functions
[index
]]);
561 ui_set_hyperbolic_state(gboolean state
)
563 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(X
->hyp
), state
);
564 ui_update_trig_mode();
569 ui_set_inverse_state(gboolean state
)
571 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(X
->inv
), state
);
572 ui_update_trig_mode();
577 ui_set_trigonometric_mode(enum trig_type mode
)
579 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(X
->trig
[mode
]), 1);
584 ui_set_numeric_mode(enum base_type mode
)
586 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(X
->disp
[mode
]), 1);
591 ui_set_undo_enabled(gboolean undo
, gboolean redo
)
593 gtk_widget_set_sensitive(X
->undo
, undo
);
594 gtk_widget_set_sensitive(X
->redo
, redo
);
601 Display
*dpy
= GDK_DISPLAY();
602 char client_hostname
[MAXHOSTNAMELEN
+ 4];
603 char hostname
[MAXHOSTNAMELEN
];
604 char *display
= DisplayString(dpy
);
605 char *scanner
= display
;
607 GETHOSTNAME(hostname
, MAXHOSTNAMELEN
);
613 while (*scanner
!= ':') {
619 if (strcmp(display
, hostname
) &&
620 strcmp(display
, "localhost") &&
621 strcmp(display
, "unix") &&
622 strcmp(display
, "")) {
623 SPRINTF(client_hostname
, " [%s] ", hostname
);
625 STRCPY(client_hostname
, "");
630 if (client_hostname
[0] == '\0')
633 return(strdup(client_hostname
));
638 ui_set_mode(enum mode_type mode
)
642 char *hostname
, title
[MAXLINE
];
647 gtk_widget_show(X
->bas_panel
);
648 gtk_widget_hide(X
->adv_panel
);
649 gtk_widget_hide(X
->fin_panel
);
650 gtk_widget_hide(X
->mode_panel
);
651 gtk_widget_hide(X
->bit_panel
);
652 gtk_widget_hide(X
->sci_panel
);
653 menu
= GET_WIDGET("view_basic_menu");
657 gtk_widget_hide(X
->bas_panel
);
658 gtk_widget_show(X
->adv_panel
);
659 gtk_widget_hide(X
->fin_panel
);
660 gtk_widget_hide(X
->mode_panel
);
661 gtk_widget_hide(X
->bit_panel
);
662 gtk_widget_hide(X
->sci_panel
);
663 menu
= GET_WIDGET("view_advanced_menu");
667 gtk_widget_hide(X
->bas_panel
);
668 gtk_widget_show(X
->adv_panel
);
669 gtk_widget_show(X
->fin_panel
);
670 gtk_widget_hide(X
->mode_panel
);
671 gtk_widget_hide(X
->bit_panel
);
672 gtk_widget_hide(X
->sci_panel
);
673 menu
= GET_WIDGET("view_financial_menu");
677 gtk_widget_hide(X
->bas_panel
);
678 gtk_widget_show(X
->adv_panel
);
679 gtk_widget_hide(X
->fin_panel
);
680 gtk_widget_show_all(X
->mode_panel
);
681 if (v
->bitcalculating_mode
) {
682 gtk_widget_show_all(X
->bit_panel
);
684 gtk_widget_hide(X
->bit_panel
);
686 gtk_widget_show(X
->sci_panel
);
687 menu
= GET_WIDGET("view_scientific_menu");
696 r
= g_new0(GtkRequisition
, 1);
697 gtk_widget_size_request(X
->menubar
, r
);
700 gtk_widget_size_request(X
->display_item
, r
);
701 w
= MAX(w
, r
->width
);
704 if (GTK_WIDGET_VISIBLE(X
->fin_panel
)) {
705 gtk_widget_size_request(X
->fin_panel
, r
);
706 w
= MAX(w
, r
->width
);
710 if (GTK_WIDGET_VISIBLE(X
->mode_panel
)) {
711 gtk_widget_size_request(X
->mode_panel
, r
);
712 w
= MAX(w
, r
->width
);
716 if (GTK_WIDGET_VISIBLE(X
->sci_panel
)) {
717 gtk_widget_size_request(X
->sci_panel
, r
);
718 w
= MAX(w
, r
->width
);
722 /* For initial display. */
723 gtk_window_set_default_size(GTK_WINDOW(X
->kframe
), w
, h
);
724 gtk_window_resize(GTK_WINDOW(X
->kframe
), w
, h
);
728 if((hostname
= make_hostname())) {
729 SNPRINTF(title
, MAXLINE
, hostname_titles
[mode
], hostname
);
732 SNPRINTF(title
, MAXLINE
, titles
[mode
]);
734 gtk_window_set_title(GTK_WINDOW(X
->kframe
), title
);
736 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu
), TRUE
);
741 ui_set_statusbar(gchar
*text
, const gchar
*imagename
)
743 GtkImage
*image
= GTK_IMAGE(X
->status_image
);
749 gtk_image_set_from_stock(image
, imagename
, GTK_ICON_SIZE_BUTTON
);
750 gtk_statusbar_pop(GTK_STATUSBAR(X
->statusbar
), 0);
751 gtk_statusbar_push(GTK_STATUSBAR(X
->statusbar
), 0, text
);
756 bin_str(int MP_value
[MP_SIZE
], char *str
, int maxbits
)
758 int i
, MP0
[MP_SIZE
], MP1
[MP_SIZE
], MP2
[MP_SIZE
], MP3
[MP_SIZE
];
761 MPstr_to_num("0", DEC
, MP0
);
762 MPstr_to_num("1", DEC
, MP1
);
763 MPstr_to_num("2", DEC
, MP2
);
765 if (mplt(MP_value
, MP0
)) {
766 mpcmim(MP_value
, MP0
);
767 mpadd(MP0
, MP1
, MP0
);
770 mpcmim(MP_value
, MP0
);
773 for (i
= 0; i
< maxbits
; i
++) {
774 double lsb
; /* Least significant bit. */
775 calc_and(MP3
, MP0
, MP1
);
779 str
[maxbits
- i
-1] = (neg
) ? '1' : '0';
781 str
[maxbits
- i
-1] = (neg
) ? '0' : '1';
784 mpdiv(MP0
, MP2
, MP3
);
795 int bit_str_len
, i
, MP1
[MP_SIZE
], MP2
[MP_SIZE
];
797 char str
[64], label
[3];
798 int ret
= usable_num(MP
);
802 MPstr_to_num(v
->display
, v
->base
, MP1
);
804 if (mpeq(MP1
, MP2
)) {
805 char *bit_str
, label
[3], tmp
[MAXLINE
];
806 int toclear
= (v
->current
== KEY_CLEAR_ENTRY
)
809 bit_str
= make_fixed(MP1
, tmp
, BIN
, MAXLINE
, toclear
);
810 bit_str_len
= strlen(bit_str
);
811 if (bit_str_len
<= MAXBITS
) {
812 gtk_widget_set_sensitive(X
->bit_panel
, TRUE
);
815 for (i
= 0; i
< MAXBITS
; i
++) {
816 label
[1] = (i
< bit_str_len
) ? bit_str
[bit_str_len
-i
-1] : '0';
817 gtk_label_set_text(GTK_LABEL(X
->bits
[MAXBITS
- i
- 1]), label
);
823 gtk_widget_set_sensitive(X
->bit_panel
, FALSE
);
827 if (ret
|| !is_integer(MP
)) {
828 gtk_widget_set_sensitive(X
->bit_panel
, FALSE
);
831 bin_str(MP
, str
, 64);
832 gtk_widget_set_sensitive(X
->bit_panel
, TRUE
);
835 for (i
= 0; i
< 64; i
++) {
836 label
[1] = str
[64 - i
- 1];
837 gtk_label_set_text(GTK_LABEL(X
->bits
[64 - i
- 1]), label
);
854 if (GTK_WIDGET_VISIBLE(
855 GTK_SCROLLED_WINDOW(X
->scrolledwindow
)->hscrollbar
)) {
858 set
= gtk_scrolled_window_get_hadjustment(
859 GTK_SCROLLED_WINDOW(X
->scrolledwindow
));
860 gtk_adjustment_set_value(set
, set
->upper
);
861 gtk_scrolled_window_set_hadjustment(
862 GTK_SCROLLED_WINDOW(X
->scrolledwindow
), set
);
868 ui_set_display(char *str
, gboolean minimize_changes
)
870 char localized
[MAX_LOCALIZED
];
871 GtkTextIter start
, end
;
877 if (str
== NULL
|| str
[0] == '\0') {
880 if (v
->noparens
== 0) {
881 localize_number(localized
, str
);
885 gtk_text_buffer_get_bounds(X
->display_buffer
, &start
, &end
);
886 text
= gtk_text_buffer_get_text(X
->display_buffer
, &start
, &end
, TRUE
);
887 diff
= strcmp (text
, str
);
893 if (minimize_changes
) {
894 if (len1
< len2
&& strncmp(text
, str
, len1
) == 0) {
896 gtk_text_buffer_insert(X
->display_buffer
, &end
, str
+ len1
, -1);
898 } else if (len1
> len2
&& strncmp(text
, str
, len2
) == 0) {
900 gtk_text_buffer_get_iter_at_offset (X
->display_buffer
, &start
, len2
);
901 gtk_text_buffer_delete(X
->display_buffer
, &start
, &end
);
907 gtk_text_buffer_delete(X
->display_buffer
, &start
, &end
);
908 gtk_text_buffer_insert(X
->display_buffer
, &end
, str
, -1);
916 /* When an error condition occurs:
918 * - make insensitive all buttons except Clr.
919 * - make all Scientific mode toggles and checkboxes insensitive.
920 * - make all menubar items insensitive except:
924 * When the error condition is cleared, resensitise everything, setting
925 * the numeric base buttons correctly.
929 ui_set_error_state(gboolean error
)
935 for (i
= 0; i
< NBUTTONS
; i
++) {
936 gtk_widget_set_sensitive(X
->buttons
[i
], !v
->error
);
938 /* Clr button always sensitive. */
939 gtk_widget_set_sensitive(X
->clear_buttons
[0], TRUE
);
940 gtk_widget_set_sensitive(X
->clear_buttons
[1], TRUE
);
943 ui_set_base(v
->base
);
946 gtk_widget_set_sensitive(X
->mode_panel
, !v
->error
);
948 // FIXME: Isn't this missing a whole lot of widgets?
949 SET_MENUBAR_ITEM_STATE("copy_menu", !v
->error
);
950 SET_MENUBAR_ITEM_STATE("paste_menu", !v
->error
);
951 SET_MENUBAR_ITEM_STATE("insert_ascii_menu", !v
->error
);
952 SET_MENUBAR_ITEM_STATE("view_basic_menu", !v
->error
);
953 SET_MENUBAR_ITEM_STATE("view_advanced_menu", !v
->error
);
954 SET_MENUBAR_ITEM_STATE("view_financial_menu", !v
->error
);
955 SET_MENUBAR_ITEM_STATE("view_scientific_menu", !v
->error
);
956 SET_MENUBAR_ITEM_STATE("show_trailing_zeroes_menu",
957 !v
->error
&& (v
->modetype
== SCIENTIFIC
));
958 SET_MENUBAR_ITEM_STATE("show_thousands_separator_menu", !v
->error
);
959 SET_MENUBAR_ITEM_STATE("show_registers_menu", !v
->error
);
960 SET_MENUBAR_ITEM_STATE("arithmetic_precedence_menu", !v
->error
);
961 SET_MENUBAR_ITEM_STATE("about_menu", !v
->error
);
967 about_cb(GtkWidget
*widget
)
969 const gchar
*authors
[] = {
970 "Rich Burridge <rich.burridge@sun.com>",
971 "Sami Pietila <sampie@ariana-dsl.utu.fi>",
972 "Robert Ancell <robert.ancell@gmail.com>",
975 const gchar
*documenters
[] = {
979 const gchar
*translator_credits
= _("translator-credits");
981 const char *license
[] = {
982 N_("Gcalctool is free software; you can redistribute it and/or modify\n"
983 "it under the terms of the GNU General Public License as published by\n"
984 "the Free Software Foundation; either version 2 of the License, or\n"
985 "(at your option) any later version.\n"),
986 N_("Gcalctool is distributed in the hope that it will be useful,\n"
987 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
988 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
989 "GNU General Public License for more details.\n"),
990 N_("You should have received a copy of the GNU General Public License\n"
991 "along with Gcalctool; if not, write to the Free Software Foundation, Inc.,\n"
992 "51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA\n")
995 char *license_trans
= g_strconcat(_(license
[0]), "\n",
1000 gtk_show_about_dialog(GTK_WINDOW(X
->kframe
),
1001 "name",_("Gcalctool"),
1003 "copyright", _("\xc2\xa9 1986-2007 The Gcalctool authors"),
1004 "license", license_trans
,
1005 "comments", _("Calculator with financial and scientific modes."),
1007 "documenters", documenters
,
1008 "translator_credits", translator_credits
,
1009 "logo-icon-name", "gnome-calculator",
1015 cell_edited_cb(GtkCellRendererText
*cell
, const gchar
*path_string
,
1016 const gchar
*new_text
, gpointer data
)
1018 GtkTreeModel
*model
= (GtkTreeModel
*) data
;
1019 GtkTreePath
*path
= gtk_tree_path_new_from_string(path_string
);
1024 column
= g_object_get_data(G_OBJECT(cell
), "column");
1026 gtk_tree_model_get_iter(model
, &iter
, path
);
1028 switch (GPOINTER_TO_INT(column
)) {
1030 gtk_tree_model_get(model
, &iter
, column
, &old_text
, -1);
1032 gtk_list_store_set(GTK_LIST_STORE(model
), &iter
, column
,
1033 g_strdup(new_text
), -1);
1036 case COLUMN_DESCRIPTION
:
1037 gtk_tree_model_get(model
, &iter
, column
, &old_text
, -1);
1039 gtk_list_store_set(GTK_LIST_STORE(model
), &iter
, column
,
1040 g_strdup(new_text
), -1);
1044 gtk_tree_path_free(path
);
1049 add_cf_column(GtkTreeView
*treeview
, gchar
*name
, gint colno
, gboolean editable
)
1051 GtkCellRenderer
*renderer
;
1052 GtkTreeModel
*model
= gtk_tree_view_get_model(treeview
);
1054 renderer
= gtk_cell_renderer_text_new();
1056 g_signal_connect(G_OBJECT(renderer
), "edited",
1057 G_CALLBACK(cell_edited_cb
), model
);
1059 g_object_set_data(G_OBJECT(renderer
), "column", GINT_TO_POINTER(colno
));
1062 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(treeview
),
1065 "editable", COLUMN_EDITABLE
,
1068 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(treeview
),
1078 aframe_cancel_cb(GtkButton
*button
, gpointer user_data
)
1080 gtk_widget_hide(X
->aframe
);
1086 aframe_key_cb(GtkWidget
*widget
, GdkEventKey
*event
, gpointer data
)
1088 g_return_val_if_fail(GTK_IS_WIDGET(widget
), FALSE
);
1090 if (event
->keyval
== GDK_Escape
) {
1091 gtk_widget_hide(X
->aframe
);
1100 aframe_ok_cb(GtkButton
*button
, gpointer user_data
)
1105 ch
= (char *) gtk_entry_get_text(GTK_ENTRY(X
->aframe_ch
));
1107 mpcim(&val
, v
->MPdisp_val
);
1108 show_display(v
->MPdisp_val
);
1109 gtk_widget_hide(X
->aframe
);
1115 base_cb(GtkWidget
*widget
)
1117 enum base_type base
;
1119 base
= (enum base_type
) g_object_get_data(G_OBJECT(widget
),
1121 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget
))) {
1133 static void do_button(struct button
*n
, int arg
)
1135 struct exprm_state
*e
;
1137 switch (v
->syntax
) {
1139 process_item(n
, arg
);
1141 if (v
->new_input
&& v
->dtype
== FIX
) {
1142 STRNCPY(v
->fnum
, v
->display
, MAX_DIGITS
- 1);
1143 ui_set_display(v
->fnum
, TRUE
);
1150 MEMCPY(&(e
->button
), n
, sizeof(struct button
));
1165 GError
*error
= NULL
;
1173 const char * const * langs
= g_get_language_names ();
1175 for (i
= 0; langs
[i
]; i
++) {
1177 if (strchr (lang
, '.')) {
1181 uri
= g_build_filename(PACKAGE_DATA_DIR
,
1182 "/gnome/help/gcalctool/",
1187 if (g_file_test (uri
, G_FILE_TEST_EXISTS
)) {
1192 command
= g_strconcat ("gnome-open ghelp://", uri
, NULL
);
1193 gscreen
= gdk_screen_get_default();
1194 gdk_spawn_command_line_on_screen (gscreen
, command
, &error
);
1198 d
= gtk_message_dialog_new(NULL
,
1199 GTK_DIALOG_MODAL
| GTK_DIALOG_DESTROY_WITH_PARENT
,
1200 GTK_MESSAGE_ERROR
, GTK_BUTTONS_OK
,
1202 gtk_dialog_run(GTK_DIALOG(d
));
1203 gtk_widget_destroy(d
);
1204 g_error_free(error
);
1214 put_constant(int n
, char *con_value
, char *con_name
)
1217 char *cstr
= g_strdup(con_value
);
1219 /* Constants are written out with no thousands seaparator and with a radix
1223 SNPRINTF(key
, MAXLINE
, "constant%1dvalue", n
);
1224 set_resource(key
, cstr
);
1227 SNPRINTF(key
, MAXLINE
, "constant%1dname", n
);
1228 set_resource(key
, con_name
);
1233 put_function(int n
, char *fun_value
, char *fun_name
)
1237 SNPRINTF(key
, MAXLINE
, "function%1dvalue", n
);
1238 set_resource(key
, fun_value
);
1240 SNPRINTF(key
, MAXLINE
, "function%1dname", n
);
1241 set_resource(key
, fun_name
);
1247 menu_proc_cb(GtkMenuItem
*mi
, gpointer user_data
)
1249 struct button
*n
= (struct button
*) g_object_get_data(G_OBJECT(mi
), "button");
1250 do_button(n
, GPOINTER_TO_INT(user_data
));
1254 /* Create popup window for editing constants/functions. */
1257 update_popup_label(GtkWidget
*menu_item
, gchar
*text
)
1260 label
= (GtkWidget
*)gtk_container_get_children(GTK_CONTAINER(menu_item
))->data
;
1261 gtk_label_set_markup_with_mnemonic(GTK_LABEL(label
), text
);
1265 update_constants_menu(void)
1267 char mline
[MAXLINE
];
1270 for (i
= 0; i
< MAXCONFUN
; i
++) {
1271 SNPRINTF(mline
, MAXLINE
,
1272 "<span weight=\"bold\">%s_%1d:</span> %s [%s]", _("C"), i
,
1273 make_number(v
->MPcon_vals
[i
], DEC
, TRUE
),
1275 update_popup_label(X
->constant_menu_items
[i
], mline
);
1281 update_functions_menu(void)
1283 char mline
[MAXLINE
];
1286 for (i
= 0; i
< MAXCONFUN
; i
++) {
1287 if (strlen(v
->fun_vals
[i
]) != 0) {
1288 SNPRINTF(mline
, MAXLINE
,
1289 "<span weight=\"bold\">%s_%1d:</span> %s [%s]",
1290 _("F"), i
, v
->fun_vals
[i
], v
->fun_names
[i
]);
1291 gtk_widget_show(X
->function_menu_items
[i
]);
1292 update_popup_label(X
->function_menu_items
[i
], mline
);
1295 gtk_widget_hide(X
->function_menu_items
[i
]);
1301 edit_constants_response_cb(GtkDialog
*dialog
, gint id
)
1308 if (id
== GTK_RESPONSE_HELP
) {
1312 if (id
== GTK_RESPONSE_ACCEPT
) {
1313 if (gtk_tree_model_get_iter_first(X
->constants_model
, &iter
)) {
1315 gtk_tree_model_get(X
->constants_model
, &iter
,
1316 COLUMN_NUMBER
, &number
,
1317 COLUMN_VALUE
, &value
,
1318 COLUMN_DESCRIPTION
, &description
, -1);
1319 MPstr_to_num(value
, DEC
, v
->MPcon_vals
[number
]);
1320 STRNCPY(v
->con_names
[number
], description
, MAXLINE
- 1);
1321 put_constant(number
, value
, description
);
1322 } while (gtk_tree_model_iter_next(X
->constants_model
, &iter
));
1326 gtk_widget_hide(GTK_WIDGET(dialog
));
1331 edit_functions_response_cb(GtkDialog
*dialog
, gint id
)
1338 if (id
== GTK_RESPONSE_HELP
) {
1342 if (id
== GTK_RESPONSE_ACCEPT
) {
1343 if (gtk_tree_model_get_iter_first(X
->functions_model
, &iter
)) {
1345 gtk_tree_model_get(X
->functions_model
, &iter
,
1346 COLUMN_NUMBER
, &number
,
1347 COLUMN_VALUE
, &value
,
1348 COLUMN_DESCRIPTION
, &description
, -1);
1349 STRNCPY(v
->fun_vals
[number
], convert(value
), MAXLINE
- 1);
1350 STRNCPY(v
->fun_names
[number
], description
, MAXLINE
- 1);
1351 put_function(number
, value
, description
);
1352 } while (gtk_tree_model_iter_next(X
->functions_model
, &iter
));
1356 gtk_widget_hide(GTK_WIDGET(dialog
));
1361 static GtkTreeModel
*
1362 create_cf_model(enum menu_type mtype
, GtkWidget
*dialog
)
1365 GtkListStore
*model
;
1367 gchar
*value
, *description
;
1369 model
= gtk_list_store_new(NUM_COLUMNS
, G_TYPE_INT
, G_TYPE_STRING
,
1370 G_TYPE_STRING
, G_TYPE_BOOLEAN
);
1371 for (i
= 0; i
< MAXCONFUN
; i
++) {
1372 gtk_list_store_append(model
, &iter
);
1374 if (mtype
== M_CON
) {
1375 value
= g_strdup(make_number(v
->MPcon_vals
[i
], DEC
, TRUE
));
1376 description
= g_strdup(v
->con_names
[i
]);
1378 value
= g_strdup(v
->fun_vals
[i
]);
1379 description
= g_strdup(v
->fun_names
[i
]);
1381 gtk_list_store_set(model
, &iter
,
1383 COLUMN_VALUE
, value
,
1384 COLUMN_DESCRIPTION
, description
,
1385 COLUMN_EDITABLE
, TRUE
,
1389 return(GTK_TREE_MODEL(model
));
1394 set_show_tsep_toggle(int state
)
1398 mi
= GET_WIDGET("show_thousands_separator_menu");
1399 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mi
), state
);
1404 set_show_bitcalculating_toggle(int state
)
1408 mi
= GET_WIDGET("show_bitcalculating_menu");
1409 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mi
), state
);
1414 set_show_zeroes_toggle(int state
)
1418 menu
= GET_WIDGET("show_trailing_zeroes_menu");
1419 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu
), state
);
1420 menu
= GET_WIDGET("acc_trailing_zeroes_item");
1421 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu
), state
);
1426 ui_make_registers() /* Calculate memory register frame values. */
1428 char *mval
, key
[MAXLINE
];
1431 for (n
= 0; n
< MAXREGS
; n
++) {
1432 mval
= make_number(v
->MPmvals
[n
], v
->base
, TRUE
);
1433 gtk_entry_set_width_chars(GTK_ENTRY(X
->regs
[n
]), strlen(mval
));
1434 gtk_entry_set_text(GTK_ENTRY(X
->regs
[n
]), mval
);
1435 SNPRINTF(key
, MAXLINE
, "register%d", n
);
1436 set_resource(key
, mval
);
1442 reset_mode_display(void)
1444 switch (v
->syntax
) {
1446 show_display(v
->MPdisp_val
);
1456 ui_make_registers();
1465 (void) gdk_window_get_origin(X
->kframe
->window
, &x
, &y
);
1466 set_int_resource(R_XPOS
, x
);
1467 set_int_resource(R_YPOS
, y
);
1472 change_mode(int mode
)
1477 ui_set_base(v
->base
);
1478 ui_set_numeric_mode(FIX
);
1480 ui_set_accuracy(v
->accuracy
);
1482 v
->show_tsep
= FALSE
;
1483 set_show_tsep_toggle(v
->show_tsep
);
1484 set_boolean_resource(R_TSEP
, v
->show_tsep
== TRUE
);
1486 v
->show_zeroes
= FALSE
;
1487 set_show_zeroes_toggle(v
->show_zeroes
);
1488 set_boolean_resource(R_ZEROES
, v
->show_zeroes
== TRUE
);
1490 reset_mode_display();
1496 request_change_mode()
1498 GtkWidget
*dialog
, *request_check
, *button
;
1501 if (!v
->warn_change_mode
)
1504 dialog
= gtk_message_dialog_new(GTK_WINDOW(X
->kframe
),
1505 GTK_DIALOG_MODAL
|GTK_DIALOG_DESTROY_WITH_PARENT
,
1506 GTK_MESSAGE_WARNING
,
1509 _("Changing Modes Clears Calculation"));
1510 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog
),
1512 _("When you change modes, the current calculation "
1513 "will be cleared, and the base will be reset to "
1516 request_check
= gtk_check_button_new_with_mnemonic(_("_Do not warn me again"));
1517 gtk_box_pack_end(GTK_BOX(GTK_DIALOG(dialog
)->vbox
),
1518 request_check
, FALSE
, FALSE
, 0);
1520 button
= gtk_dialog_add_button(GTK_DIALOG(dialog
),
1521 _("C_hange Mode"), GTK_RESPONSE_ACCEPT
);
1522 gtk_button_set_image(GTK_BUTTON(button
),
1523 gtk_image_new_from_stock(GTK_STOCK_REFRESH
,
1524 GTK_ICON_SIZE_BUTTON
));
1525 /* Set default focus on affirmative button */
1526 gtk_widget_grab_focus(button
);
1528 gtk_dialog_set_alternative_button_order(GTK_DIALOG(dialog
),
1529 GTK_RESPONSE_ACCEPT
,
1530 GTK_RESPONSE_CANCEL
,
1533 gtk_window_set_position(GTK_WINDOW(dialog
),
1534 GTK_WIN_POS_CENTER_ON_PARENT
);
1536 gtk_widget_show_all(dialog
);
1537 response
= gtk_dialog_run(GTK_DIALOG(dialog
));
1539 // FIXME: Save this in GConf
1540 v
->warn_change_mode
= !gtk_toggle_button_get_active(
1541 GTK_TOGGLE_BUTTON(request_check
));
1543 gtk_widget_destroy(dialog
);
1545 return response
== GTK_RESPONSE_ACCEPT
;
1551 bit_toggle_cb(GtkWidget
*event_box
, GdkEventButton
*event
)
1554 unsigned long long lval
;
1555 int n
, MP1
[MP_SIZE
], index
;
1557 index
= GPOINTER_TO_INT(g_object_get_data(G_OBJECT(event_box
),
1559 n
= MAXBITS
- index
- 1;
1560 MPstr_to_num(v
->display
, v
->base
, MP1
);
1561 mpcmd(MP1
, &number
);
1562 lval
= (long long) number
;
1564 if (lval
& (1LL << n
)) {
1565 lval
&= ~(1LL << n
);
1566 gtk_label_set_text(GTK_LABEL(X
->bits
[index
]), " 0");
1569 gtk_label_set_text(GTK_LABEL(X
->bits
[index
]), " 1");
1572 number
= (double) lval
;
1573 mpcdm(&number
, v
->MPdisp_val
);
1574 show_display(v
->MPdisp_val
);
1582 menu_item_select_cb(GtkWidget
*widget
)
1584 GtkStatusbar
*statusbar
= GTK_STATUSBAR(X
->statusbar
);
1588 context_id
= gtk_statusbar_get_context_id(statusbar
, "menuhelp");
1590 tooltip
= (gchar
*)g_object_get_data(G_OBJECT(widget
), "tooltip");
1592 gtk_statusbar_push(statusbar
, context_id
, tooltip
);
1599 menu_item_deselect_cb(GtkWidget
*widget
)
1601 GtkStatusbar
*statusbar
= GTK_STATUSBAR(X
->statusbar
);
1604 context_id
= gtk_statusbar_get_context_id(statusbar
, "menuhelp");
1605 gtk_statusbar_pop(statusbar
, context_id
);
1610 set_menubar_tooltip(gchar
*menu_name
)
1615 menu
= GET_WIDGET(menu_name
);
1616 tooltip
= gtk_widget_get_tooltip_text(menu
);
1617 g_object_set_data(G_OBJECT(menu
), "tooltip", tooltip
);
1618 gtk_widget_set_tooltip_text(menu
, NULL
);
1623 update_memory_menus()
1628 for (i
= 0; i
< MAXREGS
; i
++) {
1629 SNPRINTF(mstr
, MAXLINE
, "<span weight=\"bold\">%s_%d:</span> %s",
1630 /* translators: R is the short form of register used inter alia
1632 _("R"), i
, make_number(v
->MPmvals
[i
], v
->base
, TRUE
));
1633 update_popup_label(X
->memory_store_items
[i
], mstr
);
1634 update_popup_label(X
->memory_recall_items
[i
], mstr
);
1635 update_popup_label(X
->memory_exchange_items
[i
], mstr
);
1642 rframe_response_cb(GtkDialog
*dialog
, int response
)
1644 ui_set_registers_visible(FALSE
);
1650 aframe_delete_cb(GtkWidget
*widget
, GdkEvent
*event
, gpointer user_data
)
1652 gtk_widget_hide(widget
);
1660 rframe_delete_cb(GtkWidget
*widget
, GdkEvent
*event
, gpointer user_data
)
1662 gtk_dialog_response(GTK_DIALOG(widget
), GTK_RESPONSE_DELETE_EVENT
);
1670 spframe_delete_cb(GtkWidget
*widget
, GdkEvent
*event
, gpointer user_data
)
1672 gtk_widget_hide(X
->spframe
);
1680 disp_cb(GtkWidget
*widget
)
1682 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget
)))
1683 do_numtype((enum num_type
) g_object_get_data(G_OBJECT(widget
), "numeric_mode"));
1690 char nkey
[MAXLINE
], *nline
;
1691 char vkey
[MAXLINE
], *vline
;
1693 SNPRINTF(nkey
, MAXLINE
, "constant%1dname", n
);
1694 if ((nline
= get_resource(nkey
)) == NULL
) {
1698 SNPRINTF(vkey
, MAXLINE
, "constant%1dvalue", n
);
1699 if ((vline
= get_resource(vkey
)) == NULL
) {
1703 MPstr_to_num(vline
, DEC
, v
->MPcon_vals
[n
]);
1704 STRNCPY(v
->con_names
[n
], nline
, MAXLINE
- 1);
1709 get_display() /* The Copy function key has been pressed. */
1711 gchar
*string
= NULL
;
1712 GtkTextIter start
, end
;
1714 if (gtk_text_buffer_get_selection_bounds(X
->display_buffer
, &start
, &end
) == TRUE
) {
1715 string
= gtk_text_buffer_get_text(X
->display_buffer
, &start
, &end
, FALSE
);
1717 gtk_text_buffer_get_bounds(X
->display_buffer
, &start
, &end
);
1718 string
= gtk_text_buffer_get_text(X
->display_buffer
, &start
, &end
, FALSE
);
1721 if (v
->shelf
!= NULL
) {
1724 v
->shelf
= g_locale_from_utf8(string
, strlen(string
), NULL
, NULL
, NULL
);
1727 gtk_clipboard_set_text(gtk_clipboard_get(X
->clipboard_atom
), v
->shelf
, -1);
1734 char nkey
[MAXLINE
], *nline
;
1735 char vkey
[MAXLINE
], *vline
;
1737 SNPRINTF(nkey
, MAXLINE
, "function%1dname", n
);
1738 if ((nline
= get_resource(nkey
)) == NULL
) {
1742 SNPRINTF(vkey
, MAXLINE
, "function%1dvalue", n
);
1743 if ((vline
= get_resource(vkey
)) == NULL
) {
1747 STRNCPY(v
->fun_vals
[n
], convert(vline
), MAXLINE
- 1);
1748 STRNCPY(v
->fun_names
[n
], nline
, MAXLINE
- 1);
1753 ui_get_localized_numeric_point(void)
1755 const char *decimal_point
;
1757 decimal_point
= localeconv()->decimal_point
;
1759 return(g_locale_to_utf8(decimal_point
, -1, NULL
, NULL
, NULL
));
1764 get_menu_entry(enum menu_type mtype
, int offset
)
1768 return(offset
+ '0');
1772 return((offset
< 10) ? offset
+ '0' : offset
+ 'A' - 10);
1775 FPRINTF(stderr
, "need to handle menu type %d\n", mtype
);
1784 get_proc(GtkClipboard
*clipboard
, const gchar
*buffer
, gpointer data
)
1787 gchar
*dstp
, *end_buffer
, *srcp
, *text
;
1789 if (buffer
== NULL
) {
1793 end_buffer
= (gchar
*) (buffer
+ strlen(buffer
));
1794 text
= malloc(strlen(buffer
)+1);
1796 srcp
= (gchar
*) buffer
;
1798 while (srcp
< end_buffer
) {
1800 /* If the clipboard buffer contains any occurances of the "thousands
1801 * separator", remove them.
1803 if (*srcp
== v
->tsep
[0]) {
1804 if (strstr(srcp
, v
->tsep
) == srcp
) {
1805 srcp
+= strlen(v
->tsep
);
1811 /* If an "A", "B", "C", "D" or "F" character is encountered, it
1812 * will be converted to its lowercase equivalent. If an "E" is
1813 * found, and the next character is a "-" or a "+", then it
1814 * remains as an upper case "E" (it's assumed to be a possible
1815 * exponential number), otherwise its converted to a lower case
1816 * "e". See bugs #455889 and #469245 for more details.
1823 case 'F': *dstp
++ = tolower(*srcp
);
1827 case 'E': if (srcp
< (end_buffer
-1)) {
1828 if (*(srcp
+1) != '-' &&
1830 *dstp
++ = tolower(*srcp
);
1837 default: *dstp
++ = *srcp
++;
1843 switch (v
->syntax
) {
1845 ret
= lr_parse((char *) text
, v
->MPdisp_val
);
1847 show_display(v
->MPdisp_val
);
1849 ui_set_statusbar(_("Clipboard contained malformed calculation"),
1850 "gtk-dialog-error");
1855 exp_append((char *) text
);
1867 ui_set_base(enum base_type base
)
1869 int i
, baseval
= basevals
[(int) base
];
1871 for (i
= 0; i
< 16; i
++) {
1872 gtk_widget_set_sensitive(X
->digit_buttons
[i
], i
< baseval
);
1874 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(X
->base
[base
]), 1);
1879 ui_set_registers_visible(gboolean visible
)
1882 ui_make_registers();
1884 menu
= GET_WIDGET("show_registers_menu");
1885 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu
), visible
);
1887 gtk_widget_realize(X
->rframe
);
1890 if (gdk_window_is_visible(X
->rframe
->window
)) {
1891 gdk_window_raise(X
->rframe
->window
);
1894 ds_position_popup(X
->kframe
, X
->rframe
, DS_POPUP_ABOVE
);
1895 gtk_widget_show(X
->rframe
);
1897 gtk_widget_hide(X
->rframe
);
1900 set_boolean_resource(R_REGS
, visible
);
1906 help_cb(GtkWidget
*widget
)
1915 hyp_cb(GtkWidget
*widget
)
1917 ui_update_trig_mode();
1923 inv_cb(GtkWidget
*widget
)
1925 ui_update_trig_mode();
1930 check_for_localized_numeric_point(int keyval
)
1932 gchar outbuf
[10]; /* Minumum size 6. */
1935 ch
= gdk_keyval_to_unicode(keyval
);
1936 g_return_val_if_fail(g_unichar_validate(ch
), FALSE
);
1938 outbuf
[g_unichar_to_utf8(ch
, outbuf
)] = '\0';
1940 return(strcmp(outbuf
, X
->lnp
) == 0);
1948 GtkTextIter start
, end
;
1950 gtk_text_buffer_get_bounds(X
->display_buffer
, &start
, &end
);
1952 text
= gtk_text_buffer_get_text(X
->display_buffer
,
1964 g_object_get(G_OBJECT(X
->display_buffer
), "cursor-position", &pos
, NULL
);
1971 display_focus_out_cb(GtkWidget
*widget
, GdkEventKey
*event
)
1973 if (v
->syntax
== EXPRS
) {
1983 display_focus_in_cb(GtkWidget
*widget
, GdkEventKey
*event
)
1993 menu_pos_func(GtkMenu
*menu
, gint
*x
, gint
*y
,
1994 gboolean
*push_in
, gpointer user_data
)
1996 GdkPoint
*loc
= (GdkPoint
*) user_data
;
2005 button_cb(GtkWidget
*widget
, GdkEventButton
*event
)
2008 enum menu_type mtype
;
2012 n
= (struct button
*) g_object_get_data(G_OBJECT(widget
), "button");
2013 mtype
= GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget
), "mtype"));
2015 if (mtype
== M_NONE
) {
2018 /* If gcalctool is being driven by gok, the on-screen keyboard
2019 * assistive technology, it's possible that the event returned by
2020 * gtk_get_current_event() is NULL. If this is the case, we need
2021 * to fudge the popping up on the menu associated with this menu
2025 update_constants_menu();
2026 update_functions_menu();
2027 update_memory_menus();
2029 menu
= X
->menus
[mtype
];
2030 if (event
== NULL
) {
2031 gdk_window_get_origin(widget
->window
, &loc
.x
, &loc
.y
);
2032 loc
.x
+= widget
->allocation
.x
;
2033 loc
.y
+= widget
->allocation
.y
;
2034 gtk_menu_popup(GTK_MENU(menu
), NULL
, NULL
, menu_pos_func
,
2035 (gpointer
) &loc
, 0, gtk_get_current_event_time());
2036 } else if (event
->button
== 1) {
2037 gtk_menu_popup(GTK_MENU(menu
), NULL
, NULL
, NULL
, NULL
,
2038 event
->button
, event
->time
);
2046 select_display_entry(int offset
)
2050 gtk_text_buffer_get_iter_at_offset(X
->display_buffer
, &iter
, offset
);
2051 gtk_text_buffer_place_cursor(X
->display_buffer
, &iter
);
2052 gtk_widget_grab_focus(X
->display_item
);
2058 kframe_key_press_cb(GtkWidget
*widget
, GdkEventKey
*event
)
2063 if (check_for_localized_numeric_point(event
->keyval
) == TRUE
) {
2065 event
->keyval
= GDK_KP_Decimal
;
2068 state
= event
->state
& (GDK_CONTROL_MASK
| GDK_MOD1_MASK
);
2070 /* Accuracy shortcuts */
2071 if (state
== GDK_CONTROL_MASK
&& v
->modetype
== SCIENTIFIC
)
2073 switch (event
->keyval
) {
2107 /* Connect home and end keys to move into the display entry */
2108 if (event
->keyval
== GDK_Home
)
2110 select_display_entry(0);
2112 } else if (event
->keyval
== GDK_End
)
2114 select_display_entry(-1);
2118 for (i
= 0; i
< NBUTTONS
; i
++) {
2119 button
= X
->buttons
[i
];
2121 /* Check any parent widgets are visible */
2122 if (!GTK_WIDGET_VISIBLE(gtk_widget_get_parent(button
)) ||
2123 !GTK_WIDGET_VISIBLE(button
) || !GTK_WIDGET_IS_SENSITIVE(button
)) {
2128 while (button_widgets
[i
].accelerator_keys
[j
] != 0) {
2129 if (button_widgets
[i
].accelerator_keys
[j
] == event
->keyval
&&
2130 (button_widgets
[i
].accelerator_mods
[j
] & ~GDK_SHIFT_MASK
) == state
) {
2131 button_cb(button
, NULL
);
2144 mouse_button_cb(GtkWidget
*widget
, GdkEventButton
*event
)
2146 if (event
->button
== 2) {
2147 gtk_clipboard_request_text(gtk_clipboard_get(X
->primary_atom
),
2158 int intval
, screen_height
, screen_width
;
2161 screen_width
= gdk_screen_get_width(gdk_screen_get_default());
2162 screen_height
= gdk_screen_get_height(gdk_screen_get_default());
2164 if (get_int_resource(R_XPOS
, &intval
)) {
2166 if (x
< 0 || x
> screen_width
) {
2171 if (get_int_resource(R_YPOS
, &intval
)) {
2173 if (y
< 0 || y
> screen_height
) {
2178 gtk_window_move(GTK_WINDOW(X
->kframe
), x
, y
);
2182 show_ascii_frame() /* Display ASCII popup. */
2184 if (!GTK_WIDGET_VISIBLE(X
->aframe
)) {
2185 ds_position_popup(X
->kframe
, X
->aframe
, DS_POPUP_LEFT
);
2187 gtk_window_set_focus(GTK_WINDOW(X
->kframe
), GTK_WIDGET(X
->aframe_ch
));
2188 gtk_widget_show(X
->aframe
);
2193 show_precision_frame() /* Display Set Precision popup. */
2195 if (!GTK_WIDGET_VISIBLE(X
->spframe
)) {
2196 ds_position_popup(X
->kframe
, X
->spframe
, DS_POPUP_LEFT
);
2198 gtk_window_set_focus(GTK_WINDOW(X
->spframe
), GTK_WIDGET(X
->spframe_val
));
2199 gtk_widget_show(X
->spframe
);
2203 /* Handle menu bar menu selection. */
2207 edit_cb(GtkWidget
*widget
)
2216 can_copy
= gtk_text_buffer_get_has_selection(X
->display_buffer
);
2217 can_paste
= gtk_clipboard_wait_is_text_available(
2218 gtk_clipboard_get(X
->clipboard_atom
));
2220 gtk_widget_set_sensitive(GTK_WIDGET(X
->copy
), can_copy
);
2221 gtk_widget_set_sensitive(GTK_WIDGET(X
->paste
), can_paste
);
2226 handle_selection() /* Handle the GET function key being pressed. */
2228 gtk_clipboard_request_text(gtk_clipboard_get(X
->clipboard_atom
),
2235 popup_paste_cb(GtkMenuItem
*menuitem
)
2243 copy_cb(GtkWidget
*widget
)
2253 paste_cb(GtkWidget
*widget
)
2263 undo_cb(GtkWidget
*widget
)
2274 redo_cb(GtkWidget
*widget
)
2285 for_each_menu(GtkWidget
*widget
, gpointer data
)
2287 /* Find the "Paste" entry and activate it (see bug #317786). */
2288 if (strcmp(G_OBJECT_TYPE_NAME(widget
), "GtkImageMenuItem") == 0) {
2289 GtkWidget
*label
= gtk_bin_get_child(GTK_BIN(widget
));
2291 if (strcmp(gtk_label_get_text(GTK_LABEL(label
)), _("Paste")) == 0) {
2292 if (gtk_clipboard_wait_is_text_available(
2293 gtk_clipboard_get(X
->clipboard_atom
))) {
2294 gtk_widget_set_sensitive(GTK_WIDGET(widget
), TRUE
);
2295 g_signal_connect(GTK_OBJECT(widget
), "activate",
2296 G_CALLBACK(popup_paste_cb
), NULL
);
2305 buffer_populate_popup_cb(GtkTextView
*textview
, GtkMenu
*menu
)
2307 gtk_container_foreach(GTK_CONTAINER(menu
), for_each_menu
, NULL
);
2313 insert_ascii_cb(GtkWidget
*widget
)
2322 shift_left_cb(GtkWidget
*widget
)
2324 int count
= GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget
),
2328 do_button(&buttons
[KEY_SHIFT
], count
);
2334 shift_right_cb(GtkWidget
*widget
)
2336 int count
= GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget
),
2340 do_button(&buttons
[KEY_SHIFT
], -count
);
2346 show_bitcalculating_cb(GtkWidget
*widget
)
2349 v
->bitcalculating_mode
= v
->bitcalculating_mode
^ 1;
2350 ui_set_mode(v
->modetype
);
2351 set_resource(R_BITCALC
, Rcstr
[v
->bitcalculating_mode
]);
2358 show_registers_cb(GtkWidget
*widget
)
2362 visible
= gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget
));
2365 set_boolean_resource(R_REGS
, visible
);
2366 ui_set_registers_visible(visible
);
2373 arithmetic_mode_cb(GtkWidget
*widget
)
2375 struct exprm_state
*e
;
2381 /* TODO: Always do clear things when mode is changed. */
2383 v
->syntax
= v
->syntax
^ 1;
2384 switch (v
->syntax
) {
2387 MPstr_to_num("0", DEC
, v
->MPdisp_val
);
2388 show_display(v
->MPdisp_val
);
2389 ui_set_statusbar(_("Activated no operator precedence mode"), "");
2390 clear_undo_history();
2395 MPstr_to_num("0", DEC
, e
->ans
);
2397 show_display(e
->ans
);
2399 _("Activated expression mode with operator precedence"), "");
2405 set_resource(R_SYNTAX
, Rsstr
[v
->syntax
]);
2406 ui_set_mode(v
->modetype
);
2407 // FIXME: We can't allow the display to be editable. See bug #326938
2408 gtk_text_view_set_editable(GTK_TEXT_VIEW(X
->display_item
),
2409 (v
->syntax
== EXPRS
));
2415 mode_radio_cb(GtkWidget
*menu
)
2417 struct exprm_state
*e
;
2418 int immediate
= 0; /* Set if we can change mode without warning user. */
2419 int complete
= 0; /* Set if the user has completed a calculation. */
2421 if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menu
))) {
2429 X
->mode
= GPOINTER_TO_INT(g_object_get_data(G_OBJECT(menu
), "calcmode"));
2431 /* If the user has completed a calculation and we are going to a
2432 * new mode that is "compatible" with this one, then just change
2433 * modes. Otherwise display a dialog warning the user that the
2434 * current calculation will be cleared.
2436 * Incompatible modes are:
2438 * Scientific -> Basic
2439 * Scientific -> Advanced
2440 * Scientific -> Financial
2442 * (unless we are in Scientific mode with Decimal numeric base and Fixed).
2445 switch (v
->syntax
) {
2447 if (v
->old_cal_value
< 0 ||
2448 v
->old_cal_value
== KEY_CALCULATE
) {
2449 complete
= 1; /* Calculation is complete. */
2455 if (!e
->expression
|| !strcmp(e
->expression
, "Ans")) {
2456 complete
= 1; /* Calculation is complete. */
2465 if ((v
->modetype
!= SCIENTIFIC
) ||
2466 (v
->dtype
== FIX
&& v
->base
== DEC
)) {
2472 v
->modetype
= X
->mode
;
2473 reset_mode_display();
2475 } else if (request_change_mode()) {
2476 change_mode(X
->mode
);
2483 accuracy_radio_cb(GtkWidget
*widget
)
2487 count
= GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget
), "accuracy"));
2490 gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget
))) {
2498 accuracy_other_cb(GtkWidget
*widget
)
2501 show_precision_frame();
2508 show_trailing_zeroes_cb(GtkWidget
*widget
)
2510 v
->show_zeroes
= gtk_check_menu_item_get_active(
2511 GTK_CHECK_MENU_ITEM(widget
));
2513 syntaxdep_show_display();
2514 set_boolean_resource(R_ZEROES
, v
->show_zeroes
);
2515 ui_make_registers();
2517 set_show_zeroes_toggle(v
->show_zeroes
);
2523 quit_cb(GtkWidget
*widget
)
2525 save_win_position();
2532 spframe_cancel_cb(GtkButton
*button
)
2534 gtk_widget_hide(X
->spframe
);
2540 spframe_key_cb(GtkWidget
*widget
, GdkEventKey
*event
)
2542 if (event
->keyval
== GDK_minus
) {
2543 ui_set_statusbar(_("Accuracy value out of range"),
2544 "gtk-dialog-error");
2546 } else if (event
->keyval
== GDK_Escape
) {
2547 gtk_widget_hide(X
->spframe
);
2556 spframe_ok_cb(GtkButton
*button
)
2558 int val
= gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(X
->spframe_val
));
2562 set_int_resource(R_ACCURACY
, v
->accuracy
);
2564 ui_set_accuracy(v
->accuracy
);
2566 ui_make_registers();
2569 gtk_widget_hide(X
->spframe
);
2575 trig_cb(GtkWidget
*widget
)
2577 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget
)))
2578 do_trigtype((enum trig_type
) g_object_get_data(G_OBJECT(widget
),
2586 struct exprm_state
*e
;
2589 ui_set_base(v
->base
);
2590 ui_set_trigonometric_mode(v
->ttype
);
2591 ui_set_numeric_mode(v
->dtype
);
2593 gtk_widget_show(X
->kframe
);
2595 switch (v
->syntax
) {
2600 /* Init expression mode.
2601 * This must be executed after do_base is called at init.
2602 * FIXME: The init code here is duplicated elsewhere.
2605 MPstr_to_num("0", DEC
, e
->ans
);
2607 show_display(e
->ans
);
2620 show_thousands_separator_cb(GtkWidget
*widget
)
2626 v
->show_tsep
= !v
->show_tsep
;
2628 syntaxdep_show_display();
2629 set_boolean_resource(R_TSEP
, v
->show_tsep
== TRUE
);
2630 ui_make_registers();
2636 edit_constants_cb(GtkMenuItem
*item
)
2638 gtk_widget_show(X
->con_dialog
);
2644 edit_functions_cb(GtkMenuItem
*item
)
2646 gtk_widget_show(X
->fun_dialog
);
2656 PangoFontDescription
*font_desc
;
2657 GtkSizeGroup
*size_group
;
2658 GtkAccelGroup
*accel_group
;
2659 GtkWidget
*treeview
;
2661 X
->ui
= glade_xml_new(UI_FILE
, NULL
, NULL
);
2662 if (X
->ui
== NULL
) {
2665 dialog
= gtk_message_dialog_new(NULL
, 0,
2668 N_("Error loading user interface"));
2669 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog
),
2670 N_("The user interace file %s is missing or unable to be loaded. Please check your installation."), UI_FILE
);
2671 gtk_dialog_add_buttons(GTK_DIALOG(dialog
), GTK_STOCK_QUIT
, GTK_RESPONSE_ACCEPT
, NULL
);
2673 gtk_dialog_run(GTK_DIALOG(dialog
));
2677 /* When connecting up signals, would ideally use autoconnect but not
2678 * sure how to get the build process working.
2679 * See http://library.gnome.org/devel/libglade/unstable and
2680 * http://www.jamesh.id.au/software/libglade/
2681 * for some information on how to get this to work
2682 * glade_xml_signal_autoconnect(X->ui);
2684 CONNECT_SIGNAL(kframe_key_press_cb
);
2685 CONNECT_SIGNAL(button_cb
);
2686 CONNECT_SIGNAL(menu_item_select_cb
);
2687 CONNECT_SIGNAL(menu_item_deselect_cb
);
2688 CONNECT_SIGNAL(mode_radio_cb
);
2689 CONNECT_SIGNAL(inv_cb
);
2690 CONNECT_SIGNAL(hyp_cb
);
2691 CONNECT_SIGNAL(trig_cb
);
2692 CONNECT_SIGNAL(base_cb
);
2693 CONNECT_SIGNAL(disp_cb
);
2694 CONNECT_SIGNAL(quit_cb
);
2695 CONNECT_SIGNAL(edit_cb
);
2696 CONNECT_SIGNAL(copy_cb
);
2697 CONNECT_SIGNAL(paste_cb
);
2698 CONNECT_SIGNAL(insert_ascii_cb
);
2699 CONNECT_SIGNAL(undo_cb
);
2700 CONNECT_SIGNAL(redo_cb
);
2701 CONNECT_SIGNAL(help_cb
);
2702 CONNECT_SIGNAL(about_cb
);
2703 CONNECT_SIGNAL(show_trailing_zeroes_cb
);
2704 CONNECT_SIGNAL(show_thousands_separator_cb
);
2705 CONNECT_SIGNAL(show_bitcalculating_cb
);
2706 CONNECT_SIGNAL(show_registers_cb
);
2707 CONNECT_SIGNAL(accuracy_radio_cb
);
2708 CONNECT_SIGNAL(accuracy_other_cb
);
2709 CONNECT_SIGNAL(arithmetic_mode_cb
);
2710 CONNECT_SIGNAL(mouse_button_cb
);
2711 CONNECT_SIGNAL(display_focus_in_cb
);
2712 CONNECT_SIGNAL(display_focus_out_cb
);
2713 /* Detect when populating the right-click menu to enable pasting */
2714 CONNECT_SIGNAL(buffer_populate_popup_cb
);
2715 CONNECT_SIGNAL(shift_left_cb
);
2716 CONNECT_SIGNAL(shift_right_cb
);
2717 CONNECT_SIGNAL(bit_toggle_cb
);
2718 CONNECT_SIGNAL(aframe_delete_cb
);
2719 CONNECT_SIGNAL(aframe_ok_cb
);
2720 CONNECT_SIGNAL(aframe_cancel_cb
);
2721 CONNECT_SIGNAL(aframe_key_cb
);
2722 CONNECT_SIGNAL(spframe_delete_cb
);
2723 CONNECT_SIGNAL(spframe_ok_cb
);
2724 CONNECT_SIGNAL(spframe_cancel_cb
);
2725 CONNECT_SIGNAL(spframe_key_cb
);
2726 CONNECT_SIGNAL(rframe_delete_cb
);
2727 CONNECT_SIGNAL(rframe_response_cb
);
2728 CONNECT_SIGNAL(edit_constants_cb
);
2729 CONNECT_SIGNAL(edit_functions_cb
);
2730 CONNECT_SIGNAL(edit_constants_response_cb
);
2731 CONNECT_SIGNAL(edit_functions_response_cb
);
2733 X
->kframe
= GET_WIDGET("calc_window");
2734 X
->aframe
= GET_WIDGET("ascii_window");
2735 X
->aframe_ch
= GET_WIDGET("ascii_entry");
2736 X
->spframe
= GET_WIDGET("precision_dialog");
2737 X
->spframe_val
= GET_WIDGET("spframe_spin");
2738 X
->rframe
= GET_WIDGET("register_dialog");
2739 X
->con_dialog
= GET_WIDGET("edit_constants_dialog");
2740 X
->fun_dialog
= GET_WIDGET("edit_functions_dialog");
2741 X
->menubar
= GET_WIDGET("menubar");
2742 X
->scrolledwindow
= GET_WIDGET("display_scroll"),
2743 X
->display_item
= GET_WIDGET("displayitem"),
2744 X
->bas_panel
= GET_WIDGET("basic_panel");
2745 X
->sci_panel
= GET_WIDGET("scientific_panel");
2746 X
->adv_panel
= GET_WIDGET("advanced_panel");
2747 X
->fin_panel
= GET_WIDGET("financial_panel");
2748 X
->clear_buttons
[0] = GET_WIDGET("calc_clear_simple_button");
2749 X
->clear_buttons
[1] = GET_WIDGET("calc_clear_advanced_button");
2750 X
->mode_panel
= GET_WIDGET("mode_panel");
2751 X
->trig
[0] = GET_WIDGET("degrees_radio");
2752 X
->trig
[1] = GET_WIDGET("gradians_radio");
2753 X
->trig
[2] = GET_WIDGET("radians_radio");
2754 X
->base
[0] = GET_WIDGET("binary_radio");
2755 X
->base
[1] = GET_WIDGET("octal_radio");
2756 X
->base
[2] = GET_WIDGET("decimal_radio");
2757 X
->base
[3] = GET_WIDGET("hexadecimal_radio");
2758 X
->disp
[0] = GET_WIDGET("engineering_radio");
2759 X
->disp
[1] = GET_WIDGET("fixed_point_radio");
2760 X
->disp
[2] = GET_WIDGET("scientific_radio");
2761 X
->inv
= GET_WIDGET("inverse_check");
2762 X
->hyp
= GET_WIDGET("hyperbolic_check");
2763 X
->bit_panel
= GET_WIDGET("bit_panel");
2764 X
->statusbar
= GET_WIDGET("statusbar");
2765 X
->undo
= GET_WIDGET("undo_menu");
2766 X
->redo
= GET_WIDGET("redo_menu");
2767 X
->copy
= GET_WIDGET("copy_menu");
2768 X
->paste
= GET_WIDGET("paste_menu");
2769 for (i
= 0; i
< 16; i
++) {
2770 SNPRINTF(name
, MAXLINE
, "calc_%x_button", i
);
2771 X
->digit_buttons
[i
] = GET_WIDGET(name
);
2773 for (i
= 0; i
< MAXREGS
; i
++) {
2774 SNPRINTF(name
, MAXLINE
, "register_entry_%d", i
);
2775 X
->regs
[i
] = GET_WIDGET(name
);
2778 /* Load buttons and set them all to be the same size */
2779 size_group
= gtk_size_group_new(GTK_SIZE_GROUP_BOTH
);
2780 for (i
= 0; i
< NBUTTONS
; i
++) {
2781 SNPRINTF(name
, MAXLINE
, "calc_%s_button",
2782 button_widgets
[i
].widget_name
);
2783 X
->buttons
[i
] = GET_WIDGET(name
);
2784 assert(X
->buttons
[i
] != NULL
);
2786 gtk_size_group_add_widget(size_group
, X
->buttons
[i
]);
2788 g_object_set_data(G_OBJECT(X
->buttons
[i
]), "button",
2789 &buttons
[button_widgets
[i
].key
]);
2790 g_object_set_data(G_OBJECT(X
->buttons
[i
]), "mtype",
2791 GINT_TO_POINTER(button_widgets
[i
].mtype
));
2794 /* Load bit panel */
2795 for (i
= 0; i
< MAXBITS
; i
++)
2797 SNPRINTF(name
, MAXLINE
, "bit_label_%d", i
);
2798 X
->bits
[i
] = GET_WIDGET(name
);
2799 SNPRINTF(name
, MAXLINE
, "bit_eventbox_%d", i
);
2800 g_object_set_data(G_OBJECT(GET_WIDGET(name
)),
2801 "bit_index", GINT_TO_POINTER(i
));
2804 /* Make menu tooltips displayed in the status bar */
2805 set_menubar_tooltip("quit_menu");
2806 set_menubar_tooltip("copy_menu");
2807 set_menubar_tooltip("paste_menu");
2808 set_menubar_tooltip("insert_ascii_menu");
2809 set_menubar_tooltip("undo_menu");
2810 set_menubar_tooltip("redo_menu");
2811 set_menubar_tooltip("view_basic_menu");
2812 set_menubar_tooltip("view_advanced_menu");
2813 set_menubar_tooltip("view_financial_menu");
2814 set_menubar_tooltip("view_scientific_menu");
2815 set_menubar_tooltip("show_trailing_zeroes_menu");
2816 set_menubar_tooltip("show_thousands_separator_menu");
2817 set_menubar_tooltip("show_bitcalculating_menu");
2818 set_menubar_tooltip("show_registers_menu");
2819 set_menubar_tooltip("ltr_precedence_menu");
2820 set_menubar_tooltip("arithmetic_precedence_menu");
2821 set_menubar_tooltip("help_menu");
2822 set_menubar_tooltip("about_menu");
2825 widget
= GET_WIDGET("kvbox");
2826 gtk_widget_set_direction(widget
, GTK_TEXT_DIR_LTR
);
2827 gtk_widget_set_direction(X
->fin_panel
, GTK_TEXT_DIR_LTR
);
2829 /* Make dialogs transient of the main window */
2830 gtk_window_set_transient_for(GTK_WINDOW(X
->aframe
), GTK_WINDOW(X
->kframe
));
2831 gtk_window_set_transient_for(GTK_WINDOW(X
->spframe
), GTK_WINDOW(X
->kframe
));
2832 gtk_window_set_transient_for(GTK_WINDOW(X
->rframe
), GTK_WINDOW(X
->kframe
));
2833 gtk_window_set_transient_for(GTK_WINDOW(X
->con_dialog
),
2834 GTK_WINDOW(X
->kframe
));
2836 gtk_spin_button_set_value(GTK_SPIN_BUTTON(X
->spframe_val
),
2837 (double) v
->accuracy
); // FIXME
2838 gtk_entry_set_max_length(GTK_ENTRY(X
->spframe_val
), 2);
2840 gtk_dialog_set_default_response(GTK_DIALOG(X
->con_dialog
),
2841 GTK_RESPONSE_ACCEPT
);
2843 /* Make constant tree model */
2844 X
->constants_model
= create_cf_model(M_CON
, X
->con_dialog
);
2845 treeview
= GET_WIDGET("edit_constants_treeview");
2846 gtk_tree_view_set_model(GTK_TREE_VIEW(treeview
), X
->constants_model
);
2847 gtk_tree_selection_set_mode(
2848 gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview
)),
2849 GTK_SELECTION_SINGLE
);
2850 add_cf_column(GTK_TREE_VIEW(treeview
), _("No."),
2851 COLUMN_NUMBER
, FALSE
);
2852 add_cf_column(GTK_TREE_VIEW(treeview
), _("Value"),
2853 COLUMN_VALUE
, TRUE
);
2854 add_cf_column(GTK_TREE_VIEW(treeview
), _("Description"),
2855 COLUMN_DESCRIPTION
, TRUE
);
2857 /* Make function tree model */
2858 X
->functions_model
= create_cf_model(M_FUN
, X
->fun_dialog
);
2859 treeview
= GET_WIDGET("edit_functions_treeview");
2860 gtk_dialog_set_default_response(GTK_DIALOG(X
->fun_dialog
),
2861 GTK_RESPONSE_ACCEPT
);
2862 gtk_window_set_transient_for(GTK_WINDOW(X
->fun_dialog
),
2863 GTK_WINDOW(X
->kframe
));
2864 gtk_tree_view_set_model(GTK_TREE_VIEW(treeview
), X
->functions_model
);
2865 gtk_tree_selection_set_mode(
2866 gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview
)),
2867 GTK_SELECTION_SINGLE
);
2868 add_cf_column(GTK_TREE_VIEW(treeview
), _("No."),
2869 COLUMN_NUMBER
, FALSE
);
2870 add_cf_column(GTK_TREE_VIEW(treeview
), _("Value"),
2871 COLUMN_VALUE
, TRUE
);
2872 add_cf_column(GTK_TREE_VIEW(treeview
), _("Description"),
2873 COLUMN_DESCRIPTION
, TRUE
);
2876 X
->display_buffer
= gtk_text_view_get_buffer(GTK_TEXT_VIEW(X
->display_item
));
2877 gtk_widget_ensure_style(X
->display_item
);
2878 font_desc
= pango_font_description_copy(X
->display_item
->style
->font_desc
);
2879 pango_font_description_set_size(font_desc
, 16 * PANGO_SCALE
);
2880 gtk_widget_modify_font(X
->display_item
, font_desc
);
2881 pango_font_description_free(font_desc
);
2882 gtk_widget_set_name(X
->display_item
, "displayitem");
2883 // FIXME: We can't allow the display to be editable. See bug #326938
2884 gtk_text_view_set_editable(GTK_TEXT_VIEW(X
->display_item
),
2885 (v
->syntax
== EXPRS
));
2886 atk_object_set_role(gtk_widget_get_accessible(X
->display_item
),
2889 gtk_widget_realize(X
->kframe
);
2892 for (i
= 0; i
< 3; i
++)
2893 g_object_set_data(G_OBJECT(X
->trig
[i
]),
2894 "trig_mode", GINT_TO_POINTER(i
));
2895 for (i
= 0; i
< 4; i
++)
2896 g_object_set_data(G_OBJECT(X
->base
[i
]),
2897 "base_mode", GINT_TO_POINTER(i
));
2898 for (i
= 0; i
< 3; i
++)
2899 g_object_set_data(G_OBJECT(X
->disp
[i
]),
2900 "numeric_mode", GINT_TO_POINTER(i
));
2902 /* Put status image into statusbar (glade doesn't support child widgets
2904 X
->status_image
= gtk_image_new_from_stock("", GTK_ICON_SIZE_BUTTON
);
2905 gtk_widget_show(X
->status_image
);
2906 gtk_box_pack_start(GTK_BOX(X
->statusbar
), X
->status_image
, FALSE
, TRUE
, 0);
2908 /* Set modes for menu items */
2909 for (i
= 1; i
< 16; i
++) {
2910 SNPRINTF(name
, MAXLINE
, "shift_left%d_menu", i
);
2911 g_object_set_data(G_OBJECT(GET_WIDGET(name
)),
2912 "shiftcount", GINT_TO_POINTER(i
));
2913 SNPRINTF(name
, MAXLINE
, "shift_right%d_menu", i
);
2914 g_object_set_data(G_OBJECT(GET_WIDGET(name
)),
2915 "shiftcount", GINT_TO_POINTER(i
));
2917 g_object_set_data(G_OBJECT(GET_WIDGET("view_basic_menu")),
2918 "calcmode", GINT_TO_POINTER(BASIC
));
2919 g_object_set_data(G_OBJECT(GET_WIDGET("view_advanced_menu")),
2920 "calcmode", GINT_TO_POINTER(ADVANCED
));
2921 g_object_set_data(G_OBJECT(GET_WIDGET("view_financial_menu")),
2922 "calcmode", GINT_TO_POINTER(FINANCIAL
));
2923 g_object_set_data(G_OBJECT(GET_WIDGET("view_scientific_menu")),
2924 "calcmode", GINT_TO_POINTER(SCIENTIFIC
));
2926 /* Make shortcuts for accuracy menus */
2927 accel_group
= gtk_accel_group_new();
2928 gtk_window_add_accel_group(GTK_WINDOW(X
->kframe
), accel_group
);
2929 for (i
= 0; i
< 10; i
++) {
2930 SNPRINTF(name
, MAXLINE
, "acc_item%d", i
);
2931 widget
= GET_WIDGET(name
);
2932 g_object_set_data(G_OBJECT(widget
), "accuracy", GINT_TO_POINTER(i
));
2938 create_menu_item_with_markup(char *label
, int menu_no
, int index
)
2940 GtkWidget
*accel_label
;
2941 GtkWidget
*menu_item
;
2943 accel_label
= gtk_label_new(NULL
);
2944 gtk_label_set_markup_with_mnemonic(GTK_LABEL(accel_label
), label
);
2945 gtk_misc_set_alignment(GTK_MISC(accel_label
), 0.0, 0.5);
2946 menu_item
= gtk_menu_item_new();
2947 gtk_container_add(GTK_CONTAINER(menu_item
), accel_label
);
2948 gtk_widget_show(accel_label
);
2949 gtk_widget_show(menu_item
);
2951 g_object_set_data(G_OBJECT(menu_item
), "button", X
->mrec
[menu_no
]);
2952 gtk_menu_shell_append(GTK_MENU_SHELL(X
->menus
[menu_no
]), menu_item
);
2954 g_signal_connect(G_OBJECT(menu_item
), "activate",
2955 G_CALLBACK(menu_proc_cb
), GINT_TO_POINTER(index
));
2962 read_cfdefs() /* Read constant/function definitions. */
2966 for (n
= 0; n
< MAXCONFUN
; n
++) {
2968 STRCPY(v
->fun_vals
[n
], ""); /* Initially empty function strings. */
2975 ui_init(int *argc
, char ***argv
)
2977 X
= (XVars
) LINT_CAST(calloc(1, sizeof(struct Xobject
)));
2979 gtk_init(argc
, argv
);
2981 X
->lnp
= ui_get_localized_numeric_point();
2983 gtk_rc_get_default_files();
2985 v
->home
= (char *) g_get_home_dir();
2986 gtk_rc_parse(g_build_path(v
->home
, RCNAME
, NULL
));
2988 gtk_window_set_default_icon_name("gnome-calculator");
2999 X
->clipboard_atom
= gdk_atom_intern("CLIPBOARD", FALSE
);
3000 X
->primary_atom
= gdk_atom_intern("PRIMARY", FALSE
);
3001 create_kframe(); /* Create main gcalctool window. */
3003 X
->menus
[M_ACC
] = GET_WIDGET("accuracy_popup");
3004 X
->mrec
[M_ACC
] = &buttons
[KEY_SET_ACCURACY
];
3005 X
->menus
[M_LSHF
] = GET_WIDGET("left_shift_popup");
3006 X
->mrec
[M_LSHF
] = &buttons
[KEY_SHIFT
];
3007 X
->menus
[M_RSHF
] = GET_WIDGET("right_shift_popup");
3008 X
->mrec
[M_RSHF
] = &buttons
[KEY_SHIFT
];
3010 X
->menus
[M_CON
] = GET_WIDGET("constants_popup");
3011 X
->mrec
[M_CON
] = &buttons
[KEY_CONSTANT
];
3012 X
->menus
[M_FUN
] = GET_WIDGET("functions_popup");
3013 X
->mrec
[M_FUN
] = &buttons
[KEY_FUNCTION
];
3014 for (i
= 0; i
< MAXCONFUN
; i
++) {
3015 X
->constant_menu_items
[i
] = create_menu_item_with_markup("", M_CON
, i
);
3016 X
->function_menu_items
[i
] = create_menu_item_with_markup("", M_FUN
, i
);
3019 X
->menus
[M_STO
] = GET_WIDGET("memory_store_popup");
3020 X
->mrec
[M_STO
] = &buttons
[KEY_STORE
];
3021 X
->menus
[M_RCL
] = GET_WIDGET("memory_recall_popup");
3022 X
->mrec
[M_RCL
] = &buttons
[KEY_RECALL
];
3023 X
->menus
[M_EXCH
] = GET_WIDGET("memory_exchange_popup");
3024 X
->mrec
[M_EXCH
] = &buttons
[KEY_EXCHANGE
];
3025 for (i
= 0; i
< MAXREGS
; i
++) {
3026 // FIXME: These labels should be replaced with GtkTreeModel labels
3027 X
->memory_store_items
[i
] = create_menu_item_with_markup("", M_STO
, i
);
3028 X
->memory_recall_items
[i
] = create_menu_item_with_markup("", M_RCL
, i
);
3029 X
->memory_exchange_items
[i
] = create_menu_item_with_markup("", M_EXCH
, i
);
3032 // This matches existing behaviour we can't do in Glade. But is it needed?
3033 gtk_container_set_border_width(GTK_CONTAINER(X
->menus
[M_ACC
]), 1);
3034 gtk_container_set_border_width(GTK_CONTAINER(X
->menus
[M_LSHF
]), 1);
3035 gtk_container_set_border_width(GTK_CONTAINER(X
->menus
[M_RSHF
]), 1);
3036 gtk_container_set_border_width(GTK_CONTAINER(X
->menus
[M_CON
]), 1);
3037 gtk_container_set_border_width(GTK_CONTAINER(X
->menus
[M_FUN
]), 1);
3038 gtk_container_set_border_width(GTK_CONTAINER(X
->menus
[M_STO
]), 1);
3039 gtk_container_set_border_width(GTK_CONTAINER(X
->menus
[M_RCL
]), 1);
3040 gtk_container_set_border_width(GTK_CONTAINER(X
->menus
[M_EXCH
]), 1);
3042 set_show_tsep_toggle(v
->show_tsep
);
3043 set_show_zeroes_toggle(v
->show_zeroes
);
3044 set_show_bitcalculating_toggle(v
->bitcalculating_mode
);
3046 /* Use loaded Arithmetic Precedence mode setting. */
3047 if (v
->syntax
== EXPRS
) {
3048 widget
= GET_WIDGET("arithmetic_precedence_menu");
3049 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget
), TRUE
);
3051 widget
= GET_WIDGET("ltr_precedence_menu");
3052 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget
), TRUE
);
3055 ui_set_display("0.00", FALSE
);
3056 ui_set_mode(v
->modetype
);
3057 ui_set_numeric_mode(FIX
);
3058 ui_set_base(v
->base
);
3059 ui_set_accuracy(v
->accuracy
);
3060 ui_set_undo_enabled(FALSE
, FALSE
);
3061 ui_update_trig_mode();
3063 /* Show the memory register window? */
3064 ui_make_registers();
3065 if (get_boolean_resource(R_REGS
, &boolval
))
3066 ui_set_registers_visible(boolval
);
3068 /* Focus on the clear button */
3069 if (v
->modetype
== BASIC
) {
3070 gtk_window_set_focus(GTK_WINDOW(X
->kframe
),
3071 GTK_WIDGET(X
->clear_buttons
[0]));
3073 gtk_window_set_focus(GTK_WINDOW(X
->kframe
),
3074 GTK_WIDGET(X
->clear_buttons
[1]));