/*
* ui.c - general user interface code.
* part of galculator
* (c) 2002-2007 Simon Floery (chimaira@users.sf.net)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <locale.h>
#include "galculator.h"
#include "ui.h"
#include "display.h"
#include "math_functions.h"
#include "config_file.h"
#include "general_functions.h"
#include "callbacks.h"
#include <gtk/gtk.h>
#include <glade/glade.h>
GladeXML *main_window_xml, *dispctrl_xml, *button_box_xml, *prefs_xml,
*about_dialog_xml, *view_xml;
char dec_point[2];
GtkListStore *prefs_constant_store, *prefs_user_function_store;
static void set_disp_ctrl_object_data ();
static void set_all_buttons_property (GFunc func, gpointer data);
static void set_all_dispctrl_buttons_property (GFunc func, gpointer data);
static void set_all_normal_buttons_property (GFunc func, gpointer data);
static void set_table_child_callback (gpointer data, gpointer user_data);
/* active_buttons. bit mask, in which modes the corresponding button is active.
* assume TRUE for all other bases/modes!
*/
s_active_buttons active_buttons[] = {\
{"button_2", ~(AB_BIN)}, \
{"button_3", ~(AB_BIN)}, \
{"button_4", ~(AB_BIN)}, \
{"button_5", ~(AB_BIN)}, \
{"button_6", ~(AB_BIN)}, \
{"button_7", ~(AB_BIN)}, \
{"button_8", ~(AB_BIN | AB_OCT)}, \
{"button_9", ~(AB_BIN | AB_OCT)}, \
{"button_a", ~(AB_DEC | AB_BIN | AB_OCT)}, \
{"button_b", ~(AB_DEC | AB_BIN | AB_OCT)}, \
{"button_c", ~(AB_DEC | AB_BIN | AB_OCT)}, \
{"button_d", ~(AB_DEC | AB_BIN | AB_OCT)}, \
{"button_e", ~(AB_DEC | AB_BIN | AB_OCT)}, \
{"button_f", ~(AB_DEC | AB_BIN | AB_OCT)}, \
{"button_ee", AB_DEC}, \
{"button_sin", AB_DEC}, \
{"button_cos", AB_DEC}, \
{"button_tan", AB_DEC}, \
{"button_point", ~(AB_BIN | AB_OCT | AB_HEX)}, \
{"button_sign", ~(AB_BIN | AB_OCT | AB_HEX)}, \
{NULL}\
};
/* glade_file_open. opens a new .glade file, checks if this open was successful
* and returns *GladeXML.
*/
static GladeXML *glade_file_open (char *filename,
char *root_widget,
gboolean fatal)
{
GladeXML *xml;
xml = glade_xml_new (filename, root_widget, NULL);
if (xml == NULL) {
fprintf (stderr, _("[%s] Couldn't load %s. This file is necessary \
to build galculator's user interface. Make sure you did a make install and the file \
is accessible!\n"), PACKAGE, filename);
if (fatal == TRUE) exit(EXIT_FAILURE);
}
return xml;
}
/* apply_object_data. with gtk (better gobject) we can store additional
* information for a widget (resp gobject). This information could be the
* operation sign for src/calc_basic.c. This function sets such object data.
* Is called from set_scientific_object_data resp set_basic_object_data.
*/
static void apply_object_data (s_operation_map operation_map[],
s_gfunc_map gfunc_map[],
s_function_map function_map[])
{
int counter;
gpointer *func;
GObject *object;
counter = 0;
while (operation_map[counter].button_name != NULL) {
object = G_OBJECT (glade_xml_get_widget (button_box_xml,
operation_map[counter].button_name));
g_object_set_data (object, "operation",
GINT_TO_POINTER(operation_map[counter].operation));
g_object_set_data (object, "display_string",
operation_map[counter].display_string);
counter++;
}
counter = 0;
while (gfunc_map[counter].button_name != NULL) {
object = G_OBJECT (glade_xml_get_widget (button_box_xml,
gfunc_map[counter].button_name));
g_object_set_data (object, "display_string", gfunc_map[counter].display_string);
g_object_set_data (object, "func", gfunc_map[counter].func);
counter++;
};
counter = 0;
while (function_map[counter].button_name != NULL) {
func = (void *) malloc (sizeof (function_map[counter].func));
memcpy (func, function_map[counter].func, sizeof (function_map[counter].func));
object = G_OBJECT (glade_xml_get_widget (button_box_xml,
function_map[counter].button_name));
g_object_set_data (object, "display_names", function_map[counter].display_names);
g_object_set_data (object, "func", func);
counter++;
};
}
/* set_scientific_object_data. Here, we set the information that is saved in
* apply_object_data. For scientific mode.
*/
static void set_scientific_object_data ()
{
s_operation_map operation_map[] = {
{"button_pow", "^", '^'},
{"button_lsh", "<<", '<'},
{"button_mod", "MOD", 'm'},
{"button_and", "AND", '&'},
{"button_or", "OR", '|'},
{"button_xor", "XOR", 'x'},
{"button_enter", "=", '='},
{"button_plus", "+", '+'},
{"button_minus", "-", '-'},
{"button_mult", "*", '*'},
{"button_div", "/", '/'},
{"button_percent", "%", '%'},
{"button_f1", "(", '('}, /* paropen or swapxy */
{"button_f2", ")", ')'}, /* parclose or rolldn */
{NULL}
};
s_gfunc_map gfunc_map[] = {
{"button_sign", "-", display_result_toggle_sign},
{"button_ee", "e", display_append_e},
{"button_f1", "(", gfunc_f1}, /* paropen or swapxy */
{"button_f2", ")", gfunc_f2}, /* parclose or rolldn */
{NULL}
};
/* declare this one static as we need the display_names throughout */
static s_function_map function_map[] = {
{"button_sin", {"sin(", "asin(", "sinh(", "asinh("}, {sin_wrapper, asin_wrapper, sinh, asinh}},
{"button_cos", {"cos(", "acos(", "cosh(", "acosh("}, {cos_wrapper, acos_wrapper, cosh, acosh}},
{"button_tan", {"tan(", "atan(", "tanh(", "atanh("}, {tan_wrapper, atan_wrapper, tanh, atanh}},
{"button_log", {"log(", "10^", "log(", "log("}, {log10, pow10y, log10, log10}},
{"button_ln", {"ln(", "e^", "ln(", "ln("}, {log, exp, log, log}},
{"button_sq", {"^2", "sqrt(", "^2", "^2"}, {powx2, sqrt, powx2, powx2}},
{"button_sqrt", {"sqrt(", "^2", "sqrt(", "sqrt("}, {sqrt, powx2, sqrt, sqrt}},
{"button_fac", {"!", "!", "!", "!"}, {factorial, factorial, factorial, factorial}},
{"button_cmp", {"~", "~", "~", "~"}, {cmp, cmp, cmp, cmp}},
{NULL}
};
apply_object_data (operation_map, gfunc_map, function_map);
}
/* set_basic_object_data. Here, we set the information that is saved in
* apply_object_data. For basic mode.
*/
static void set_basic_object_data ()
{
s_operation_map operation_map[] = {
{"button_enter", "=", '='},
{"button_plus", "+", '+'},
{"button_minus", "-", '-'},
{"button_mult", "*", '*'},
{"button_div", "/", '/'},
{"button_percent", "%", '%'},
{"button_f1", "(", '('}, /* paropen or swapxy */
{"button_f2", ")", ')'}, /* parclose or rolldn */
{NULL}
};
s_gfunc_map gfunc_map[] = {
{"button_sign", "-", display_result_toggle_sign},
{"button_f1", "(", gfunc_f1}, /* paropen or swapxy */
{"button_f2", ")", gfunc_f2}, /* parclose or rolldn */
{NULL}
};
s_function_map function_map[] = {
{"button_sqrt", {"sqrt", "^2", "sqrt", "sqrt"}, {sqrt, powx2, sqrt, sqrt}},
{NULL}
};
apply_object_data (operation_map, gfunc_map, function_map);
}
/* set_disp_ctrl_object_data. Here, we set the information that is saved in
* apply_object_data. For display control buttons.
*/
static void set_disp_ctrl_object_data ()
{
int counter=0;
s_gfunc_map map[] = {\
{"button_clr", NULL, clear},\
{"button_backspace", NULL, backspace},\
{"button_allclr", NULL, all_clear},\
{NULL}\
};
while (map[counter].button_name != NULL) {
g_object_set_data (G_OBJECT (glade_xml_get_widget (
dispctrl_xml, map[counter].button_name)),
"display_string", map[counter].display_string);
g_object_set_data (G_OBJECT (glade_xml_get_widget (
dispctrl_xml, map[counter].button_name)),
"func", map[counter].func);
counter++;
};
}
/* ui_pack_from_xml. This is a very special function. But we need it at least
* three times. takes child_name from child_xml and adds it to box at index.
* signals are connected and accel_group of accel_child_name is attached to
* box's toplevel window.
*/
static void ui_pack_from_xml (GtkWidget *box,
int index,
GladeXML *child_xml,
char *child_name,
char *accel_child_name,
gboolean expand,
gboolean fill)
{
GtkWidget *child_widget=NULL, *accel_child_widget=NULL;
GtkAccelGroup *accel_group=NULL;
GList *accel_list=NULL;
/* at first connect signal handlers */
glade_xml_signal_autoconnect (child_xml);
/* next, get the "root" child */
child_widget = glade_xml_get_widget (child_xml, child_name);
/* we have to add the accel_group of child to the main_window in order
* to get working accelerators.
*/
accel_child_widget = glade_xml_get_widget (child_xml, accel_child_name);
if (!accel_child_widget)
error_message ("Couldn't find widget \"%s\" in \"ui_pack_from_xml\"", accel_child_name);
accel_list = gtk_widget_list_accel_closures (accel_child_widget);
if (accel_list)
accel_group = gtk_accel_group_from_accel_closure ((GClosure *) accel_list->data);
if (accel_group)
gtk_window_add_accel_group ((GtkWindow *) gtk_widget_get_toplevel (box), accel_group);
gtk_box_pack_start ((GtkBox *) box, child_widget, expand, fill, 0);
gtk_box_reorder_child ((GtkBox *) box, child_widget, index);
gtk_widget_show (box);
}
/* ui_main_window_create. creates the main_window, containing menu toolbar and
* the display skeleton. display control buttons and the calculator's buttons
* are added by the callbacks for scientific resp basic mode.
*/
GtkWidget *ui_main_window_create ()
{
main_window_xml = glade_file_open (MAIN_GLADE_FILE, "main_window", TRUE);
/* connect the signals in the interface */
glade_xml_signal_autoconnect(main_window_xml);
return glade_xml_get_widget (main_window_xml, "main_window");
}
/* ui_main_window_set_dispctrl. we can't (un-)hide the dispctrl buttons as they
* have the same key accelerators and thus only one button group would get
* activated.
*/
void ui_main_window_set_dispctrl (int location)
{
GtkWidget *table_dispctrl, *box;
s_signal_cb signal_cb;
/* destroy any existing display controls */
if (dispctrl_xml) {
table_dispctrl = glade_xml_get_widget (dispctrl_xml, "table_dispctrl");
if (table_dispctrl) gtk_widget_destroy (table_dispctrl);
g_object_unref (G_OBJECT(dispctrl_xml));
dispctrl_xml = NULL;
}
/* now create the new one at location */
switch(location) {
case DISPCTRL_BOTTOM:
box = glade_xml_get_widget (view_xml, "display_vbox");
dispctrl_xml = glade_file_open (DISPCTRL_BOTTOM_GLADE_FILE,
"table_dispctrl", TRUE);
ui_pack_from_xml (box, 1, dispctrl_xml, "table_dispctrl",
"button_clr", TRUE, TRUE);
break;
case DISPCTRL_RIGHT:
box = glade_xml_get_widget (view_xml, "display_hbox");
dispctrl_xml = glade_file_open (DISPCTRL_RIGHT_GLADE_FILE,
"table_dispctrl", TRUE);
ui_pack_from_xml (box, 1, dispctrl_xml, "table_dispctrl",
"button_clr", FALSE, FALSE);
break;
case DISPCTRL_RIGHTV:
box = glade_xml_get_widget (view_xml, "display_hbox");
dispctrl_xml = glade_file_open (DISPCTRL_RIGHTV_GLADE_FILE,
"table_dispctrl", TRUE);
ui_pack_from_xml (box, 1, dispctrl_xml, "table_dispctrl",
"button_clr", FALSE, FALSE);
break;
default:
error_message ("Unknown location %i in \"ui_main_window_set_dispctrl\"", location);
}
set_disp_ctrl_object_data ();
/* finally we connect that signal handler */
signal_cb.detailed_signal = g_strdup ("button_press_event");
signal_cb.callback = (GCallback) on_button_press_event;
set_all_dispctrl_buttons_property (set_table_child_callback, (gpointer) &signal_cb);
set_all_dispctrl_buttons_tip();
}
/* ui_main_window_buttons_destroy. removes the scientific resp basic mode
* buttons. display control buttons are not touched here!
*/
void ui_main_window_buttons_destroy ()
{
GtkWidget *box;
if (!button_box_xml) return;
box = glade_xml_get_widget (button_box_xml, "button_box");
if (box) gtk_widget_destroy (box);
}
/* ui_main_window_buttons_create. fills main_window with calculator's buttons,
* paying respect to current mode. dispctrl buttons need to be done extra.
*/
void ui_main_window_buttons_create (int mode)
{
GtkWidget *box, *button;
struct lconv *locale_settings;
s_signal_cb signal_cb;
switch (mode) {
case BASIC_MODE:
if (button_box_xml) g_object_unref (G_OBJECT(button_box_xml));
button_box_xml = glade_file_open (BASIC_GLADE_FILE, "button_box", TRUE);
box = glade_xml_get_widget (view_xml, "classic_view_vbox");
ui_pack_from_xml (box, 2, button_box_xml, "button_box",
"button_1", TRUE, TRUE);
set_basic_object_data (button_box_xml);
break;
case SCIENTIFIC_MODE:
if (button_box_xml) g_object_unref (G_OBJECT(button_box_xml));
button_box_xml = glade_file_open (SCIENTIFIC_GLADE_FILE, "button_box", TRUE);
box = glade_xml_get_widget (view_xml, "classic_view_vbox");
ui_pack_from_xml (box, 2, button_box_xml, "button_box",
"button_1", TRUE, TRUE);
set_scientific_object_data (button_box_xml);
break;
case PAPER_MODE:
return;
default:
error_message ("Unknown mode in \"ui_main_window_buttons_create\"");
}
signal_cb.detailed_signal = g_strdup ("button_press_event");
signal_cb.callback = (GCallback) on_button_press_event;
set_all_normal_buttons_property (set_table_child_callback, (gpointer) &signal_cb);
/* update "decimal point" button to locale's decimal point */
dec_point[0] = DEFAULT_DEC_POINT;
locale_settings = localeconv();
if (strlen (locale_settings->decimal_point) != 1) {
fprintf (stderr, _("[%s] length of decimal point (in locale) \
is not supported: >%s<\nYou might face problems when using %s! %s\n)"),
PACKAGE, locale_settings->decimal_point, PROG_NAME, BUG_REPORT);
} else dec_point[0] = locale_settings->decimal_point[0];
dec_point[1] = '\0';
gtk_button_set_label ((GtkButton *) glade_xml_get_widget (
button_box_xml, "button_point"), dec_point);
/* disable mr and m+ button if there is nothing to display */
button = glade_xml_get_widget (button_box_xml, "button_MR");
gtk_widget_set_sensitive (button, memory.len > 0);
button = glade_xml_get_widget (button_box_xml, "button_Mplus");
gtk_widget_set_sensitive (button, memory.len > 0);
/* apply button specific prefs */
set_all_normal_buttons_size (prefs.button_width, prefs.button_height);
set_all_normal_buttons_font (prefs.custom_button_font ? prefs.button_font : "");
set_all_normal_buttons_tip ();
}
/* set_table_child_callback. Function argument for set_all_*_buttons_property.
* sets the size.
*/
static void set_table_child_callback (gpointer data, gpointer user_data)
{
s_signal_cb *signal_cb;
GtkTableChild *table_child;
table_child = data;
signal_cb = user_data;
g_signal_connect (table_child->widget, signal_cb->detailed_signal,
signal_cb->callback, NULL);
}
/* set_table_child_size. Function argument for set_all_buttons_property.
* sets the size.
*/
static void set_table_child_size (gpointer data, gpointer user_data)
{
GtkRequisition *size;
GtkTableChild *table_child;
size = user_data; /* dereference */
table_child = data;
gtk_widget_set_size_request (table_child->widget, size->width, size->height);
}
/* set_table_child_font. Function argument for set_all_buttons_property.
* sets the font of buttons. We have to set the label of the button!
*/
static void set_table_child_font (gpointer data, gpointer user_data)
{
PangoFontDescription *font;
GtkTableChild *table_child;
GtkWidget *w=NULL;
font = user_data; /* dereference */
table_child = data;
if (GTK_IS_BIN (table_child->widget))
w = gtk_bin_get_child ((GtkBin *)(table_child->widget));
/* if it's a normal button, w is now the label we want to font-change.
* if it's a popup button, we have to get the most left child first.
*/
if (GTK_IS_BOX (w)) w = ((GtkBoxChild *)((((GtkBox *)w)->children)->data))->widget;
if (GTK_IS_LABEL(w)) gtk_widget_modify_font (w, font);
/* else do nothing */
}
gboolean set_table_child_tip_accel_finder (GtkAccelKey *key, GClosure *closure, gpointer data)
{
gpointer *d;
GClosure *c;
GtkTooltipsData *tip_data;
gchar *tt, *al;
d = (gpointer *) data;
c = (GClosure *) d[0];
tip_data = (GtkTooltipsData *) d[1];
if (closure == c) {
tt = tip_data->tip_text;
al = gtk_accelerator_get_label(key->accel_key, key->accel_mods);
tip_data->tip_text = g_strdup_printf("%s %s", tt, al);
g_free(tt);
g_free(al);
return TRUE;
}
return FALSE;
}
static void set_table_child_tip_accel (gpointer data, gpointer user_data)
{
GtkTableChild *tc;
GtkWidget *button;
GList *closure_list;
GtkAccelGroup *accel_group;
GtkTooltipsData *tip_data;
gpointer d[2];
tc = data;
button = tc->widget;
/* get all accelerators (== closures) connected to this button */
closure_list = gtk_widget_list_accel_closures (button);
if (!closure_list) return;
if (!closure_list->data) return;
/* we head for first closure */
accel_group = gtk_accel_group_from_accel_closure(closure_list->data);
if (!accel_group) return;
tip_data = gtk_tooltips_data_get(button);
if (!tip_data) return;
d[0] = (gpointer) closure_list->data;
d[1] = (gpointer) tip_data;
gtk_accel_group_find(accel_group, (GtkAccelGroupFindFunc)set_table_child_tip_accel_finder, d);
}
/* set_all_dispctrl_buttons_property. calls func with argument data for
* every button of the display control section.
*/
static void set_all_dispctrl_buttons_property (GFunc func, gpointer data)
{
GtkTable *table;
if (!dispctrl_xml) return;
/* at first the display control table. always there; somehow */
table = (GtkTable *) glade_xml_get_widget (dispctrl_xml,
"table_dispctrl");
if (!table) return;
/* dispctrl_right has an extra table for cosmetic reasons. */
if (GTK_IS_TABLE (((GtkTableChild *)table->children->data)->widget))
table = (GtkTable *) ((GtkTableChild *)table->children->data)->widget;
g_list_foreach (table->children, func, data);
}
/* set_all_dispctrl_buttons_property. calls func with argument data for
* every button of the "calculator" section.
*/
static void set_all_normal_buttons_property (GFunc func, gpointer data)
{
GtkTable *table;
/* now depending on mode the remaining buttons */
switch (prefs.mode) {
case BASIC_MODE:
table = (GtkTable *) glade_xml_get_widget (button_box_xml,
"table_buttons");
g_list_foreach (table->children, func, data);
break;
case SCIENTIFIC_MODE:
table = (GtkTable *) glade_xml_get_widget (button_box_xml,
"table_standard_buttons");
g_list_foreach (table->children, func, data);
table = (GtkTable *) glade_xml_get_widget (button_box_xml,
"table_bin_buttons");
g_list_foreach (table->children, func, data);
table = (GtkTable *) glade_xml_get_widget (button_box_xml,
"table_func_buttons");
g_list_foreach (table->children, func, data);
break;
case PAPER_MODE:
/* do nothing - no buttons */
break;
default:
error_message ("Unknown mode %i in \"set_all_normal_buttons_property\"", prefs.mode);
}
}
/* set_all_buttons_property. calls func with argument data for every button.
*/
static void set_all_buttons_property (GFunc func, gpointer data)
{
set_all_dispctrl_buttons_property (func, data);
set_all_normal_buttons_property (func, data);
}
/* set_all_buttons_size. gateway for set_all_buttons_property.
*/
void set_all_buttons_size (int width, int height)
{
GtkRequisition size;
size.width = width;
size.height = height;
set_all_buttons_property (set_table_child_size, (gpointer) &size);
}
void set_all_normal_buttons_tip ()
{
set_all_normal_buttons_property (set_table_child_tip_accel, NULL);
}
void set_all_dispctrl_buttons_tip ()
{
set_all_dispctrl_buttons_property (set_table_child_tip_accel, NULL);
}
/* set_all_nomral_buttons_size. gateway for set_all_normal_buttons_property.
*/
void set_all_normal_buttons_size (int width, int height)
{
GtkRequisition size;
size.width = width;
size.height = height;
set_all_normal_buttons_property (set_table_child_size, (gpointer) &size);
}
/* set_all_dispctrl_buttons_size. gateway for set_all_dispctrl_buttons_property.
*/
void set_all_dispctrl_buttons_size (int width, int height)
{
GtkRequisition size;
size.width = width;
size.height = height;
set_all_dispctrl_buttons_property (set_table_child_size, (gpointer) &size);
}
/* set_all_buttons_font. gateway for set_all_buttons_property.
*/
void set_all_buttons_font (char *font_string)
{
PangoFontDescription *pango_font;
pango_font = pango_font_description_from_string (font_string);
set_all_buttons_property (set_table_child_font, pango_font);
}
/* set_all_normal_buttons_font. gateway for set_all_buttons_property.
*/
void set_all_normal_buttons_font (char *font_string)
{
PangoFontDescription *pango_font;
pango_font = pango_font_description_from_string (font_string);
set_all_normal_buttons_property (set_table_child_font, pango_font);
}
/* set_all_dispctrl_buttons_font. gateway for set_all_buttons_property.
*/
void set_all_dispctrl_buttons_font (char *font_string)
{
PangoFontDescription *pango_font;
pango_font = pango_font_description_from_string (font_string);
set_all_dispctrl_buttons_property (set_table_child_font, pango_font);
}
gboolean button_deactivation (gpointer data)
{
GtkToggleButton *b;
b = (GtkToggleButton*) data;
gtk_toggle_button_set_active (b, FALSE);
return FALSE;
}
void button_activation (GtkToggleButton *b)
{
g_timeout_add (100, button_deactivation, (gpointer) b);
}
void update_active_buttons (int number_base, int notation_mode)
{
int counter=0;
GtkWidget *current_button;
unsigned int state;
/* state = (1 << number_base) | (1 << (notation_mode + NR_NUMBER_BASES)); */
state = 1 << number_base;
while (active_buttons[counter].button_name != NULL) {
current_button = glade_xml_get_widget (button_box_xml,
active_buttons[counter].button_name);
if (current_button == NULL) {
counter++;
continue;
}
gtk_widget_set_sensitive (current_button,
(active_buttons[counter].mask & state) == state);
counter++;
}
}
void update_dispctrl()
{
/* just put one here and hide it afterwards. we need the button
for working key accelerators. */
if (prefs.mode == BASIC_MODE)
ui_main_window_set_dispctrl (DISPCTRL_BOTTOM);
else if (current_status.notation == CS_RPN)
ui_main_window_set_dispctrl (DISPCTRL_RIGHTV);
else ui_main_window_set_dispctrl (DISPCTRL_RIGHT);
set_widget_visibility (dispctrl_xml, "table_dispctrl",
prefs.vis_dispctrl);
set_all_dispctrl_buttons_size (prefs.button_width, prefs.button_height);
set_all_dispctrl_buttons_font (prefs.custom_button_font ? prefs.button_font : "");
}
/*
* (un) hide a widget
*/
void set_widget_visibility (GladeXML *xml, char *widget_name, gboolean visible)
{
GtkWidget *widget;
widget = glade_xml_get_widget (xml, widget_name);
if (!widget) {
error_message ("Couldn't find widget \"%s\" in \"set_widget_visibility\"", widget_name);
return;
}
if (visible) gtk_widget_show_all (widget);
else gtk_widget_hide_all (widget);
}
/* menu code - e.g. used for the constant popup menu */
void position_menu (GtkMenu *menu,
gint *x,
gint *y,
gboolean *push_in,
gpointer user_data)
{
/* this code is taken from GTK 2.2.1 source, therefore credits go there.
* gtk+-2.0.6/gtk/gtkoptionmenu.c (function gtk_option_menu_position)
* modified to fit our button menu widget.
*/
GtkWidget *child;
GtkWidget *widget;
GtkRequisition requisition;
GList *children;
gint screen_width;
gint menu_xpos;
gint menu_ypos;
gint menu_width;
g_return_if_fail (GTK_IS_BUTTON (user_data));
widget = GTK_WIDGET (user_data);
gtk_widget_get_child_requisition (GTK_WIDGET (menu), &requisition);
menu_width = requisition.width;
/* i guess we don't need the "active" stuff from the original positioning
code. we don't have any active items
*/
gdk_window_get_origin (widget->window, &menu_xpos, &menu_ypos);
menu_xpos += widget->allocation.x;
menu_ypos += widget->allocation.y + widget->allocation.height / 2 - 2;
children = GTK_MENU_SHELL(menu)->children;
while (children) {
child = children->data;
if (GTK_WIDGET_VISIBLE (child)) {
gtk_widget_get_child_requisition (child, &requisition);
menu_ypos -= requisition.height;
}
children = children->next;
}
/*screen_width = gdk_screen_get_width (gtk_widget_get_screen (widget));*/
screen_width = gdk_screen_width ();
if (menu_xpos < 0) menu_xpos = 0;
else if ((menu_xpos + menu_width) > screen_width)
menu_xpos -= ((menu_xpos + menu_width) - screen_width);
*x = menu_xpos;
*y = menu_ypos;
*push_in = TRUE;
}
GtkWidget *ui_user_functions_menu_create (s_user_function *user_function, GCallback user_function_handler)
{
GtkWidget *menu, *child;
int counter=0;
char *label;
menu = gtk_menu_new();
while (user_function[counter].name != NULL) {
label = g_strdup_printf ("%s(%s) = %s", user_function[counter].name,
user_function[counter].variable,
user_function[counter].expression);
child = gtk_menu_item_new_with_label(label);
g_free (label);
gtk_menu_shell_append ((GtkMenuShell *) menu, child);
gtk_widget_show (child);
g_signal_connect (G_OBJECT (child), "activate", user_function_handler, GINT_TO_POINTER(counter));
counter++;
}
return menu;
}
GtkWidget *ui_constants_menu_create (s_constant *constant, GCallback const_handler)
{
GtkWidget *menu, *child;
int counter=0;
char *label;
menu = gtk_menu_new();
while (constant[counter].name != NULL) {
label = g_strdup_printf ("%s: %s (%s)", constant[counter].name, constant[counter].value, constant[counter].desc);
child = gtk_menu_item_new_with_label(label);
g_free (label);
gtk_menu_shell_append ((GtkMenuShell *) menu, child);
gtk_widget_show (child);
g_signal_connect (G_OBJECT (child), "activate", const_handler, constant[counter].value);
counter++;
}
return menu;
}
GtkWidget *ui_memory_menu_create (s_array memory, GCallback memory_handler, char *last_item)
{
GtkWidget *menu, *child;
int counter=0;
char *label;
menu = gtk_menu_new();
for (counter = 0; counter < memory.len; counter++) {
label = g_strdup_printf ("%f", memory.data[counter]);
child = gtk_menu_item_new_with_label(label);
g_free (label);
gtk_menu_shell_append ((GtkMenuShell *) menu, child);
gtk_widget_show (child);
g_signal_connect (G_OBJECT (child), "activate", memory_handler, GINT_TO_POINTER(counter));
}
if (last_item != NULL) {
label = g_strdup (last_item);
child = gtk_menu_item_new_with_label(label);
g_free (label);
gtk_menu_shell_append ((GtkMenuShell *) menu, child);
gtk_widget_show (child);
g_signal_connect (G_OBJECT (child), "activate", memory_handler, GINT_TO_POINTER(counter));
}
return menu;
}
GtkWidget *ui_right_mouse_menu_create ()
{
GtkWidget *menu, *menu_item;
menu = gtk_menu_new();
menu_item = gtk_check_menu_item_new_with_mnemonic (_("Show _menu bar"));
gtk_check_menu_item_set_active ((GtkCheckMenuItem *) menu_item, prefs.show_menu);
gtk_menu_shell_append ((GtkMenuShell *) menu, menu_item);
gtk_widget_show (menu_item);
g_signal_connect (G_OBJECT (menu_item), "activate", (GCallback) on_show_menubar1_activate, NULL);
return menu;
}
GtkWidget *ui_pref_dialog_create ()
{
int counter=0;
GtkWidget *w, *prefs_dialog;
GtkTreeIter iter;
GtkWidget *tree_view;
GtkCellRenderer *renderer;
GtkTreeViewColumn *column;
GtkTreeSelection *select;
GtkSizeGroup *sgroup;
s_prefs_entry *prefs_list;
prefs_xml = glade_file_open (PREFS_GLADE_FILE, "prefs_dialog", FALSE);
glade_xml_signal_autoconnect(prefs_xml);
prefs_dialog = glade_xml_get_widget (prefs_xml, "prefs_dialog");
gtk_window_set_title ((GtkWindow *)prefs_dialog, \
g_strdup_printf (_("%s Preferences"), PACKAGE));
/* preferences -> gui */
prefs_list = config_file_get_prefs_list();
while (prefs_list[counter].key != NULL) {
if (prefs_list[counter].set_handler != NULL) {
prefs_list[counter].set_handler (prefs_xml,
prefs_list[counter].widget_name,
prefs_list[counter].variable);
}
counter++;
}
w = glade_xml_get_widget (prefs_xml, "prefs_button_font_label");
gtk_widget_set_sensitive (w, prefs.custom_button_font);
w = glade_xml_get_widget (prefs_xml, "prefs_button_font");
gtk_widget_set_sensitive (w, prefs.custom_button_font);
w = glade_xml_get_widget (prefs_xml, "prefs_bin_length");
gtk_widget_set_sensitive (w, prefs.bin_fixed);
/* make user defined constants list. */
prefs_constant_store = gtk_list_store_new (NR_CONST_COLUMNS,
G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
counter = 0;
while (constant[counter].name != NULL) {
gtk_list_store_append (prefs_constant_store, &iter);
gtk_list_store_set (prefs_constant_store, &iter,
CONST_NAME_COLUMN, constant[counter].name,
CONST_VALUE_COLUMN, constant[counter].value,
CONST_DESC_COLUMN, constant[counter].desc,
-1);
counter++;
}
tree_view = glade_xml_get_widget (prefs_xml, "constant_treeview");
gtk_tree_view_set_model ((GtkTreeView *) tree_view,
GTK_TREE_MODEL (prefs_constant_store));
renderer = gtk_cell_renderer_text_new ();
column = gtk_tree_view_column_new_with_attributes ("Name", renderer,
"text", CONST_NAME_COLUMN, NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
column = gtk_tree_view_column_new_with_attributes ("Value", renderer,
"text", CONST_VALUE_COLUMN, NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
column = gtk_tree_view_column_new_with_attributes ("Description", renderer,
"text", CONST_DESC_COLUMN, NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
select = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE);
g_signal_connect (G_OBJECT (select), "changed",
G_CALLBACK (const_list_selection_changed_cb),
NULL);
/* make user defined function list */
prefs_user_function_store = gtk_list_store_new (NR_UFUNC_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
counter = 0;
while (user_function[counter].name != NULL) {
gtk_list_store_append (prefs_user_function_store, &iter);
gtk_list_store_set (prefs_user_function_store, &iter,
UFUNC_NAME_COLUMN, user_function[counter].name,
UFUNC_VARIABLE_COLUMN, user_function[counter].variable,
UFUNC_EXPRESSION_COLUMN, user_function[counter].expression,
-1);
counter++;
}
tree_view = glade_xml_get_widget (prefs_xml, "user_function_treeview");
gtk_tree_view_set_model ((GtkTreeView *) tree_view,
GTK_TREE_MODEL (prefs_user_function_store));
renderer = gtk_cell_renderer_text_new ();
column = gtk_tree_view_column_new_with_attributes ("Name", renderer,
"text", UFUNC_NAME_COLUMN, NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
column = gtk_tree_view_column_new_with_attributes ("Variable", renderer,
"text", UFUNC_VARIABLE_COLUMN, NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
column = gtk_tree_view_column_new_with_attributes ("Expression", renderer,
"text", UFUNC_EXPRESSION_COLUMN, NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
select = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE);
g_signal_connect (G_OBJECT (select), "changed",
G_CALLBACK (user_function_list_selection_changed_cb),
NULL);
/* pack widget of same size into GtkSizeGroup */
sgroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
gtk_size_group_add_widget (sgroup,
glade_xml_get_widget (prefs_xml, "prefs_button_font_label"));
gtk_size_group_add_widget (sgroup,
glade_xml_get_widget (prefs_xml, "prefs_button_width_label"));
gtk_size_group_add_widget (sgroup,
glade_xml_get_widget (prefs_xml, "prefs_button_height_label"));
sgroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
gtk_size_group_add_widget (sgroup,
glade_xml_get_widget (prefs_xml, "prefs_const_add_button"));
gtk_size_group_add_widget (sgroup,
glade_xml_get_widget (prefs_xml, "prefs_const_update_button"));
gtk_size_group_add_widget (sgroup,
glade_xml_get_widget (prefs_xml, "prefs_const_delete_button"));
gtk_size_group_add_widget (sgroup,
glade_xml_get_widget (prefs_xml, "prefs_const_clear_button"));
sgroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
gtk_size_group_add_widget (sgroup,
glade_xml_get_widget (prefs_xml, "prefs_func_add_button"));
gtk_size_group_add_widget (sgroup,
glade_xml_get_widget (prefs_xml, "prefs_func_update_button"));
gtk_size_group_add_widget (sgroup,
glade_xml_get_widget (prefs_xml, "prefs_func_delete_button"));
gtk_size_group_add_widget (sgroup,
glade_xml_get_widget (prefs_xml, "prefs_func_clear_button"));
gtk_widget_show (prefs_dialog);
return prefs_dialog;
}
GtkWidget *ui_about_dialog_create()
{
about_dialog_xml = glade_file_open (ABOUT_GLADE_FILE,
"about_dialog", FALSE);
glade_xml_signal_autoconnect(about_dialog_xml);
return glade_xml_get_widget (about_dialog_xml, "about_dialog");
}
void ui_formula_entry_activate ()
{
GtkWidget *formula_entry;
formula_entry = glade_xml_get_widget (view_xml, "formula_entry");
gtk_widget_activate(formula_entry);
}
void ui_formula_entry_set (G_CONST_RETURN gchar *text)
{
GtkWidget *formula_entry;
if (text == NULL) return;
formula_entry = glade_xml_get_widget (view_xml, "formula_entry");
gtk_entry_set_text ((GtkEntry *) formula_entry, text);
}
void ui_formula_entry_insert (G_CONST_RETURN gchar *text)
{
GtkWidget *formula_entry;
int position;
if (text == NULL) return;
formula_entry = glade_xml_get_widget (view_xml, "formula_entry");
position = gtk_editable_get_position ((GtkEditable *) formula_entry);
gtk_editable_insert_text ((GtkEditable *) formula_entry, text, -1,
&position);
gtk_editable_set_position ((GtkEditable *) formula_entry, position);
}
void ui_formula_entry_backspace ()
{
GtkWidget *formula_entry;
formula_entry = glade_xml_get_widget (view_xml, "formula_entry");
gtk_editable_delete_text ((GtkEditable *) formula_entry,
strlen(gtk_entry_get_text((GtkEntry *) formula_entry)) - 1, -1);
}
/* ui_formula_entry_state. if color == NULL looks like we get default. this is
* what we want.
*/
void ui_formula_entry_state (gboolean error)
{
GtkWidget *formula_entry;
GdkColor *color=NULL;
formula_entry = glade_xml_get_widget (view_xml, "formula_entry");
if (error) {
color = (GdkColor *) malloc(sizeof(GdkColor));
gdk_color_parse ("red", color);
}
gtk_widget_modify_text (formula_entry, 0, color);
gtk_widget_modify_text (formula_entry, 1, color);
gtk_widget_modify_text (formula_entry, 2, color);
gtk_widget_modify_text (formula_entry, 3, color);
gtk_widget_modify_text (formula_entry, 4, color);
if (color) g_free(color);
}
void ui_button_set_pan ()
{
set_button_label_and_tooltip (button_box_xml, "button_enter",
_("="), _("Enter"));
set_button_label_and_tooltip (button_box_xml, "button_pow",
_("x^y"), _("Power"));
set_button_label_and_tooltip (button_box_xml, "button_f1",
_("("), _("Open Bracket"));
set_button_label_and_tooltip (button_box_xml, "button_f2",
_(")"), _("Close Bracket"));
}
void ui_button_set_rpn ()
{
set_button_label_and_tooltip (button_box_xml, "button_enter",
_("ENT"), _("Enter"));
set_button_label_and_tooltip (button_box_xml, "button_pow",
_("y^x"), _("Power"));
set_button_label_and_tooltip (button_box_xml, "button_f1",
_("x<>y"), _("swap current number with top of stack"));
set_button_label_and_tooltip (button_box_xml, "button_f2",
_("roll"), _("roll down stack"));
}
void ui_relax_fmod_buttons ()
{
GtkWidget *tbutton;
tbutton = glade_xml_get_widget (button_box_xml, "button_inv");
gtk_toggle_button_set_active ((GtkToggleButton *) tbutton, FALSE);
tbutton = glade_xml_get_widget (button_box_xml, "button_hyp");
gtk_toggle_button_set_active ((GtkToggleButton *) tbutton, FALSE);
}
void ui_classic_view_create()
{
GtkWidget *classic_view_vbox, *box;
/* at first, check if there is already a classic view */
if (view_xml) {
classic_view_vbox = glade_xml_get_widget (view_xml, "classic_view_vbox");
if (classic_view_vbox) return;
}
/* if not, build one */
view_xml = glade_file_open (CLASSIC_VIEW_GLADE_FILE, "classic_view_vbox", TRUE);
box = glade_xml_get_widget (main_window_xml, "window_vbox");
ui_pack_from_xml (box, 1, view_xml, "classic_view_vbox", "textview", TRUE, TRUE);
display_init ();
remember_display_values ();
}
void ui_classic_view_destroy()
{
GtkWidget *classic_view_vbox;
if (!view_xml) return;
classic_view_vbox = glade_xml_get_widget (view_xml, "classic_view_vbox");
if (classic_view_vbox) gtk_widget_destroy (classic_view_vbox);
}
void ui_paper_view_create()
{
GtkWidget *paper_view_vbox, *box, *tree_view;
GtkCellRenderer *renderer;
GtkTreeViewColumn *column;
GtkListStore *paper_store;
GtkTreeSelection *select;
/* at first, check if there is already a ng view */
if (view_xml) {
paper_view_vbox = glade_xml_get_widget (view_xml, "paper_view_vbox");
if (paper_view_vbox) return;
}
/* if not, build one */
view_xml = glade_file_open (PAPER_VIEW_GLADE_FILE, "paper_view_vbox", TRUE);
box = glade_xml_get_widget (main_window_xml, "window_vbox");
ui_pack_from_xml (box, 1, view_xml, "paper_view_vbox", "paper_treeview", TRUE, TRUE);
/* markup / xalign / foreground */
paper_store = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_FLOAT, G_TYPE_STRING);
tree_view = glade_xml_get_widget (view_xml, "paper_treeview");
gtk_tree_view_set_model ((GtkTreeView *) tree_view, GTK_TREE_MODEL (paper_store));
renderer = gtk_cell_renderer_text_new ();
column = gtk_tree_view_column_new_with_attributes ("Result Display", renderer, "markup", 0, "xalign", 1, "foreground", 2, NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
select = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE);
g_signal_connect (G_OBJECT (tree_view), "button-press-event",
G_CALLBACK (paper_tree_view_selection_changed_cb),
NULL);
gtk_widget_grab_focus(glade_xml_get_widget (view_xml, "paper_entry"));
}
void ui_paper_view_destroy()
{
GtkWidget *paper_view_vbox;
if (!view_xml) return;
paper_view_vbox = glade_xml_get_widget (view_xml, "paper_view_vbox");
if (paper_view_vbox) gtk_widget_destroy (paper_view_vbox);
}
syntax highlighted by Code2HTML, v. 0.9.1