/*
    Qalculate (GTK+ UI)

    Copyright (C) 2003-2007, 2008, 2016-2019  Hanna Knutsson (hanna.knutsson@protonmail.com)

    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.
*/

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <gdk/gdkkeysyms.h>
#include <gtk/gtk.h>
#include <gdk/gdk.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <glib/gstdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
#include <limits>
#include <fstream>

#include "support.h"
#include "callbacks.h"
#include "interface.h"
#include "main.h"
#include <stack>
#include <deque>

#if HAVE_UNORDERED_MAP
#	include <unordered_map>
#elif 	defined(__GNUC__)

#	ifndef __has_include
#	define __has_include(x) 0
#	endif

#	if (defined(__clang__) && __has_include(<tr1/unordered_map>)) || (__GNUC__ >= 4 && __GNUC_MINOR__ >= 3)
#		include <tr1/unordered_map>
		namespace Sgi = std;
#		define unordered_map std::tr1::unordered_map
#	else
#		if __GNUC__ < 3
#			include <hash_map.h>
			namespace Sgi { using ::hash_map; }; // inherit globals
#		else
#			include <ext/hash_map>
#			if __GNUC__ == 3 && __GNUC_MINOR__ == 0
				namespace Sgi = std;		// GCC 3.0
#			else
				namespace Sgi = ::__gnu_cxx;	// GCC 3.1 and later
#			endif
#		endif
#		define unordered_map Sgi::hash_map
#	endif
#else      // ...  there are other compilers, right?
	namespace Sgi = std;
#	define unordered_map Sgi::hash_map
#endif

#define AUTOCALC_HISTORY_TIMEOUT 2000

extern bool do_timeout, check_expression_position;
extern gint expression_position;

extern GtkBuilder *main_builder, *argumentrules_builder, *csvimport_builder, *csvexport_builder, *setbase_builder, *datasetedit_builder, *datasets_builder, *decimals_builder;
extern GtkBuilder *functionedit_builder, *functions_builder, *matrixedit_builder, *matrix_builder, *namesedit_builder, *nbases_builder, *plot_builder, *precision_builder;
extern GtkBuilder *preferences_builder, *unitedit_builder, *units_builder, *unknownedit_builder, *variableedit_builder, *variables_builder;
extern GtkBuilder *periodictable_builder, *simplefunctionedit_builder, *percentage_builder, *calendarconversion_builder;

extern GtkWidget *mainwindow;

bool changing_in_nbases_dialog;

extern GtkWidget *tabs, *expander_keypad, *expander_history, *expander_stack, *expander_convert;
extern GtkEntryCompletion *completion;
extern GtkWidget *completion_view, *completion_window, *completion_scrolled;
extern GtkListStore *completion_store;
extern GtkTreeModel *completion_filter, *completion_sort;

extern unordered_map<size_t, GtkWidget*> cal_year, cal_month, cal_day, cal_label;
extern GtkWidget *chinese_stem, *chinese_branch;

extern GtkCssProvider *expression_provider, *resultview_provider, *statuslabel_l_provider, *statuslabel_r_provider;

extern GtkWidget *expressiontext, *statuslabel_l, *statuslabel_r, *result_bases;
int two_result_bases_rows = -1;
extern GtkTextBuffer *expressionbuffer;
extern GtkTextTag *expression_par_tag;
extern GtkWidget *f_menu, *v_menu, *u_menu, *u_menu2, *recent_menu;
extern KnownVariable *vans[5];
MathStructure lastx;
extern GtkWidget *tPlotFunctions;
extern GtkListStore *tPlotFunctions_store;
extern GtkWidget *tFunctionArguments;
extern GtkListStore *tFunctionArguments_store;
extern GtkWidget *tSubfunctions;
extern GtkListStore *tSubfunctions_store;
extern GtkWidget *tFunctions, *tFunctionCategories;
extern GtkListStore *tFunctions_store;
extern GtkTreeModel *tFunctions_store_filter;
extern GtkTreeStore *tFunctionCategories_store;
extern GtkWidget *tVariables, *tVariableCategories;
extern GtkListStore *tVariables_store;
extern GtkTreeModel *tVariables_store_filter;
extern GtkTreeStore *tVariableCategories_store;
extern GtkWidget *tUnits, *tUnitCategories;
extern GtkListStore *tUnits_store;
extern GtkTreeModel *tUnits_store_filter;
extern GtkTreeStore *tUnitCategories_store;
extern GtkWidget *tUnitSelectorCategories;
extern GtkWidget *tUnitSelector;
extern GtkListStore *tUnitSelector_store;
extern GtkTreeModel *tUnitSelector_store_filter, *units_convert_filter;
extern GtkTreeStore *tUnitSelectorCategories_store;
extern GtkWidget *units_convert_view, *units_convert_window, *units_convert_scrolled;
extern GtkCellRenderer *units_convert_flag_renderer;
extern GtkWidget *tDataObjects, *tDatasets;
extern GtkListStore *tDataObjects_store, *tDatasets_store;
extern GtkWidget *tDataProperties;
extern GtkListStore *tDataProperties_store;
extern GtkWidget *tNames;
extern GtkListStore *tNames_store;
extern GtkAccelGroup *accel_group;
extern string selected_function_category;
extern MathFunction *selected_function;
extern GtkWidget *item_factorize, *item_simplify;
DataObject *selected_dataobject = NULL;
DataSet *selected_dataset = NULL;
DataProperty *selected_dataproperty = NULL;
MathFunction *edited_function = NULL;
KnownVariable *edited_variable = NULL;
UnknownVariable *edited_unknown = NULL;
KnownVariable *edited_matrix = NULL;
Unit *edited_unit = NULL;
DataSet *edited_dataset = NULL;
DataProperty *edited_dataproperty = NULL;
bool editing_variable = false, editing_unknown = false, editing_matrix = false, editing_unit = false, editing_function = false, editing_dataset = false, editing_dataproperty = false;
size_t selected_subfunction;
size_t last_subfunction_index;
Argument *selected_argument;
Argument *edited_argument;
extern string selected_variable_category;
extern Variable *selected_variable;
extern string selected_unit_category;
extern string selected_unit_selector_category;
extern Unit *selected_unit;
extern Unit *selected_to_unit;
bool save_mode_on_exit;
bool save_defs_on_exit;
bool use_custom_result_font, use_custom_expression_font, use_custom_status_font;
bool save_custom_result_font = false, save_custom_expression_font = false, save_custom_status_font = false;
string custom_result_font, custom_expression_font, custom_status_font;
int scale_n = 0;
bool hyp_is_on, inv_is_on;
bool show_keypad, show_history, show_stack, show_convert, continuous_conversion, set_missing_prefixes;
bool copy_separator;
bool caret_as_xor = false;
extern bool load_global_defs, fetch_exchange_rates_at_startup, first_time, showing_first_time_message;
extern int allow_multiple_instances;
int b_decimal_comma;
int auto_update_exchange_rates;
bool first_error;
bool display_expression_status;
bool block_unit_convert, block_unit_selector_convert;
extern MathStructure *mstruct, *matrix_mstruct, *parsed_mstruct, *parsed_tostruct, *displayed_mstruct;
extern string result_text, parsed_text;
string previous_expression;
bool result_text_approximate = false;
string result_text_long;
extern GtkWidget *resultview;
extern GtkWidget *historyview;
extern GtkWidget *stackview;
extern GtkListStore *stackstore, *historystore;
extern GtkCellRenderer *register_renderer;
extern GtkTreeViewColumn *register_column, *history_column, *history_index_column, *flag_column, *units_flag_column;
extern cairo_surface_t *surface_result;
gint history_width_e = 0, history_width_a = 0;
vector<vector<GtkWidget*> > insert_element_entries;
bool b_busy, b_busy_command, b_busy_result, b_busy_expression, b_busy_fetch;
cairo_surface_t *tmp_surface;
bool expression_has_changed = false, current_object_has_changed = false, expression_has_changed2 = false, expression_has_changed_pos = false;
bool block_result_update = false, block_expression_execution = false, block_display_parse = false;
string parsed_expression;
bool parsed_had_errors = false, parsed_had_warnings = false;
vector<DataProperty*> tmp_props;
vector<DataProperty*> tmp_props_orig;
bool keep_unit_selection = false;
int visible_keypad = 0;
int programming_inbase = 0, programming_outbase = 0;

string prev_output_base, prev_input_base;

string command_convert_units_string;
Unit *command_convert_unit;

int block_conversion_category_switch = 0;

extern GtkWidget *tMatrixEdit, *tMatrix;
extern GtkListStore *tMatrixEdit_store, *tMatrix_store;
vector<GtkTreeViewColumn*> matrix_edit_columns, matrix_columns;

extern GtkAccelGroup *accel_group;

extern gint win_height, win_width, history_height, keypad_height, variables_width, variables_height, variables_position, units_width, units_height, units_position, functions_width, functions_height, functions_hposition, functions_vposition, datasets_width, datasets_height, datasets_hposition, datasets_vposition1, datasets_vposition2;

vector<string> expression_history;
int expression_history_index = -1;
bool dont_change_index = false;
bool result_font_updated = false;
bool first_draw_of_result = true;

PlotLegendPlacement default_plot_legend_placement = PLOT_LEGEND_TOP_RIGHT;
bool default_plot_display_grid = true;
bool default_plot_full_border = false;
string default_plot_min = "0";
string default_plot_max = "10";
string default_plot_step = "1";
int default_plot_sampling_rate = 100;
int default_plot_linewidth = 2;
bool default_plot_use_sampling_rate = true;
bool default_plot_rows = false;
int default_plot_type = 0;
PlotStyle default_plot_style = PLOT_STYLE_LINES;
PlotSmoothing default_plot_smoothing = PLOT_SMOOTHING_NONE;
string default_plot_variable = "x";
bool default_plot_color = true;

bool b_editing_stack = false;

string status_error_color, status_warning_color;

string nbases_error_color, nbases_warning_color;

bool names_edited = false;

int message_type = 1;

gint current_object_start = -1, current_object_end = -1;
bool editing_to_expression = false;
bool stop_timeouts = false;

PrintOptions printops, parse_printops, displayed_printops;
bool displayed_caf = false;
EvaluationOptions evalops;

bool rpn_mode, rpn_keys;
bool adaptive_interval_display;
bool use_e_notation;

extern Thread *view_thread, *command_thread;
bool exit_in_progress = false, command_aborted = false, display_aborted = false, result_too_long = false;

vector<mode_struct> modes;
vector<GtkWidget*> mode_items;
vector<GtkWidget*> popup_result_mode_items;
vector<GtkWidget*> popup_expression_mode_items;
GtkMenu *popup_menu_expressiontext;

deque<string> inhistory;
deque<bool> inhistory_protected;
deque<int> inhistory_type;
deque<int> inhistory_value;
vector<MathStructure*> history_parsed;
vector<MathStructure*> history_answer;

deque<string> expression_undo_buffer;
size_t undo_index = 0;
bool add_to_undo = true;

int current_inhistory_index = -1;
int history_index = 0;
int initial_inhistory_index = 0;
int nr_of_new_expressions = 0;

unordered_map<void*, string> date_map;
unordered_map<void*, string> number_map;
unordered_map<void*, string> number_base_map;
unordered_map<void*, bool> number_approx_map;
unordered_map<void*, string> number_exp_map;
unordered_map<void*, bool> number_exp_minus_map;

unordered_map<string, GdkPixbuf*> flag_images;

extern MathFunction *f_answer;
extern MathFunction *f_expression;

unordered_map<string, GtkTreeIter> convert_category_map;

extern gchar history_error_color[8];
extern gchar history_warning_color[8];
extern gchar history_parse_color[8];
extern gchar history_bookmark_color[8];

bool status_error_color_set;
bool status_warning_color_set;

string old_fromValue, old_toValue;

guint completion_timeout_id = 0;
int completion_delay = 0;

extern QalculateDateTime last_version_check_date;
string last_found_version;

int completion_min = 1, completion_min2 = 2;
bool enable_completion = true, enable_completion2 = true;

bool keep_function_dialog_open = false;

bool automatic_fraction = false;

bool ignore_locale = false;

bool hexadecimal_twos_complement_in = false, twos_complement_in = false;

int default_signed = -1;
int default_bits = -1;

string result_bin, result_oct, result_dec, result_hex;
Number max_bases, min_bases;

vector<string> history_bookmarks;

bool versatile_exact = false;

bool auto_calculate = false;
bool result_autocalculated = false;

bool to_fraction = false;
char to_prefix = 0;
int to_base = 0;
Number to_nbase;

extern bool do_imaginary_j;
bool complex_angle_form = false;

#define TEXT_TAGS			"<span size=\"xx-large\">"
#define TEXT_TAGS_END			"</span>"
#define TEXT_TAGS_SMALL			"<span size=\"large\">"
#define TEXT_TAGS_SMALL_END		"</span>"
#define TEXT_TAGS_XSMALL		"<span size=\"medium\">"
#define TEXT_TAGS_XSMALL_END		"</span>"

#define TTB(str)			if(scaledown <= 0) {str += "<span size=\"xx-large\">";} else if(scaledown == 1) {str += "<span size=\"x-large\">";} else if(scaledown == 2) {str += "<span size=\"large\">";} else {str += "<span size=\"medium\">";}
#define TTB_SMALL(str)			if(scaledown <= 0) {str += "<span size=\"large\">";} else if(scaledown == 1) {str += "<span size=\"medium\">";} else if(scaledown == 2) {str += "<span size=\"small\">";} else {str += "<span size=\"x-small\">";}
#define TTB_XSMALL(str)			if(scaledown <= 0) {str += "<span size=\"medium\">";} else if(scaledown == 1) {str += "<span size=\"small\">";} else {str += "<span size=\"x-small\">";}
#define TTBP(str)			if(ips.power_depth > 0) {TTB_SMALL(str);} else {TTB(str);}
#define TTBP_SMALL(str)			if(ips.power_depth > 0) {TTB_XSMALL(str);} else {TTB_SMALL(str);}
#define TTE(str)			str += "</span>";
#define TT(str, x)			{if(scaledown <= 0) {str += "<span size=\"xx-large\">";} else if(scaledown == 1) {str += "<span size=\"x-large\">";} else if(scaledown == 2) {str += "<span size=\"large\">";} else {str += "<span size=\"medium\">";} str += x; str += "</span>";}
#define TT_SMALL(str, x)		{if(scaledown <= 0) {str += "<span size=\"large\">";} else if(scaledown == 1) {str += "<span size=\"medium\">";} else if(scaledown == 2) {str += "<span size=\"small\">";} else {str += "<span size=\"x-small\">";} str += x; str += "</span>";}
#define TT_XSMALL(str, x)		{if(scaledown <= 0) {str += "<span size=\"medium\">";} else if(scaledown == 1) {str += "<span size=\"small\">";} else {str += "<span size=\"x-small\">";} str += x; str += "</span>";}
#define TTP(str, x)			if(ips.power_depth > 0) {TT_SMALL(str, x);} else {TT(str, x);}
#define TTP_SMALL(str, x)		if(ips.power_depth > 0) {TT_XSMALL(str, x);} else {TT_SMALL(str, x);}

#define PANGO_TT(layout, x)		if(scaledown <= 0) {pango_layout_set_markup(layout, "<span size=\"xx-large\">" x "</span>", -1);} else if(scaledown == 1) {pango_layout_set_markup(layout, "<span size=\"x-large\">" x "</span>", -1);} else if(scaledown == 2) {pango_layout_set_markup(layout, "<span size=\"large\">" x "</span>", -1);} else {pango_layout_set_markup(layout, "<span size=\"medium\">" x "</span>", -1);}
#define PANGO_TT_SMALL(layout, x)	if(scaledown <= 0) {pango_layout_set_markup(layout, "<span size=\"large\">" x "</span>", -1);} else if(scaledown == 1) {pango_layout_set_markup(layout, "<span size=\"medium\">" x "</span>", -1);} else if(scaledown == 1) {pango_layout_set_markup(layout, "<span size=\"medium\">" x "</span>", -1);} else {pango_layout_set_markup(layout, "<span size=\"x-small\">" x "</span>", -1);}
#define PANGO_TT_XSMALL(layout, x)	if(scaledown <= 0) {pango_layout_set_markup(layout, "<span size=\"medium\">" x "</span>", -1);} else if(scaledown == 1) {pango_layout_set_markup(layout, "<span size=\"small\">" x "</span>", -1);} else {pango_layout_set_markup(layout, "<span size=\"x-small\">" x "</span>", -1);}
#define PANGO_TTP(layout, x)		if(ips.power_depth > 0) {PANGO_TT_SMALL(layout, x);} else {PANGO_TT(layout, x);}
#define PANGO_TTP_SMALL(layout, x)	if(ips.power_depth > 0) {PANGO_TT_XSMALL(layout, x);} else {PANGO_TT_SMALL(layout, x);}

#define CALCULATE_SPACE_W		gint space_w, space_h; PangoLayout *layout_space = gtk_widget_create_pango_layout(resultview, NULL); PANGO_TTP(layout_space, " "); pango_layout_get_pixel_size(layout_space, &space_w, &space_h); g_object_unref(layout_space);

#define HISTORY_IS_EXPRESSION(x) (inhistory_type[x] == QALCULATE_HISTORY_EXPRESSION || inhistory_type[x] == QALCULATE_HISTORY_RPN_OPERATION || inhistory_type[x] == QALCULATE_HISTORY_REGISTER_MOVED)
#define HISTORY_IS_PARSE(x) (inhistory_type[x] == QALCULATE_HISTORY_PARSE || inhistory_type[x] == QALCULATE_HISTORY_PARSE_APPROXIMATE || inhistory_type[x] == QALCULATE_HISTORY_PARSE_WITHEQUALS)
#define HISTORY_NOT_EXPRESSION(x) (inhistory_type[x] != QALCULATE_HISTORY_EXPRESSION && inhistory_type[x] != QALCULATE_HISTORY_RPN_OPERATION && inhistory_type[x] != QALCULATE_HISTORY_REGISTER_MOVED)
#define HISTORY_NOT_PARSE(x) (inhistory_type[x] != QALCULATE_HISTORY_PARSE && inhistory_type[x] != QALCULATE_HISTORY_PARSE_APPROXIMATE && inhistory_type[x] != QALCULATE_HISTORY_PARSE_WITHEQUALS)
#define ITEM_IS_EXPRESSION(x) (HISTORY_IS_EXPRESSION(x) || ((size_t) x < inhistory_type.size() - 1 && HISTORY_IS_PARSE(x) && HISTORY_IS_EXPRESSION(x + 1)))
#define ITEM_NOT_EXPRESSION(x) (HISTORY_NOT_EXPRESSION(x) && ((size_t) x >= inhistory_type.size() - 1 || HISTORY_NOT_PARSE(x) || HISTORY_NOT_EXPRESSION(x + 1)))

AnswerFunction::AnswerFunction() : MathFunction(_("answer"), 1, 1, CALCULATOR->f_warning->category(), _("History Answer Value")) {
	if(strcmp(_("answer"), "answer")) addName("answer");
	VectorArgument *arg = new VectorArgument(_("History Index(es)"));
	arg->addArgument(new IntegerArgument("", ARGUMENT_MIN_MAX_NONZERO, true, true, INTEGER_TYPE_SINT));
	setArgumentDefinition(1, arg);
}
int AnswerFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
	if(vargs[0].size() == 0) return 0;
	if(vargs[0].size() > 1) mstruct.clearVector();
	for(size_t i = 0; i < vargs[0].size(); i++) {
		int index = vargs[0][i].number().intValue();
		if(index < 0) index = (int) history_answer.size() + 1 + index;
		if(index <= 0 || index > (int) history_answer.size() || history_answer[(size_t) index - 1] == NULL) {
			CALCULATOR->error(true, _("History index %s does not exist."), vargs[0][i].print().c_str(), NULL);
			if(vargs[0].size() == 1) mstruct.setUndefined();
			else mstruct.addChild(m_undefined);
		} else {
			if(vargs[0].size() == 1) mstruct.set(*history_answer[(size_t) index - 1]);
			else mstruct.addChild(*history_answer[(size_t) index - 1]);
		}
	}
	return 1;
}
ExpressionFunction::ExpressionFunction() : MathFunction(_("expression"), 1, 1, CALCULATOR->f_warning->category(), _("History Parsed Expression")) {
	if(strcmp(_("expression"), "expression")) addName("expression");
	VectorArgument *arg = new VectorArgument(_("History Index(es)"));
	arg->addArgument(new IntegerArgument("", ARGUMENT_MIN_MAX_NONZERO, true, true, INTEGER_TYPE_SINT));
	setArgumentDefinition(1, arg);
}
int ExpressionFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
	if(vargs[0].size() == 0) return 0;
	if(vargs[0].size() > 1) mstruct.clearVector();
	for(size_t i = 0; i < vargs[0].size(); i++) {
		int index = vargs[0][i].number().intValue();
		if(index < 0) index = (int) history_parsed.size() + 1 + index;
		if(index <= 0 || index > (int) history_parsed.size() || history_parsed[(size_t) index - 1] == NULL) {
			CALCULATOR->error(true, _("History index %s does not exist."), vargs[0][i].print().c_str(), NULL);
			if(vargs[0].size() == 1) mstruct.setUndefined();
			else mstruct.addChild(m_undefined);
		} else {
			if(vargs[0].size() == 1) mstruct.set(*history_parsed[(size_t) index - 1]);
			else mstruct.addChild(*history_parsed[(size_t) index - 1]);
		}
	}
	return 1;
}

void executeCommand(int command_type, bool show_result = true, string ceu_str = "", Unit *u = NULL, int run = 1);

extern int has_information_unit(const MathStructure &m, bool top = true);

string print_with_evalops(const Number &nr) {
	PrintOptions po;
	po.base = evalops.parse_options.base;
	po.base_display = BASE_DISPLAY_NONE;
	po.twos_complement = evalops.parse_options.twos_complement;
	Number nr_base;
	if(po.base == BASE_CUSTOM) {
		nr_base = CALCULATOR->customOutputBase();
		CALCULATOR->setCustomOutputBase(CALCULATOR->customInputBase());
	}
	if(po.base == BASE_CUSTOM && CALCULATOR->customInputBase().isInteger() && (CALCULATOR->customInputBase() > 1 || CALCULATOR->customInputBase() < -1)) {
		nr_base = CALCULATOR->customOutputBase();
		CALCULATOR->setCustomOutputBase(CALCULATOR->customInputBase());
	} else if((po.base < BASE_CUSTOM && po.base != BASE_UNICODE && po.base != BASE_BIJECTIVE_26) || (po.base == BASE_CUSTOM && CALCULATOR->customInputBase() <= 12 && CALCULATOR->customInputBase() >= -12)) {
		po.base = 10;
		string str = "dec(";
		str += nr.print(po);
		str += ")";
		return str;
	} else if(po.base == BASE_CUSTOM) {
		po.base = 10;
	}
	string str = nr.print(po);
	if(po.base == BASE_CUSTOM) CALCULATOR->setCustomOutputBase(nr_base);
	return str;
}

enum {
	COMMAND_FACTORIZE,
	COMMAND_EXPAND_PARTIAL_FRACTIONS,
	COMMAND_EXPAND,
	COMMAND_TRANSFORM,
	COMMAND_CONVERT_UNIT,
	COMMAND_CONVERT_STRING,
	COMMAND_CONVERT_BASE,
	COMMAND_CONVERT_OPTIMAL,
	COMMAND_CALCULATE,
	COMMAND_EVAL
};

void add_line_breaks(string &str, int expr = false, size_t first_i = 0);

bool equalsIgnoreCase(const string &str1, const string &str2, size_t i2, size_t i2_end, size_t minlength) {
	if(str1.empty() || str2.empty()) return false;
	size_t l = 0;
	if(i2_end == string::npos) i2_end = str2.length();
	for(size_t i1 = 0;; i1++, i2++) {
		if(i2 >= i2_end) {
			return i1 >= str1.length();
		}
		if(i1 >= str1.length()) break;
		if((str1[i1] < 0 && i1 + 1 < str1.length()) || (str2[i2] < 0 && i2 + 1 < str2.length())) {
			size_t iu1 = 1, iu2 = 1;
			if(str1[i1] < 0) {
				while(iu1 + i1 < str1.length() && str1[i1 + iu1] < 0) {
					iu1++;
				}
			}
			if(str2[i2] < 0) {
				while(iu2 + i2 < str2.length() && str2[i2 + iu2] < 0) {
					iu2++;
				}
			}
			bool isequal = (iu1 == iu2);
			if(isequal) {
				for(size_t i = 0; i < iu1; i++) {
					if(str1[i1 + i] != str2[i2 + i]) {
						isequal = false;
						break;
					}
				}
			}
			if(!isequal) {
				char *gstr1 = utf8_strdown(str1.c_str() + (sizeof(char) * i1), iu1);
				char *gstr2 = utf8_strdown(str2.c_str() + (sizeof(char) * i2), iu2);
				if(!gstr1 || !gstr2) return false;
				bool b = strcmp(gstr1, gstr2) == 0;
				free(gstr1);
				free(gstr2);
				if(!b) return false;
			}
			i1 += iu1 - 1;
			i2 += iu2 - 1;
		} else if(str1[i1] != str2[i2] && !((str1[i1] >= 'a' && str1[i1] <= 'z') && str1[i1] - 32 == str2[i2]) && !((str1[i1] <= 'Z' && str1[i1] >= 'A') && str1[i1] + 32 == str2[i2])) {
			return false;
		}
		l++;
	}
	return l >= minlength;
}

bool title_matches(ExpressionItem *item, const string &str, size_t minlength = 0) {
	const string &title = item->title(true);
	size_t i = 0;
	while(true) {
		while(true) {
			if(i >= title.length()) return false;
			if(title[i] != ' ') break;
			i++;
		}
		size_t i2 = title.find(' ', i);
		if(equalsIgnoreCase(str, title, i, i2, minlength)) {
			return true;
		}
		if(i2 == string::npos) break;
		i = i2 + 1;
	}
	return false;
}
bool name_matches(ExpressionItem *item, const string &str) {
	for(size_t i2 = 1; i2 <= item->countNames(); i2++) {
		if(item->getName(i2).case_sensitive) {
			if(str == item->getName(i2).name.substr(0, str.length())) {
				return true;
			}
		} else {
			if(equalsIgnoreCase(str, item->getName(i2).name, 0, str.length(), 0)) {
				return true;
			}
		}
	}
	return false;
}
bool country_matches(Unit *u, const string &str, size_t minlength = 0) {
	const string &countries = u->countries();
	size_t i = 0;
	while(true) {
		while(true) {
			if(i >= countries.length()) return false;
			if(countries[i] != ' ') break;
			i++;
		}
		size_t i2 = countries.find(',', i);
		if(equalsIgnoreCase(str, countries, i, i2, minlength)) {
			return true;
		}
		if(i2 == string::npos) break;
		i = i2 + 1;
	}
	return false;
}
bool completion_names_match(string name, const string &str, size_t minlength = 0) {
	size_t i = 0;
	while(true) {
		size_t i2 = name.find(i == 0 ? " <i>" : "</i>", i);
		if(equalsIgnoreCase(str, name, i, i2, minlength)) {
			return true;
		}
		if(i2 == string::npos) break;
		if(i == 0) {
			i = i2 + 4;
		} else {
			i = name.find("<i>", i2);
			if(i == string::npos) break;
			i += 3;
		}
	}
	return false;
}

void remove_separator(string &copy_text) {
	for(size_t i = ((CALCULATOR->local_digit_group_separator.empty() || CALCULATOR->local_digit_group_separator == " ") ? 1 : 0); i < 3; i++) {
		string str_sep;
		if(i == 0) str_sep = CALCULATOR->local_digit_group_separator;
		else if(i == 1) str_sep = " ";
		else str_sep = " ";
		size_t index = copy_text.find(str_sep);
		while(index != string::npos) {
			if(index > 0 && index + str_sep.length() < copy_text.length() && copy_text[index - 1] >= '0' && copy_text[index - 1] <= '9' && copy_text[index + str_sep.length()] >= '0' && copy_text[index + str_sep.length()] <= '9') {
				copy_text.erase(index, str_sep.length());
			} else {
				index++;
			}
			index = copy_text.find(str_sep, index);
		}
	}
}

void show_help(const char *file, GObject *parent) {
	string surl;
#ifdef _WIN32
	char exepath[MAX_PATH];
	GetModuleFileName(NULL, exepath, MAX_PATH);
	surl = "file://";
	surl += exepath;
	surl.resize(surl.find_last_of('\\'));
	if(surl.substr(surl.length() - 4) == "\\bin") {
		surl.resize(surl.find_last_of('\\'));
		surl += "\\share\\doc\\";
		surl += PACKAGE;
		surl += "\\html\\";
	} else if(surl.substr(surl.length() - 6) == "\\.libs") {
		surl.resize(surl.find_last_of('\\'));
		surl.resize(surl.find_last_of('\\'));
		surl += "\\doc\\html\\";
	} else {
		surl += "\\doc\\";
	}
	gsub("\\", "/", surl);
	surl += file;
	if(ShellExecuteA(NULL, "open", surl.c_str(), NULL, NULL, SW_SHOWNORMAL) <= (HINSTANCE) 32) {
		GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(parent), (GtkDialogFlags) 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("Could not display help for Qalculate!."));
		gtk_dialog_run(GTK_DIALOG(dialog));
		gtk_widget_destroy(dialog);
	}
#else
	GError *error = NULL;
	surl = "file://" PACKAGE_DOC_DIR "/html/";
	surl += file;
#	if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 22
	gtk_show_uri_on_window(GTK_WINDOW(parent), surl.c_str(), gtk_get_current_event_time(), &error);
#	else
	gtk_show_uri(NULL, surl.c_str(), gtk_get_current_event_time(), &error);
#	endif
	if(error) {
		gchar *error_str = g_locale_to_utf8(error->message, -1, NULL, NULL, NULL);
		GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(parent), (GtkDialogFlags) 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("Could not display help for Qalculate!.\n%s"), error_str);
		gtk_dialog_run(GTK_DIALOG(dialog));
		gtk_widget_destroy(dialog);
		g_free(error_str);
		g_error_free(error);
	}
#endif
}

void fix_history_string2(string &str) {
	gsub("&", "&amp;", str);
	gsub(">", "&gt;", str);
	gsub("<", "&lt;", str);
}
string fix_history_string(const string &str2) {
	string str = str2;
	gsub("&", "&amp;", str);
	gsub(">", "&gt;", str);
	gsub("<", "&lt;", str);
	return str;
}
void unfix_history_string(string &str) {
	gsub("&amp;", "&", str);
	gsub("&gt;", ">", str);
	gsub("&lt;", "<", str);
}
void replace_result_cis(string &resstr) {
	if(can_display_unicode_string_function_exact("∠", (void*) historyview)) gsub(" cis ", "∠", resstr);
}
void improve_result_text(string &resstr) {
	size_t i1 = 0, i2 = 0, i3 = 0, i_prev = 0;
	size_t i_equals = resstr.find(_("approx.")) + strlen(_("approx."));
	while(i_prev + 2 < resstr.length()) {
		i1 = resstr.find_first_of("\"\'", i_prev);
		if(i1 == string::npos) break;
		i2 = resstr.find(resstr[i1], i1 + 1);
		if(i2 == string::npos) break;
		if(i2 - i1 > 2) {
			if(!text_length_is_one(resstr.substr(i1 + 1, i2 - i1 - 1))) {
				i_prev = i2 + 1;
				continue;
			}
		}
		
		if(i1 > 1 && resstr[i1 - 1] == ' ' && (i_equals == string::npos || i1 != i_equals + 1) && (is_in(NUMBERS, resstr[i1 - 2]) || i1 == i_prev + 1)) {
			if(resstr[i1 - 2] < 0) {
				i3 = i1 - 2;
				while(i3 > 0 && resstr[i3] < 0 && (unsigned char) resstr[i3] < 0xC0) i3--;
				string str = resstr.substr(i3, i1 - i3 - 1);
				if(str != SIGN_DIVISION && str != SIGN_DIVISION_SLASH && str != SIGN_MULTIPLICATION && str != SIGN_MULTIDOT && str != SIGN_SMALLCIRCLE && str != SIGN_MULTIBULLET && str != SIGN_MINUS && str != SIGN_PLUS && str != SIGN_NOT_EQUAL && str != SIGN_GREATER_OR_EQUAL && str != SIGN_LESS_OR_EQUAL && str != SIGN_ALMOST_EQUAL && str != printops.comma()) {
					resstr.replace(i1 - 1, 2, "<i>");
					if(i_equals != string::npos && i1 < i_equals) i_equals += 1;
					i2 += 1;
				} else {
					resstr.replace(i1, 1, "<i>");
					if(i_equals != string::npos && i1 < i_equals) i_equals += 2;
					i2 += 2;
				}
			} else {
				resstr.replace(i1 - 1, 2, "<i>");
				if(i_equals != string::npos && i1 < i_equals) i_equals += 1;
				i2 += 1;
			}
		} else {
			resstr.replace(i1, 1, "<i>");
			if(i_equals != string::npos && i1 < i_equals) i_equals += 2;
			i2 += 2;
		}
		resstr.replace(i2, 1, "</i>");
		if(i_equals != string::npos && i1 < i_equals) i_equals += 3;
		i_prev = i2 + 4;
	}
	i1 = 1;
	while(i1 < resstr.length()) {
		i1 = resstr.find('_', i1);
		if(i1 == string::npos || i1 + 1 == resstr.length()) break;
		if(is_not_in(NOT_IN_NAMES, resstr[i1 + 1])) {
			i2 = resstr.find_last_of(NOT_IN_NAMES, i1 - 1);
			i3 = resstr.find_first_of(NOT_IN_NAMES, i1 + 1);
			if(i2 == string::npos) i2 = 0;
			else i2 = i2 + 1;
			if(i3 == string::npos) i3 = resstr.length();
			ExpressionItem *item = CALCULATOR->getActiveExpressionItem(resstr.substr(i2, i3 - i2));
			if(item) {
				i2 = item->hasName(resstr.substr(i2, i3 - i2), true);
				if(i2 > 0 && item->getName(i2).suffix) {
					i1 = resstr.rfind('_', i3 - 1);
					resstr.replace(i1, 1, "<sub>");
					i1 += 4;
					resstr.insert(i3 + 4, "</sub>");
					i1 += 6;
				} else {
					i1 = i3 - 1;
				}
			}
		}
		i1++;
	}
}


bool completion_blocked = false;
void block_completion() {
	gtk_widget_hide(completion_window);
	completion_blocked = true;
}
void unblock_completion() {
	completion_blocked = false;
}

string get_expression_text() {
	GtkTextIter istart, iend;
	gtk_text_buffer_get_start_iter(expressionbuffer, &istart);
	gtk_text_buffer_get_end_iter(expressionbuffer, &iend);
	gchar *gtext = gtk_text_buffer_get_text(expressionbuffer, &istart, &iend, FALSE);
	string text = gtext;
	g_free(gtext);
	return text;
}
string get_selected_expression_text(bool return_all_if_no_sel = false) {
	if(!gtk_text_buffer_get_has_selection(expressionbuffer)) {
		if(return_all_if_no_sel) {
			string str = get_expression_text();
			remove_blank_ends(str);
			return str;
		}
		return "";
	}
	GtkTextIter istart, iend;
	gtk_text_buffer_get_selection_bounds(expressionbuffer, &istart, &iend);
	gchar *gtext = gtk_text_buffer_get_text(expressionbuffer, &istart, &iend, FALSE);
	string text = gtext;
	g_free(gtext);
	return text;
}
void add_expression_to_undo() {
	if(expression_undo_buffer.size() > 100) expression_undo_buffer.pop_front();
	else undo_index++;
	while(undo_index < expression_undo_buffer.size()) {
		expression_undo_buffer.pop_back();
	}
	expression_undo_buffer.push_back(get_expression_text());
}

void overwrite_expression_selection(const gchar *text) {
	block_completion();
	add_to_undo = false;
	gtk_text_buffer_delete_selection(expressionbuffer, FALSE, TRUE);
	add_to_undo = true;
	if(text) gtk_text_buffer_insert_at_cursor(expressionbuffer, text, -1);
	unblock_completion();
}
void set_expression_text(const gchar *text) {
	bool b = add_to_undo;
	add_to_undo = false;
	gtk_text_buffer_set_text(expressionbuffer, text, -1);
	add_to_undo = b;
	if(add_to_undo) add_expression_to_undo();
}
void clear_expression_text() {
	gtk_text_buffer_set_text(expressionbuffer, "", -1);
}
bool expression_is_empty() {
	GtkTextIter istart;
	gtk_text_buffer_get_start_iter(expressionbuffer, &istart);
	return gtk_text_iter_is_end(&istart);
}
bool is_at_beginning_of_expression(bool allow_selection = false) {
	if(!allow_selection && gtk_text_buffer_get_has_selection(expressionbuffer)) return false;
	GtkTextIter ipos;
	gtk_text_buffer_get_iter_at_mark(expressionbuffer, &ipos, gtk_text_buffer_get_insert(expressionbuffer));
	return gtk_text_iter_is_start(&ipos);
}

void set_assumptions_items(AssumptionType, AssumptionSign);
void set_mode_items(const PrintOptions&, const EvaluationOptions&, AssumptionType, AssumptionSign, bool, int, bool, bool, bool, bool, bool, bool, bool);

string sdot, saltdot, sdiv, sslash, stimes, sminus;
string sdot_s, saltdot_s, sdiv_s, sslash_s, stimes_s, sminus_s;

void set_operator_symbols() {
	if(can_display_unicode_string_function_exact(SIGN_MINUS, (void*) expressiontext)) sminus = SIGN_MINUS;
	else sminus = "-";
	if(can_display_unicode_string_function(SIGN_DIVISION, (void*) expressiontext)) sdiv = SIGN_DIVISION;
	else sdiv = "/";
	sslash = "/";
	if(can_display_unicode_string_function(SIGN_MULTIDOT, (void*) expressiontext)) sdot = SIGN_MULTIDOT;
	else sdot = "*";
	if(can_display_unicode_string_function(SIGN_MIDDLEDOT, (void*) expressiontext)) saltdot = SIGN_MIDDLEDOT;
	else saltdot = "*";
	if(can_display_unicode_string_function(SIGN_MULTIPLICATION, (void*) expressiontext)) stimes = SIGN_MULTIPLICATION;
	else stimes = "*";
	
	if(can_display_unicode_string_function_exact(SIGN_MINUS, (void*) statuslabel_l)) sminus_s = SIGN_MINUS;
	else sminus_s = "-";
	if(can_display_unicode_string_function(SIGN_DIVISION, (void*) statuslabel_l)) sdiv_s = SIGN_DIVISION;
	else sdiv_s = "/";
	if(can_display_unicode_string_function_exact(SIGN_DIVISION, (void*) statuslabel_l)) sslash_s = SIGN_DIVISION_SLASH;
	else sslash_s = "/";
	if(can_display_unicode_string_function(SIGN_MULTIDOT, (void*) statuslabel_l)) sdot_s = SIGN_MULTIDOT;
	else sdot_s = "*";
	if(can_display_unicode_string_function(SIGN_MIDDLEDOT, (void*) statuslabel_l)) saltdot_s = SIGN_MIDDLEDOT;
	else saltdot_s = "*";
	if(can_display_unicode_string_function(SIGN_MULTIPLICATION, (void*) statuslabel_l)) stimes_s = SIGN_MULTIPLICATION;
	else stimes_s = "*";
}

const char *expression_add_sign() {
	return "+";
}
const char *expression_sub_sign() {
	if(!printops.use_unicode_signs) return "-";
	return sminus.c_str();
}
const char *expression_times_sign() {
	if(printops.use_unicode_signs && printops.multiplication_sign == MULTIPLICATION_SIGN_DOT) return sdot.c_str();
	else if(printops.use_unicode_signs && printops.multiplication_sign == MULTIPLICATION_SIGN_ALTDOT) return saltdot.c_str();
	else if(printops.use_unicode_signs && printops.multiplication_sign == MULTIPLICATION_SIGN_X) return stimes.c_str();
	return "*";
}
const char *expression_divide_sign() {
	if(!printops.use_unicode_signs) return "/";
	if(printops.division_sign == DIVISION_SIGN_DIVISION) return sdiv.c_str();
	return sslash.c_str();
}

#define EXPRESSION_STOP 1
#define EXPRESSION_SPINNER 2
#define EXPRESSION_INFO 3
void update_expression_icons(int id = 0) {
	switch(id) {
		case EXPRESSION_STOP: {
			gtk_stack_set_visible_child(GTK_STACK(gtk_builder_get_object(main_builder, "expression_button_stack")), GTK_WIDGET(gtk_builder_get_object(main_builder, "expression_button_stop")));
			gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(main_builder, "expression_button")), _("Stop process"));
			break;
		}
		case EXPRESSION_SPINNER: {
			gtk_stack_set_visible_child(GTK_STACK(gtk_builder_get_object(main_builder, "expression_button_stack")), GTK_WIDGET(gtk_builder_get_object(main_builder, "expressionspinner")));
			gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(main_builder, "expression_button")), _("Stop process"));
			break;
		}
		case EXPRESSION_INFO: {
			gtk_stack_set_visible_child(GTK_STACK(gtk_builder_get_object(main_builder, "expression_button_stack")), GTK_WIDGET(gtk_builder_get_object(main_builder, "message_tooltip_icon")));
			gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(main_builder, "expression_button")), gtk_widget_get_tooltip_text(GTK_WIDGET(gtk_builder_get_object(main_builder, "message_tooltip_icon"))));
			break;
		}
		default: {
			if(gtk_stack_get_visible_child(GTK_STACK(gtk_builder_get_object(main_builder, "expression_button_stack"))) != GTK_WIDGET(gtk_builder_get_object(main_builder, "expression_button_equals"))) {
				gtk_stack_set_visible_child(GTK_STACK(gtk_builder_get_object(main_builder, "expression_button_stack")), GTK_WIDGET(gtk_builder_get_object(main_builder, "expression_button_equals")));
				gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(main_builder, "expression_button")), rpn_mode ? _("Calculate expression and add to stack") : _("Calculate expression"));
			}
		}
	}
}

void result_font_modified() {
	while(gtk_events_pending()) gtk_main_iteration();
	set_result_size_request();
	result_font_updated = TRUE;
	set_operator_symbols();
	result_display_updated();
}
void expression_font_modified() {
	while(gtk_events_pending()) gtk_main_iteration();
	set_expression_size_request();
	set_operator_symbols();
	PangoLayout *layout_par = gtk_widget_create_pango_layout(expressiontext, "()");
	gint w1 = 0, w2 = 0;
	pango_layout_get_pixel_size(layout_par, &w1, NULL);
	pango_layout_set_markup(layout_par, "<b>()</b>", -1);
	pango_layout_get_pixel_size(layout_par, &w2, NULL);
	if(w1 == w2) g_object_set(expression_par_tag, "weight", PANGO_WEIGHT_BOLD, NULL);
	else g_object_set(expression_par_tag, "weight", PANGO_WEIGHT_NORMAL, NULL);
}

PangoCoverageLevel get_least_coverage(const gchar *gstr, GtkWidget *widget) {

	PangoCoverageLevel level = PANGO_COVERAGE_EXACT;
	PangoContext *context = gtk_widget_get_pango_context(widget);
	PangoLanguage *language = pango_context_get_language(context);
	PangoFontDescription *font_desc;
	gtk_style_context_get(gtk_widget_get_style_context(widget), GTK_STATE_FLAG_NORMAL, GTK_STYLE_PROPERTY_FONT, &font_desc, NULL);
	PangoFontset *fontset = pango_context_load_fontset(context, font_desc, language);
	pango_font_description_free(font_desc);
	while(gstr[0] != '\0') {
		if(gstr[0] < 0) {
			gunichar gu = g_utf8_get_char_validated(gstr, -1);
			if(gu != (gunichar) -1 && gu != (gunichar) -2) {
				PangoFont *font = pango_fontset_get_font(fontset, (guint) gu);
				if(font) {
					PangoCoverage *coverage = pango_font_get_coverage(font, language);
					if(pango_coverage_get(coverage, (int) gu) < level) {
						level = pango_coverage_get(coverage, gu);
					}
					g_object_unref(font);
					pango_coverage_unref(coverage);
				} else {
					level = PANGO_COVERAGE_NONE;
				}
			}
		}
		gstr = g_utf8_find_next_char(gstr, NULL);
		if(!gstr) break;
	}
	g_object_unref(fontset);
	return level;

}

bool can_display_unicode_string_function(const char *str, void *w) {
	if(!w) w = (void*) historyview;
	return get_least_coverage(str, (GtkWidget*) w) >= PANGO_COVERAGE_APPROXIMATE;
}
bool can_display_unicode_string_function_exact(const char *str, void *w) {
	if(!w) w = (void*) historyview;
	return get_least_coverage(str, (GtkWidget*) w) >= PANGO_COVERAGE_EXACT;
}

void set_result_size_request() {
	MathStructure mtest, mtest2;
	mtest.setType(STRUCT_DIVISION);
	mtest.addChild(1);
	mtest2.setType(STRUCT_POWER);
	mtest2.addChild(1);
	mtest2.addChild(1);
	mtest.addChild(mtest2);
	mtest.format();
	PrintOptions po;
	po.can_display_unicode_string_function = &can_display_unicode_string_function;
	po.can_display_unicode_string_arg = (void*) resultview;
	cairo_surface_t *tmp_surface2 = draw_structure(mtest, po);
	if(tmp_surface2) {
		cairo_surface_flush(tmp_surface2);
		int h = cairo_image_surface_get_height(tmp_surface2) / gtk_widget_get_scale_factor(resultview);
		h += 8;
		cairo_surface_destroy(tmp_surface2);
		gtk_widget_set_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "scrolled_result")), -1, h);
	}
}

void set_expression_size_request() {
	PangoLayout *layout_test = gtk_widget_create_pango_layout(expressiontext, "Äy\nÄy\nÄy");
	gint w, h;
	pango_layout_get_pixel_size(layout_test, &w, &h);
	gtk_widget_set_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "expressionscrolled")), -1, h + 12);
}

void set_unicode_buttons() {
	if(printops.use_unicode_signs) {
		if(can_display_unicode_string_function(SIGN_MINUS, (void*) gtk_builder_get_object(main_builder, "label_sub"))) gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "label_sub")), SIGN_MINUS);
		else gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "label_sub")), MINUS);
		if(can_display_unicode_string_function(SIGN_MULTIPLICATION, (void*) gtk_builder_get_object(main_builder, "label_times"))) gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "label_times")), SIGN_MULTIPLICATION);
		else gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "label_times")), MULTIPLICATION);
		if(can_display_unicode_string_function(SIGN_DIVISION_SLASH, (void*) gtk_builder_get_object(main_builder, "label_divide"))) gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "label_divide")), SIGN_DIVISION_SLASH);
		else if(can_display_unicode_string_function(SIGN_DIVISION, (void*) gtk_builder_get_object(main_builder, "label_divide"))) gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "label_divide")), SIGN_DIVISION);
		else gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "label_divide")), DIVISION);
		
		if(can_display_unicode_string_function(SIGN_MULTIPLICATION, (void*) gtk_builder_get_object(main_builder, "label_factorize"))) gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "label_factorize2")), "a" SIGN_MULTIPLICATION "b");
		else gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "label_factorize2")), "a" MULTIPLICATION "b");
		
		if(can_display_unicode_string_function(SIGN_MINUS, (void*) gtk_builder_get_object(main_builder, "label_history_sub"))) gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_history_sub")), SIGN_MINUS);
		else gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_history_sub")), MINUS);
		if(can_display_unicode_string_function(SIGN_MULTIPLICATION, (void*) gtk_builder_get_object(main_builder, "label_history_times"))) gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_history_times")), SIGN_MULTIPLICATION);
		else gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_history_times")), MULTIPLICATION);
		if(can_display_unicode_string_function(SIGN_DIVISION_SLASH, (void*) gtk_builder_get_object(main_builder, "label_history_divide"))) gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_history_divide")), SIGN_DIVISION_SLASH);
		else if(can_display_unicode_string_function(SIGN_DIVISION, (void*) gtk_builder_get_object(main_builder, "label_history_divide"))) gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_history_divide")), SIGN_DIVISION);
		else gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_history_divide")), DIVISION);
		
		if(can_display_unicode_string_function(SIGN_MINUS, (void*) gtk_builder_get_object(main_builder, "label_rpn_sub"))) gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_rpn_sub")), SIGN_MINUS);
		else gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_rpn_sub")), MINUS);
		if(can_display_unicode_string_function(SIGN_MULTIPLICATION, (void*) gtk_builder_get_object(main_builder, "label_rpn_times"))) gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_rpn_times")), SIGN_MULTIPLICATION);
		else gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_rpn_times")), MULTIPLICATION);
		if(can_display_unicode_string_function(SIGN_DIVISION_SLASH, (void*) gtk_builder_get_object(main_builder, "label_rpn_divide"))) gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_rpn_divide")), SIGN_DIVISION_SLASH);
		else if(can_display_unicode_string_function(SIGN_DIVISION, (void*) gtk_builder_get_object(main_builder, "label_rpn_divide"))) gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_rpn_divide")), SIGN_DIVISION);
		else gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_rpn_divide")), DIVISION);
		if(can_display_unicode_string_function(SIGN_MINUS, (void*) gtk_builder_get_object(main_builder, "label_rpn_negate"))) gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_rpn_negate")), SIGN_MINUS "x");
		else gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_rpn_negate")), MINUS "x");
		
		if(can_display_unicode_string_function(SIGN_SQRT, (void*) gtk_builder_get_object(main_builder, "label_sqrt"))) gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_sqrt")), SIGN_SQRT);
		else gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_sqrt")), "sqrt");
		if(can_display_unicode_string_function(SIGN_SQRT, (void*) gtk_builder_get_object(main_builder, "label_sqrt2"))) gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_sqrt2")), SIGN_SQRT);
		else gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_sqrt2")), "sqrt");
		if(can_display_unicode_string_function("x̄", (void*) gtk_builder_get_object(main_builder, "label_mean"))) gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "label_mean")), "x̄");
		else gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_mean")), "mean");
		if(can_display_unicode_string_function("∑", (void*) gtk_builder_get_object(main_builder, "label_sum"))) gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_sum")), "∑");
		else gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_sum")), "sum");
		if(can_display_unicode_string_function("π", (void*) gtk_builder_get_object(main_builder, "label_pi"))) gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_pi")), "π");
		else gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_pi")), "pi");
		
	} else {
		gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "label_sub")), MINUS);
		gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "label_times")), MULTIPLICATION);
		gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "label_divide")), DIVISION);
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_sqrt")), "sqrt");
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_sqrt2")), "sqrt");
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_mean")), "mean");
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_sum")), "sum");
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_pi")), "pi");
		gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "label_factorize2")), "a" MULTIPLICATION "b");
		
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_history_sub")), MINUS);
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_history_times")), MULTIPLICATION);
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_history_divide")), DIVISION);
		
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_rpn_sub")), MINUS);
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_rpn_times")), MULTIPLICATION);
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_rpn_divide")), DIVISION);
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_rpn_negate")), MINUS "x");
	}
	
	gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "label_dot")), CALCULATOR->getDecimalPoint().c_str());

#define SUP_STRING(X) string("<span size=\"x-small\" rise=\"" + i2s((int) (pango_font_description_get_size(font_desc) / 1.5)) + "\">") + string(X) + "</span>"
#define SUB_STRING(X) string("<span size=\"x-small\" rise=\"" + i2s((int) (-pango_font_description_get_size(font_desc) / 1.5)) + "\">") + string(X) + "</span>"

	PangoFontDescription *font_desc = NULL;
	gtk_style_context_get(gtk_widget_get_style_context(GTK_WIDGET(gtk_builder_get_object(main_builder, "label_history_xy"))), GTK_STATE_FLAG_NORMAL, GTK_STYLE_PROPERTY_FONT, &font_desc, NULL);
	gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "label_history_xy")), (string("x") + SUP_STRING("y")).c_str());
	pango_font_description_free(font_desc);
	gtk_style_context_get(gtk_widget_get_style_context(GTK_WIDGET(gtk_builder_get_object(main_builder, "label_rpn_xy"))), GTK_STATE_FLAG_NORMAL, GTK_STYLE_PROPERTY_FONT, &font_desc, NULL);
	gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "label_rpn_xy")), (string("x") + SUP_STRING("y")).c_str());
	pango_font_description_free(font_desc);
	gtk_style_context_get(gtk_widget_get_style_context(GTK_WIDGET(gtk_builder_get_object(main_builder, "label_xy"))), GTK_STATE_FLAG_NORMAL, GTK_STYLE_PROPERTY_FONT, &font_desc, NULL);
	gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "label_xy")), (string("x") + SUP_STRING("y")).c_str());
	if(evalops.structuring != STRUCTURING_FACTORIZE) {
		gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "label_factorize")), (string("a(x)") + SUP_STRING("b")).c_str());
		gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_factorize")), _("Factorize"));
	} else {
		gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "label_factorize")), (string("x+x") + SUP_STRING("b")).c_str());
		gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_factorize")), _("Expand"));
	}
	pango_font_description_free(font_desc);
	gtk_style_context_get(gtk_widget_get_style_context(GTK_WIDGET(gtk_builder_get_object(main_builder, "label_reciprocal"))), GTK_STATE_FLAG_NORMAL, GTK_STYLE_PROPERTY_FONT, &font_desc, NULL);
	if(printops.use_unicode_signs && can_display_unicode_string_function(SIGN_MINUS, (void*) gtk_builder_get_object(main_builder, "label_reciprocal"))) gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "label_reciprocal")), (string("x") + SUP_STRING(SIGN_MINUS "1")).c_str());
	else gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "label_reciprocal")), (string("x") + SUP_STRING("-1")).c_str());
	gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "label_log2")), (string("log") + SUB_STRING("2")).c_str());
	pango_font_description_free(font_desc);

	gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "label_comma")), CALCULATOR->getComma().c_str());
	if(can_display_unicode_string_function(SIGN_SQRT, (void*) gtk_builder_get_object(main_builder, "label_history_sqrt"))) gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_history_sqrt")), SIGN_SQRT);
	else gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_history_sqrt")), "sqrt");
	if(can_display_unicode_string_function(SIGN_SQRT, (void*) gtk_builder_get_object(main_builder, "label_rpn_sqrt"))) gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_rpn_sqrt")), SIGN_SQRT);
	else gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_rpn_sqrt")), "sqrt");
	if(can_display_unicode_string_function("∑", (void*) gtk_builder_get_object(main_builder, "label_rpn_sum"))) gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_rpn_sum")), "∑");
	else gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_rpn_sum")), "sum");

	GtkRequisition a;
	gint w, h;
	gtk_widget_get_preferred_size(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_reciprocal")), &a, NULL);
	w = a.width; h = a.height;
	gtk_widget_get_preferred_size(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_xy")), &a, NULL);
	if(a.width > w) w = a.width;
	if(a.height > h) h = a.height;
	gtk_widget_get_preferred_size(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_sqrt")), &a, NULL);
	if(a.width > w) w = a.width;
	if(a.height > h) h = a.height;
	gtk_widget_get_preferred_size(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_sum")), &a, NULL);
	if(a.width > w) w = a.width;
	if(a.height > h) h = a.height;
	gtk_widget_get_preferred_size(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_registerup")), &a, NULL);
	if(a.width > w) w = a.width;
	if(a.height > h) h = a.height;
	gtk_widget_set_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_registerup")), w, h);
	gtk_widget_set_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_copyregister")), w, h);
	gtk_widget_set_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_editregister")), w, h);
	gtk_widget_set_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_clearstack")), w, h);
	gtk_widget_set_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_add")), w, h);
	gtk_widget_set_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_sqrt")), w, h);
	gtk_widget_set_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_sum")), w, h);

}


bool string_is_less(string str1, string str2) {
	size_t i = 0;
	bool b_uni = false;
	while(i < str1.length() && i < str2.length()) {
		if(str1[i] == str2[i]) i++;
		else if(str1[i] < 0 || str2[i] < 0) {b_uni = true; break;}
		else return str1[i] < str2[i];
	}
	if(b_uni) return g_utf8_collate(str1.c_str(), str2.c_str()) < 0;
	return str1 < str2;
}

struct tree_struct {
	string item;
	list<tree_struct> items;
	list<tree_struct>::iterator it;
	list<tree_struct>::reverse_iterator rit;
	vector<void*> objects;	
	tree_struct *parent;
	void sort() {
		items.sort();
		for(list<tree_struct>::iterator it = items.begin(); it != items.end(); ++it) {
			it->sort();
		}
	}
	bool operator < (const tree_struct &s1) const {
		return string_is_less(item, s1.item);
	}	
};

tree_struct function_cats, unit_cats, variable_cats;
vector<void*> ia_units, ia_variables, ia_functions;	
vector<string> recent_functions_pre;
vector<string> recent_variables_pre;
vector<string> recent_units_pre;
vector<GtkWidget*> recent_function_items;
vector<GtkWidget*> recent_variable_items;
vector<GtkWidget*> recent_unit_items;
vector<MathFunction*> recent_functions;
vector<Variable*> recent_variables;
vector<Unit*> recent_units;
Unit *latest_button_unit = NULL, *latest_button_currency = NULL;
string latest_button_unit_pre, latest_button_currency_pre;

bool is_answer_variable(Variable *v) {
	return v == vans[0] || v == vans[1] || v == vans[2] || v == vans[3] || v == vans[4];
}

bool wrap_expression_selection(const char *insert_before = NULL, bool return_true_if_whole_selected = false) {
	if(!gtk_text_buffer_get_has_selection(expressionbuffer)) return false;
	GtkTextMark *mstart = gtk_text_buffer_get_selection_bound(expressionbuffer);
	if(!mstart) return false;
	GtkTextMark *mend = gtk_text_buffer_get_insert(expressionbuffer);
	if(!mend) return false;
	GtkTextIter istart, iend;
	gtk_text_buffer_get_iter_at_mark(expressionbuffer, &istart, mstart);
	gtk_text_buffer_get_iter_at_mark(expressionbuffer, &iend, mend);
	bool b_ret = (!return_true_if_whole_selected || (gtk_text_iter_is_start(&istart) && gtk_text_iter_is_end(&iend)) || (gtk_text_iter_is_start(&iend) && gtk_text_iter_is_end(&istart)));
	if(gtk_text_iter_compare(&istart, &iend) > 0) {
		add_to_undo = false;
		if(insert_before) gtk_text_buffer_insert(expressionbuffer, &iend, insert_before, -1);
		gtk_text_buffer_insert(expressionbuffer, &iend, "(", -1);
		gtk_text_buffer_get_iter_at_mark(expressionbuffer, &istart, mstart);
		add_to_undo = true;
		gtk_text_buffer_insert(expressionbuffer, &istart, ")", -1);
		gtk_text_buffer_place_cursor(expressionbuffer, &istart);
	} else {
		add_to_undo = false;
		if(insert_before) gtk_text_buffer_insert(expressionbuffer, &istart, insert_before, -1);
		gtk_text_buffer_insert(expressionbuffer, &istart, "(", -1);
		gtk_text_buffer_get_iter_at_mark(expressionbuffer, &iend, mend);
		add_to_undo = true;
		gtk_text_buffer_insert(expressionbuffer, &iend, ")", -1);
		gtk_text_buffer_place_cursor(expressionbuffer, &iend);
	}
	return b_ret;
}

void show_message(const gchar *text, GtkWidget *win) {
	GtkWidget *edialog = gtk_message_dialog_new(GTK_WINDOW(win), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", text);
	gtk_dialog_run(GTK_DIALOG(edialog));
	gtk_widget_destroy(edialog);
}
bool ask_question(const gchar *text, GtkWidget *win) {
	GtkWidget *edialog = gtk_message_dialog_new(GTK_WINDOW(win), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_YES_NO, "%s", text);
	int question_answer = gtk_dialog_run(GTK_DIALOG(edialog));
	gtk_widget_destroy(edialog);
	return question_answer == GTK_RESPONSE_YES;
}

#define STATUS_SPACE	if(b) str += "  "; else b = true;

void set_status_text(string text, bool break_begin = false, bool had_errors = false, bool had_warnings = false) {

	string str;
	if(had_errors) {
		str = "<span foreground=\"";
		str += status_error_color;
		str += "\">";
	} else if(had_warnings) {
		str = "<span foreground=\"";
		str += status_warning_color;
		str += "\">";
	}
	if(text.empty()) str += " ";
	else str += text;
	if(had_errors || had_warnings) str += "</span>";

	if(break_begin) gtk_label_set_ellipsize(GTK_LABEL(statuslabel_l), PANGO_ELLIPSIZE_START);
	else gtk_label_set_ellipsize(GTK_LABEL(statuslabel_l), PANGO_ELLIPSIZE_END);
	
	gtk_label_set_markup(GTK_LABEL(statuslabel_l), str.c_str());
	
}

void display_parse_status();

void update_status_text() {

	string str = "<span size=\"small\">";
	
	bool b = false;
	if(evalops.approximation == APPROXIMATION_EXACT) {
		STATUS_SPACE
		str += _("EXACT");
	} else if(evalops.approximation == APPROXIMATION_APPROXIMATE) {
		STATUS_SPACE
		str += _("APPROX");
	}
	if(evalops.parse_options.rpn) {
		STATUS_SPACE
		str += _("RPN");
	}
	switch(evalops.parse_options.base) {
		case BASE_DECIMAL: {
			break;
		}
		case BASE_BINARY: {
			STATUS_SPACE
			str += _("BIN");
			break;
		}
		case BASE_OCTAL: {
			STATUS_SPACE
			str += _("OCT");
			break;
		}
		case 12: {
			STATUS_SPACE
			str += _("DUO");
			break;
		}
		case BASE_HEXADECIMAL: {
			STATUS_SPACE
			str += _("HEX");
			break;
		}
		case BASE_ROMAN_NUMERALS: {
			STATUS_SPACE
			str += _("ROMAN");
			break;
		}
		case BASE_BIJECTIVE_26: {
			STATUS_SPACE
			str += "B26";
			break;
		}
		case BASE_CUSTOM: {
			STATUS_SPACE
			str += CALCULATOR->customInputBase().print(CALCULATOR->messagePrintOptions());
			break;
		}
		case BASE_GOLDEN_RATIO: {
			STATUS_SPACE
			str += "φ";
			break;
		}
		case BASE_SUPER_GOLDEN_RATIO: {
			STATUS_SPACE
			str += "ψ";
			break;
		}
		case BASE_PI: {
			STATUS_SPACE
			str += "π";
			break;
		}
		case BASE_E: {
			STATUS_SPACE
			str += "e";
			break;
		}
		case BASE_SQRT2: {
			STATUS_SPACE
			str += "√2";
			break;
		}
		case BASE_UNICODE: {
			STATUS_SPACE
			str += "UNICODE";
			break;
		}
		default: {
			STATUS_SPACE
			str += i2s(evalops.parse_options.base);
			break;
		}
	}
	switch (evalops.parse_options.angle_unit) {
		case ANGLE_UNIT_DEGREES: {
			STATUS_SPACE
			str += _("DEG");
			break;
		}
		case ANGLE_UNIT_RADIANS: {
			STATUS_SPACE
			str += _("RAD");
			break;
		}
		case ANGLE_UNIT_GRADIANS: {
			STATUS_SPACE
			str += _("GRA");
			break;
		}
		default: {}
	}
	if(evalops.parse_options.read_precision != DONT_READ_PRECISION) {
		STATUS_SPACE
		str += _("PREC");
	}
	if(!evalops.parse_options.functions_enabled) {
		STATUS_SPACE
		str += "<s>";
		str += _("FUNC");
		str += "</s>";
	}
	if(!evalops.parse_options.units_enabled) {
		STATUS_SPACE
		str += "<s>";
		str += _("UNIT");
		str += "</s>";
	}
	if(!evalops.parse_options.variables_enabled) {
		STATUS_SPACE
		str += "<s>";
		str += _("VAR");
		str += "</s>";
	}
	if(!evalops.allow_infinite) {
		STATUS_SPACE
		str += "<s>";
		str += _("INF");
		str += "</s>";
	}
	if(!evalops.allow_complex) {
		STATUS_SPACE
		str += "<s>";
		str += _("CPLX");
		str += "</s>";
	}

	remove_blank_ends(str);
	if(!b) str += " ";
	
	str += "</span>";

	if(str != gtk_label_get_label(GTK_LABEL(statuslabel_r))) {
		gtk_label_set_text(GTK_LABEL(statuslabel_l), "");	
		gtk_label_set_markup(GTK_LABEL(statuslabel_r), str.c_str());	
		display_parse_status();
	}
	
}

bool check_exchange_rates(GtkWidget *win = NULL, bool set_result = false) {
	int i = CALCULATOR->exchangeRatesUsed();
	if(i == 0) return false;
	if(auto_update_exchange_rates == 0 && win != NULL) return false;
	if(CALCULATOR->checkExchangeRatesDate(auto_update_exchange_rates > 0 ? auto_update_exchange_rates : 7, false, auto_update_exchange_rates == 0, i)) return false;
	if(auto_update_exchange_rates == 0) return false;
	bool b = false;
	if(auto_update_exchange_rates < 0) {
		GtkWidget *edialog = gtk_message_dialog_new(win == NULL ? GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")) : GTK_WINDOW(win), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING, GTK_BUTTONS_YES_NO, _("Do you wish to update the exchange rates now?"));
		gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(edialog), _("It has been %s day(s) since the exchange rates last were updated."), i2s((int) floor(difftime(time(NULL), CALCULATOR->getExchangeRatesTime(i)) / 86400)).c_str());
		GtkWidget *w = gtk_check_button_new_with_label(_("Do not ask again"));
		gtk_container_add(GTK_CONTAINER(gtk_message_dialog_get_message_area(GTK_MESSAGE_DIALOG(edialog))), w);
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), FALSE);
		gtk_widget_show(w);
		switch(gtk_dialog_run(GTK_DIALOG(edialog))) {
			case GTK_RESPONSE_YES: {
				b = true;
				if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) {
					auto_update_exchange_rates = 7;
				}
				break;
			}
			case GTK_RESPONSE_NO: {
				if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) {
					auto_update_exchange_rates = 0;
				}
				break;
			}
			default: {}
		}
		gtk_widget_destroy(edialog);
	}
	if(b || auto_update_exchange_rates > 0) {
		if(auto_update_exchange_rates <= 0) i = -1;
		if(!b && set_result) setResult(NULL, false, false, false, "", 0, false);
		fetch_exchange_rates(b ? 15 : 8, i);
		CALCULATOR->loadExchangeRates();
		return true;
	}
	return false;
}

/*
	display errors generated under calculation
*/
void display_errors(int *history_index_p = NULL, GtkWidget *win = NULL, int *inhistory_index = NULL, int type = 0) {
	if(!CALCULATOR->message()) return;
	int index = 0;
	MessageType mtype, mtype_highest = MESSAGE_INFORMATION;
	string str = "";
	GtkTreeIter history_iter;
	int inhistory_added = 0;
	while(true) {
		mtype = CALCULATOR->message()->type();
		if(mtype == MESSAGE_INFORMATION && (type == 1 || type == 2) && win && CALCULATOR->message()->message().find("-------------------------------------\n") == 0) {
			GtkWidget *edialog = gtk_message_dialog_new(GTK_WINDOW(win),GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, "%s", CALCULATOR->message()->message().c_str());
			gtk_dialog_run(GTK_DIALOG(edialog));
			gtk_widget_destroy(edialog);
		} else {
			if(index > 0) {
				if(index == 1) str = "• " + str;
				str += "\n• ";
			}
			str += CALCULATOR->message()->message();
			if(mtype == MESSAGE_ERROR || (mtype_highest != MESSAGE_ERROR && mtype == MESSAGE_WARNING)) {
				mtype_highest = mtype;
			}
			if((mtype == MESSAGE_ERROR || mtype == MESSAGE_WARNING) && history_index_p && inhistory_index) {
				if(mtype == MESSAGE_ERROR) {
					inhistory.insert(inhistory.begin() + *inhistory_index, CALCULATOR->message()->message());
					inhistory_type.insert(inhistory_type.begin() + *inhistory_index, QALCULATE_HISTORY_ERROR);
					inhistory_protected.insert(inhistory_protected.begin() + *inhistory_index, false);
					inhistory_value.insert(inhistory_value.begin() + *inhistory_index, nr_of_new_expressions);
					string history_message = "- ";
					history_message += CALCULATOR->message()->message();
					add_line_breaks(history_message, false, 2);
					string history_str = "<span foreground=\"";
					history_str += history_error_color;
					history_str += "\">";
					history_str += fix_history_string(history_message);
					history_str += "</span>";
					(*history_index_p)++;
					gtk_list_store_insert_with_values(historystore, &history_iter, *history_index_p, 0, history_str.c_str(), 1, *inhistory_index, 3, nr_of_new_expressions, 4, 0, 5, 6, 6, 0.0, 7, PANGO_ALIGN_LEFT, -1);
				} else if(mtype == MESSAGE_WARNING) {
					inhistory.insert(inhistory.begin() + *inhistory_index, CALCULATOR->message()->message());
					inhistory_type.insert(inhistory_type.begin() + *inhistory_index, QALCULATE_HISTORY_WARNING);
					inhistory_protected.insert(inhistory_protected.begin() + *inhistory_index, false);
					inhistory_value.insert(inhistory_value.begin() + *inhistory_index, nr_of_new_expressions);
					string history_message = "- ";
					history_message += CALCULATOR->message()->message();
					add_line_breaks(history_message, false, 2);
					string history_str = "<span foreground=\"";
					history_str += history_warning_color;
					history_str += "\">";
					history_str += fix_history_string(history_message);
					history_str += "</span>";
					(*history_index_p)++;
					gtk_list_store_insert_with_values(historystore, &history_iter, *history_index_p, 0, history_str.c_str(), 1, *inhistory_index, 3, nr_of_new_expressions, 4, 0, 5, 6, 6, 0.0, 7, PANGO_ALIGN_LEFT, -1);
				}
				inhistory_added++;
			}
		}
		index++;
		if(!CALCULATOR->nextMessage()) break;
	}
	if(inhistory_added > 0) {
		GtkTreeIter index_iter = history_iter;
		gint index_hi = -1;
		gint hi_add = 1;
		while(gtk_tree_model_iter_previous(GTK_TREE_MODEL(historystore), &index_iter)) {
			gtk_tree_model_get(GTK_TREE_MODEL(historystore), &index_iter, 1, &index_hi, -1);
			if(index_hi >= 0) {
				gtk_list_store_set(historystore, &index_iter, 1, index_hi + hi_add, -1);
				if(inhistory_added > 1) {
					inhistory_added--;
					hi_add++;
				}
			}
		}
	}
	if(!str.empty()) {
		if(type == 1) {
			gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(main_builder, "message_tooltip_icon")), str.c_str());
			if(mtype_highest == MESSAGE_ERROR) {
				gtk_image_set_from_icon_name(GTK_IMAGE(gtk_builder_get_object(main_builder, "message_tooltip_icon")), "dialog-error", GTK_ICON_SIZE_BUTTON);
			} else if(mtype_highest == MESSAGE_WARNING) {
				gtk_image_set_from_icon_name(GTK_IMAGE(gtk_builder_get_object(main_builder, "message_tooltip_icon")), "dialog-warning", GTK_ICON_SIZE_BUTTON);
			} else {
				gtk_image_set_from_icon_name(GTK_IMAGE(gtk_builder_get_object(main_builder, "message_tooltip_icon")), "dialog-information", GTK_ICON_SIZE_BUTTON);
			}
			update_expression_icons(EXPRESSION_INFO);
			if(first_error) {
				gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "message_label")), _("When errors, warnings and other information are generated during calculation the button to the right of the expression entry changes to reflect this. If you hold the pointer over or click the button, the message will be shown."));
				gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "message_icon")));
				gtk_info_bar_set_message_type(GTK_INFO_BAR(gtk_builder_get_object(main_builder, "message_bar")), GTK_MESSAGE_INFO);
				gtk_info_bar_set_show_close_button(GTK_INFO_BAR(gtk_builder_get_object(main_builder, "message_bar")), TRUE);
				gtk_revealer_set_reveal_child(GTK_REVEALER(gtk_builder_get_object(main_builder, "message_revealer")), TRUE);
				first_error = FALSE;
			}
		} else if(type == 2) {
			gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "message_label")), str.c_str());
			gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(main_builder, "message_icon")));
			if(mtype_highest == MESSAGE_ERROR) {
				gtk_info_bar_set_message_type(GTK_INFO_BAR(gtk_builder_get_object(main_builder, "message_bar")), GTK_MESSAGE_ERROR);				
				gtk_image_set_from_icon_name(GTK_IMAGE(gtk_builder_get_object(main_builder, "message_icon")), "dialog-error-symbolic", GTK_ICON_SIZE_BUTTON);
			} else if(mtype_highest == MESSAGE_WARNING) {
				gtk_info_bar_set_message_type(GTK_INFO_BAR(gtk_builder_get_object(main_builder, "message_bar")), GTK_MESSAGE_WARNING);
				gtk_image_set_from_icon_name(GTK_IMAGE(gtk_builder_get_object(main_builder, "message_icon")), "dialog-warning-symbolic", GTK_ICON_SIZE_BUTTON);
			} else {
				gtk_info_bar_set_message_type(GTK_INFO_BAR(gtk_builder_get_object(main_builder, "message_bar")), GTK_MESSAGE_INFO);
				gtk_image_set_from_icon_name(GTK_IMAGE(gtk_builder_get_object(main_builder, "message_icon")), "dialog-information-symbolic", GTK_ICON_SIZE_BUTTON);
			}
			gtk_info_bar_set_show_close_button(GTK_INFO_BAR(gtk_builder_get_object(main_builder, "message_bar")), TRUE);
			/*gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "message_yes_button")));
			gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "message_no_button")));*/
			gtk_revealer_set_reveal_child(GTK_REVEALER(gtk_builder_get_object(main_builder, "message_revealer")), TRUE);
		} else if(mtype_highest != MESSAGE_INFORMATION) {
			GtkWidget *edialog = gtk_message_dialog_new(GTK_WINDOW(win),GTK_DIALOG_DESTROY_WITH_PARENT, mtype_highest == MESSAGE_ERROR ? GTK_MESSAGE_ERROR : (mtype_highest == MESSAGE_WARNING ? GTK_MESSAGE_WARNING : GTK_MESSAGE_INFO), GTK_BUTTONS_CLOSE, "%s", str.c_str());
			gtk_dialog_run(GTK_DIALOG(edialog));
			gtk_widget_destroy(edialog);
		}

	}
}

extern GtkCellRenderer *history_renderer;
extern gint history_scroll_width;

void on_history_resize(GtkWidget*, GdkRectangle *alloc, gpointer) {
	gint hsep = 0;
	gtk_widget_style_get(historyview, "horizontal-separator", &hsep, NULL);
	int prev_hw = history_width_a;
	history_width_a = alloc->width - gtk_tree_view_column_get_width(history_index_column) - hsep * 4;
	PangoLayout *layout = gtk_widget_create_pango_layout(historyview, "");
	if(can_display_unicode_string_function_exact("🔒", historyview)) pango_layout_set_markup(layout, "<span size=\"small\"><sup> 🔒</sup></span>", -1);
	else pango_layout_set_markup(layout, "<span size=\"x-small\"><sup> P</sup></span>", -1);
	gint w = 0;
	pango_layout_get_pixel_size(layout, &w, NULL);
	g_object_unref(layout);
	history_width_e = history_width_a - 6 - history_scroll_width - w;
	history_width_a -= history_scroll_width * 2;
	if(prev_hw != history_width_a) {
		gtk_tree_view_column_set_max_width(history_column, history_width_a + history_scroll_width * 2);
		reload_history();
	}
}

gboolean on_display_errors_timeout(gpointer) {
	if(stop_timeouts) return false;
	if(!do_timeout) return true;
	if(CALCULATOR->checkSaveFunctionCalled()) {
		update_vmenu();
	}
	display_errors();
	return true;
}

gboolean on_activate_link(GtkLabel*, gchar *uri, gpointer) {
#ifdef _WIN32
	ShellExecuteA(NULL, "open", uri, NULL, NULL, SW_SHOWNORMAL);
	return TRUE;
#else
	return FALSE;
#endif
}

gboolean on_check_version_idle(gpointer) {
	string new_version;
#ifdef _WIN32
	int ret = checkAvailableVersion("windows", VERSION, &new_version, 5);
#else
	int ret = checkAvailableVersion("qalculate-gtk", VERSION, &new_version, 5);
#endif
	if(ret > 0 && new_version != last_found_version) {
		last_found_version = new_version;
		GtkWidget *dialog = gtk_dialog_new_with_buttons(NULL, GTK_WINDOW(mainwindow), (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT), _("_Close"), GTK_RESPONSE_REJECT, NULL);
		gtk_container_set_border_width(GTK_CONTAINER(dialog), 5);
		GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
		gtk_container_set_border_width(GTK_CONTAINER(hbox), 12);
		gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), hbox);
		GtkWidget *label = gtk_label_new(NULL);
		gchar *gstr = g_strdup_printf(_("A new version of %s is available.\n\nYou can get version %s at %s."), "Qalculate!", new_version.c_str(), "<a href=\"http://qalculate.github.io/downloads.html\">qalculate.github.io</a>");
		gtk_label_set_markup(GTK_LABEL(label), gstr);
		g_free(gstr);
		gtk_container_add(GTK_CONTAINER(hbox), label);
		g_signal_connect(G_OBJECT(label), "activate-link", G_CALLBACK(on_activate_link), NULL);
		gtk_widget_show_all(dialog);
		gtk_dialog_run(GTK_DIALOG(dialog));
		gtk_widget_destroy(dialog);
	}
	last_version_check_date.setToCurrentDate();
	return FALSE;
}

bool display_function_hint(MathFunction *f, int arg_index = 1) {
	if(!f) return false;
	int iargs = f->maxargs();
	Argument *arg;
	Argument default_arg;
	string str, str2, str3;
	const ExpressionName *ename = &f->preferredName(false, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) statuslabel_l);
	bool last_is_vctr = f->getArgumentDefinition(iargs) && f->getArgumentDefinition(iargs)->type() == ARGUMENT_TYPE_VECTOR;
	if(arg_index > iargs && iargs >= 0 && !last_is_vctr) {
		if(iargs == 1 && f->getArgumentDefinition(1) && f->getArgumentDefinition(1)->handlesVector()) {
			return false;
		}
		gchar *gstr = g_strdup_printf(_("Too many arguments for %s()."), ename->name.c_str());
		set_status_text(gstr, false, false, true);
		g_free(gstr);
		return true;
	}
	str += ename->name;		
	if(iargs < 0) {
		iargs = f->minargs() + 1;
		if(arg_index > iargs) arg_index = iargs;
	}
	if(arg_index > iargs && last_is_vctr) arg_index = iargs;
	str += "(";
	int i_reduced = 0;
	if(iargs != 0) {
		for(int i2 = 1; i2 <= iargs; i2++) {
			if(i2 > f->minargs() && arg_index < i2) {
				str += "[";
			}
			if(i2 > 1) {
				str += CALCULATOR->getComma();
				str += " ";
			}
			if(i2 == arg_index) str += "<b>";
			arg = f->getArgumentDefinition(i2);
			if(arg && !arg->name().empty()) {
				str2 = arg->name();
			} else {
				str2 = _("argument");
				str2 += " ";
				str2 += i2s(i2);
			}
			if(i2 == arg_index) {
				if(arg) {
					if(i_reduced == 2) str3 = arg->print();
					else str3 = arg->printlong();
				} else {
					Argument arg_default;
					if(i_reduced == 2) str3 = arg_default.print();
					else str3 = arg_default.printlong();
				}
				if(!str3.empty()) {
					str2 += ": ";
					str2 += str3;
				}
				gsub("&", "&amp;", str2);
				gsub(">", "&gt;", str2);
				gsub("<", "&lt;", str2);
				str += str2;					
				str += "</b>";
				if(i_reduced < 2) {
					PangoLayout *layout_test = gtk_widget_create_pango_layout(statuslabel_l, NULL);
					pango_layout_set_markup(layout_test, str.c_str(), -1);
					gint w, h;
					pango_layout_get_pixel_size(layout_test, &w, &h);
					if(w > gtk_widget_get_allocated_width(statuslabel_l) - 20) {
						str = ename->name;	
						str += "(";
						if(i2 != 1) {
							str += "…";
							i_reduced++;
						} else {
							i_reduced = 2;
						}
						i2--;
					}
					g_object_unref(layout_test);	
				} else {
					i_reduced = 0;
				}
			} else {
				gsub("&", "&amp;", str2);
				gsub(">", "&gt;", str2);
				gsub("<", "&lt;", str2);
				str += str2;
				if(i2 > f->minargs() && arg_index < i2) {
					str += "]";
				}
			}
		}
		if(f->maxargs() < 0) {
			str += CALCULATOR->getComma();
			str += " …";
		}
	}
	str += ")";
	set_status_text(str);
	return true;
}

void replace_interval_with_function(MathStructure &m);
void clearresult();
void update_result_bases();

bool last_is_operator(string str, bool allow_exp = false) {
	remove_blank_ends(str);
	if(str.empty()) return false;
	if(str[str.length() - 1] > 0) {
		if(is_in(OPERATORS LEFT_PARENTHESIS LEFT_VECTOR_WRAP, str[str.length() - 1]) && (str[str.length() - 1] != '!' || str.length() == 1)) return true;
		if(allow_exp && is_in(EXP, str[str.length() - 1])) return true;
		if(str.length() >= 3 && str[str.length() - 1] == 'r' && str[str.length() - 2] == 'o' && str[str.length() - 3] == 'x') return true;
	} else { 
		if(str.length() >= 3 && str[str.length() - 2] < 0) {
			str = str.substr(str.length() - 3);
			if(str == "∧" || str == "∨" || str == "⊻" || str == "≤" || str == "≥" || str == "≠" || str == "∠" || str == expression_times_sign() || str == expression_divide_sign() || str == expression_add_sign() || str == expression_sub_sign()) {
				return true;
			}
		}
		if(str.length() >= 2) {
			str = str.substr(str.length() - 2);
			if(str == "¬" || str == expression_times_sign() || str == expression_divide_sign() || str == expression_add_sign() || str == expression_sub_sign()) return true;
		}
	}
	return false;
}

void add_to_expression_history(string str);
gint autocalc_history_timeout_id = 0;
vector<CalculatorMessage> autocalc_messages;
gboolean do_autocalc_history_timeout(gpointer) {
	autocalc_history_timeout_id = 0;
	if(!do_timeout || !result_autocalculated || rpn_mode) return false;
	if(check_exchange_rates(NULL, true)) {
		execute_expression(true, false, OPERATION_ADD, NULL, false, 0, "", "", false);
		return false;
	}
	CALCULATOR->addMessages(&autocalc_messages);
	result_text = get_expression_text();
	add_to_expression_history(result_text);
	expression_has_changed = false;
	setResult(NULL, true, true, true, "", 0);
	if(!block_conversion_category_switch) {
		Unit *u = CALCULATOR->findMatchingUnit(*mstruct);
		if(u && !u->category().empty()) {
			string s_cat = u->category();
			if(s_cat.empty()) s_cat = _("Uncategorized");
			if(s_cat != selected_unit_category) {
				GtkTreeIter iter = convert_category_map[s_cat];
				GtkTreePath *path = gtk_tree_model_get_path(gtk_tree_view_get_model(GTK_TREE_VIEW(tUnitSelectorCategories)), &iter);
				gtk_tree_view_expand_to_path(GTK_TREE_VIEW(tUnitSelectorCategories), path);
				gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(tUnitSelectorCategories), path, NULL, TRUE, 0.5, 0);
				gtk_tree_path_free(path);
				gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitSelectorCategories)), &iter);
			}
		}
		if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "convert_button_continuous_conversion")))) {
			gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitSelector)));
		}
	}
	result_autocalculated = false;
	return false;
}

bool auto_calc_stopped_at_operator = false;

void do_auto_calc(bool recalculate = true, string str = string()) {
	if(block_result_update || block_expression_execution) return;
	MathStructure mauto;
	bool do_factors = false, do_pfe = false, do_expand = false, do_conv = false;
	bool do_timeout_bak = do_timeout;
	if(recalculate) {
		auto_calc_stopped_at_operator = false;
		if(autocalc_history_timeout_id != 0) {
			g_source_remove(autocalc_history_timeout_id);
			autocalc_history_timeout_id = 0;
		}
		bool origstr = str.empty();
		if(origstr) str = get_expression_text();
		if(str.empty()) {clearresult(); return;}
		
		if(evalops.parse_options.base != BASE_UNICODE && (evalops.parse_options.base != BASE_CUSTOM || (CALCULATOR->customInputBase() <= 62 && CALCULATOR->customInputBase() >= -62))) {
			if(last_is_operator(str, evalops.parse_options.base == 10) && (evalops.parse_options.base != BASE_ROMAN_NUMERALS || str[str.length() - 1] != '|' || str.find('|') == str.length() - 1)) return;
			GtkTextMark *mark = gtk_text_buffer_get_insert(expressionbuffer);
			if(mark) {
				GtkTextIter ipos;
				gtk_text_buffer_get_iter_at_mark(expressionbuffer, &ipos, mark);
				if(!gtk_text_iter_is_end(&ipos)) {
					GtkTextIter iter = ipos;
					gtk_text_iter_forward_char(&iter);
					gchar *gstr = gtk_text_buffer_get_text(expressionbuffer, &ipos, &iter, FALSE);
					string c2 = gstr;
					g_free(gstr);
					string c1;
					if(!gtk_text_iter_is_start(&ipos)) {
						iter = ipos;
						gtk_text_iter_backward_char(&iter);
						gstr = gtk_text_buffer_get_text(expressionbuffer, &iter, &ipos, FALSE);
						c1 = gstr;
						g_free(gstr);
					}
					if((c2.length() == 1 && is_in("*/^|&<>=)]", c2[0]) && (c2[0] != '|' || evalops.parse_options.base != BASE_ROMAN_NUMERALS)) || (c2.length() > 1 && (c2 == "∧" || c2 == "∨" || c2 == "⊻" || c2 == expression_times_sign() || c2 == expression_divide_sign() || c2 == SIGN_NOT_EQUAL || c2 == SIGN_GREATER_OR_EQUAL || c2 == SIGN_LESS_OR_EQUAL))) {
						if(c1.empty() || (c1.length() == 1 && is_in(OPERATORS LEFT_PARENTHESIS, c1[0]) && c1[0] != '!' && (c1[0] != '|' || (evalops.parse_options.base != BASE_ROMAN_NUMERALS && c1 != "|")) && (c1[0] != '&' || c2 != "&") && (c1[0] != '/' || (c2 != "/" && c2 != expression_divide_sign())) && (c1[0] != '*' || (c2 != "*" && c2 != expression_times_sign())) && ((c1[0] != '>' && c1[0] != '<') || (c2 != "=" && c2 != c1)) && ((c2 != ">" && c2 == "<") || (c1[0] != '=' && c1 != c2))) || (c1.length() > 1 && (c1 == "∧" || c1 == "∨" || c1 == "⊻" || c1 == SIGN_NOT_EQUAL || c1 == SIGN_GREATER_OR_EQUAL || c1 == SIGN_LESS_OR_EQUAL || (c1 == expression_times_sign() && c2 != "*" && c2 != expression_times_sign()) || (c1 == expression_divide_sign() && c2 != "/" && c2 != expression_divide_sign()) || c1 == expression_add_sign() || c1 == expression_sub_sign()))) {
							auto_calc_stopped_at_operator = true;
							return;
						}
					}
				}
			}
			
		}
		if(origstr) {
			to_fraction = false; to_prefix = 0; to_base = 0; to_nbase.clear();
		}
		string from_str = str, to_str;
		if(origstr && CALCULATOR->separateToExpression(from_str, to_str, evalops, true, true)) {
			if(from_str.empty()) {clearresult(); return;}
			remove_duplicate_blanks(to_str);
			string to_str1, to_str2;
			size_t ispace = to_str.find_first_of(SPACES);
			if(ispace != string::npos) {
				to_str1 = to_str.substr(0, ispace);
				remove_blank_ends(to_str1);
				to_str2 = to_str.substr(ispace + 1);
				remove_blank_ends(to_str2);
			}
			bool do_to = false;
			if(equalsIgnoreCase(to_str, "hex") || equalsIgnoreCase(to_str, "hexadecimal") || equalsIgnoreCase(to_str, _("hexadecimal"))) {
				to_base = BASE_HEXADECIMAL;
				do_to = true;
			} else if(equalsIgnoreCase(to_str, "oct") || equalsIgnoreCase(to_str, "octal") || equalsIgnoreCase(to_str, _("octal"))) {
				to_base = BASE_OCTAL;
				do_to = true;
			} else if(equalsIgnoreCase(to_str, "dec") || equalsIgnoreCase(to_str, "decimal") || equalsIgnoreCase(to_str, _("decimal"))) {
				to_base = BASE_DECIMAL;
				do_to = true;
			} else if(equalsIgnoreCase(to_str, "duo") || equalsIgnoreCase(to_str, "duodecimal") || equalsIgnoreCase(to_str, _("duodecimal"))) {
				to_base = BASE_DUODECIMAL;
				do_to = true;
			} else if(equalsIgnoreCase(to_str, "bin") || equalsIgnoreCase(to_str, "binary") || equalsIgnoreCase(to_str, _("binary"))) {
				to_base = BASE_BINARY;
				do_to = true;
			} else if(equalsIgnoreCase(to_str, "roman") || equalsIgnoreCase(to_str, _("roman"))) {
				to_base = BASE_ROMAN_NUMERALS;
				do_to = true;
			} else if(equalsIgnoreCase(to_str, "bijective") || equalsIgnoreCase(to_str, _("bijective"))) {
				to_base = BASE_BIJECTIVE_26;
				do_to = true;
			} else if(equalsIgnoreCase(to_str, "sexa") || equalsIgnoreCase(to_str, "sexagesimal") || equalsIgnoreCase(to_str, _("sexagesimal"))) {
				to_base = BASE_SEXAGESIMAL;
				do_to = true;
			} else if(equalsIgnoreCase(to_str, "time") || equalsIgnoreCase(to_str, _("time"))) {
				to_base = BASE_TIME;
				do_to = true;
			} else if(equalsIgnoreCase(to_str, "Unicode")) {
				to_base = BASE_UNICODE;
				do_to = true;
			} else if(equalsIgnoreCase(to_str, "utc") || equalsIgnoreCase(to_str, "gmt")) {
				printops.time_zone = TIME_ZONE_UTC;
				do_auto_calc(true, from_str);
				printops.time_zone = TIME_ZONE_LOCAL;
				return;
			} else if(to_str.length() > 3 && (equalsIgnoreCase(to_str.substr(0, 3), "utc") || equalsIgnoreCase(to_str.substr(0, 3), "gmt"))) {
				to_str = to_str.substr(3);
				remove_blanks(to_str);
				bool b_minus = false;
				if(to_str[0] == '+') {
					to_str.erase(0, 1);
				} else if(to_str[0] == '-') {
					b_minus = true;
					to_str.erase(0, 1);
				} else if(to_str.find(SIGN_MINUS) == 0) {
					b_minus = true;
					to_str.erase(0, strlen(SIGN_MINUS));
				}
				unsigned int tzh = 0, tzm = 0;
				int itz = 0;
				if(!to_str.empty() && sscanf(to_str.c_str(), "%2u:%2u", &tzh, &tzm) > 0) {
					itz = tzh * 60 + tzm;
					if(b_minus) itz = -itz;
				}
				printops.time_zone = TIME_ZONE_CUSTOM;
				printops.custom_time_zone = itz;
				do_auto_calc(true, from_str);
				printops.custom_time_zone = 0;
				printops.time_zone = TIME_ZONE_LOCAL;
				return;
			} else if(to_str == "CET") {
				printops.time_zone = TIME_ZONE_CUSTOM;
				printops.custom_time_zone = 60;
				do_auto_calc(true, from_str);
				printops.custom_time_zone = 0;
				printops.time_zone = TIME_ZONE_LOCAL;
				return;
			} else if(equalsIgnoreCase(to_str, "bases") || equalsIgnoreCase(to_str, _("bases"))) {
			} else if(equalsIgnoreCase(to_str, "calendars") || equalsIgnoreCase(to_str, _("calendars"))) {
			} else if(equalsIgnoreCase(to_str, "rectangular") || equalsIgnoreCase(to_str, "cartesian") || equalsIgnoreCase(to_str, _("rectangular")) || equalsIgnoreCase(to_str, _("cartesian"))) {
				ComplexNumberForm cnf_bak = evalops.complex_number_form;
				bool caf_bak = complex_angle_form;
				complex_angle_form = false;
				evalops.complex_number_form = COMPLEX_NUMBER_FORM_RECTANGULAR;
				do_auto_calc(true, from_str);
				evalops.complex_number_form = cnf_bak;
				complex_angle_form = caf_bak;
				return;
			} else if(equalsIgnoreCase(to_str, "exponential") || equalsIgnoreCase(to_str, _("exponential"))) {
				ComplexNumberForm cnf_bak = evalops.complex_number_form;
				bool caf_bak = complex_angle_form;
				complex_angle_form = false;
				evalops.complex_number_form = COMPLEX_NUMBER_FORM_EXPONENTIAL;
				do_auto_calc(true, from_str);
				evalops.complex_number_form = cnf_bak;
				complex_angle_form = caf_bak;
				return;
			} else if(equalsIgnoreCase(to_str, "polar") || equalsIgnoreCase(to_str, _("polar"))) {
				ComplexNumberForm cnf_bak = evalops.complex_number_form;
				bool caf_bak = complex_angle_form;
				complex_angle_form = false;
				evalops.complex_number_form = COMPLEX_NUMBER_FORM_POLAR;
				do_auto_calc(true, from_str);
				evalops.complex_number_form = cnf_bak;
				complex_angle_form = caf_bak;
				return;
			} else if(to_str == "cis") {
				ComplexNumberForm cnf_bak = evalops.complex_number_form;
				bool caf_bak = complex_angle_form;
				complex_angle_form = false;
				evalops.complex_number_form = COMPLEX_NUMBER_FORM_CIS;
				do_auto_calc(true, from_str);
				evalops.complex_number_form = cnf_bak;
				complex_angle_form = caf_bak;
				return;
			} else if(equalsIgnoreCase(to_str, "angle") || equalsIgnoreCase(to_str, _("angle")) || equalsIgnoreCase(to_str, "phasor") || equalsIgnoreCase(to_str, _("phasor"))) {
				ComplexNumberForm cnf_bak = evalops.complex_number_form;
				bool caf_bak = complex_angle_form;
				complex_angle_form = true;
				evalops.complex_number_form = COMPLEX_NUMBER_FORM_CIS;
				do_auto_calc(true, from_str);
				evalops.complex_number_form = cnf_bak;
				complex_angle_form = caf_bak;
				return;
			} else if(equalsIgnoreCase(to_str, "optimal") || equalsIgnoreCase(to_str, _("optimal"))) {
				bool b_units_saved = evalops.parse_options.units_enabled;
				evalops.parse_options.units_enabled = true;
				AutoPostConversion save_auto_post_conversion = evalops.auto_post_conversion;
				evalops.auto_post_conversion = POST_CONVERSION_OPTIMAL_SI;
				do_auto_calc(true, from_str);
				evalops.auto_post_conversion = save_auto_post_conversion;
				evalops.parse_options.units_enabled = b_units_saved;
				return;
			} else if(equalsIgnoreCase(to_str, "base") || equalsIgnoreCase(to_str, _("base"))) {
				bool b_units_saved = evalops.parse_options.units_enabled;
				evalops.parse_options.units_enabled = true;
				AutoPostConversion save_auto_post_conversion = evalops.auto_post_conversion;
				evalops.auto_post_conversion = POST_CONVERSION_BASE;
				do_auto_calc(true, from_str);
				evalops.auto_post_conversion = save_auto_post_conversion;
				evalops.parse_options.units_enabled = b_units_saved;
				return;
			} else if(equalsIgnoreCase(to_str, "mixed") || equalsIgnoreCase(to_str, _("mixed"))) {
				bool b_units_saved = evalops.parse_options.units_enabled;
				evalops.parse_options.units_enabled = true;
				AutoPostConversion save_auto_post_conversion = evalops.auto_post_conversion;
				MixedUnitsConversion save_mixed_units_conversion = evalops.mixed_units_conversion;
				evalops.auto_post_conversion = POST_CONVERSION_NONE;
				evalops.mixed_units_conversion = MIXED_UNITS_CONVERSION_FORCE_INTEGER;
				do_auto_calc(true, from_str);
				evalops.auto_post_conversion = save_auto_post_conversion;
				evalops.mixed_units_conversion = save_mixed_units_conversion;
				evalops.parse_options.units_enabled = b_units_saved;
				return;
			} else if(equalsIgnoreCase(to_str, "fraction") || equalsIgnoreCase(to_str, _("fraction"))) {
				do_to = true;
				to_fraction = true;
			} else if(equalsIgnoreCase(to_str, "factors") || equalsIgnoreCase(to_str, _("factors")) || equalsIgnoreCase(to_str, "factor")) {
				do_factors = true;
				str = from_str;
			} else if(equalsIgnoreCase(to_str, "partial fraction") || equalsIgnoreCase(to_str, _("partial fraction"))) {
				do_pfe = true;
				str = from_str;
			} else if(equalsIgnoreCase(to_str1, "base") || equalsIgnoreCase(to_str1, _("base"))) {
				if(equalsIgnoreCase(to_str2, "golden") || equalsIgnoreCase(to_str2, "golden ratio") || to_str2 == "φ") to_base = BASE_GOLDEN_RATIO;
				else if(to_str2 == "b26" || to_str2 == "B26") to_base = BASE_BIJECTIVE_26;
				else if(equalsIgnoreCase(to_str2, "unicode")) to_base = BASE_UNICODE;
				else if(equalsIgnoreCase(to_str2, "supergolden") || equalsIgnoreCase(to_str2, "supergolden ratio") || to_str2 == "ψ") to_base = BASE_SUPER_GOLDEN_RATIO;
				else if(equalsIgnoreCase(to_str2, "pi") || to_str2 == "π") to_base = BASE_PI;
				else if(to_str2 == "e") to_base = BASE_E;
				else if(to_str2 == "sqrt(2)" || to_str2 == "sqrt 2" || to_str2 == "sqrt2" || to_str2 == "√2") to_base = BASE_SQRT2;
				else {
					EvaluationOptions eo = evalops;
					eo.parse_options.base = 10;
					MathStructure m;
					eo.approximation = APPROXIMATION_TRY_EXACT;
					CALCULATOR->beginTemporaryStopMessages();
					CALCULATOR->calculate(&m, CALCULATOR->unlocalizeExpression(to_str2, eo.parse_options), 200, eo);
					if(CALCULATOR->endTemporaryStopMessages()) {
						to_base = BASE_CUSTOM;
						to_nbase.clear();
					} else if(m.isInteger() && m.number() >= 2 && m.number() <= 36) {
						to_base = m.number().intValue();
					} else {
						to_base = BASE_CUSTOM;
						to_nbase = m.number();
					}
				}
				do_to = true;
			} else {
				if(to_str[0] == '?') {
					to_prefix = 1;
				} else if(to_str.length() > 1 && to_str[1] == '?' && (to_str[0] == 'b' || to_str[0] == 'a' || to_str[0] == 'd')) {
					to_prefix = to_str[0];
				}
				do_conv = true;
			}
			if(do_to) {
				str = from_str;
			}
		} else if(origstr) {
			size_t i = str.find_first_of(SPACES LEFT_PARENTHESIS);
			if(i != string::npos) {
				to_str = str.substr(0, i);
				if(to_str == "factor" || equalsIgnoreCase(to_str, "factorize") || equalsIgnoreCase(to_str, _("factorize"))) {
					str = str.substr(i + 1);
					do_factors = true;
				} else if(equalsIgnoreCase(to_str, "expand") || equalsIgnoreCase(to_str, _("expand"))) {
					str = str.substr(i + 1);
					do_expand = true;
				}
			}
		}
		if(origstr && !do_conv && gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "convert_button_continuous_conversion")))) {
			string ceu_str = CALCULATOR->unlocalizeExpression(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(main_builder, "convert_entry_unit"))), evalops.parse_options);
			remove_blank_ends(ceu_str);
			if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "convert_button_set_missing_prefixes"))) && !ceu_str.empty()) {
				if(!ceu_str.empty() && ceu_str[0] != '0' && ceu_str[0] != '?' && ceu_str[0] != '+' && ceu_str[0] != '-' && (ceu_str.length() == 1 || ceu_str[1] != '?')) {
					ceu_str = "?" + ceu_str;
				}
			}
			if(ceu_str.empty()) {
				parsed_tostruct->setUndefined();
			} else {
				if(ceu_str[0] == '?') {
					to_prefix = 1;
				} else if(ceu_str.length() > 1 && ceu_str[1] == '?' && (ceu_str[0] == 'b' || ceu_str[0] == 'a' || ceu_str[0] == 'd')) {
					to_prefix = ceu_str[0];
				}
				parsed_tostruct->set(ceu_str);
			}
		} else {
			parsed_tostruct->setUndefined();
		}

		do_timeout_bak = do_timeout;
		do_timeout = false;

		CALCULATOR->beginTemporaryStopMessages();
		if(!CALCULATOR->calculate(&mauto, CALCULATOR->unlocalizeExpression(str, evalops.parse_options), 100, evalops, parsed_mstruct, parsed_tostruct)) {
			mauto.setAborted();
		} else if(do_factors || do_pfe || do_expand) {
			CALCULATOR->startControl(100);
			if(do_factors) {
				if(!mauto.integerFactorize()) {
					mauto.structure(STRUCTURING_FACTORIZE, evalops, true);
				}
			} else if(do_pfe) {
				mauto.expandPartialFractions(evalops);
			} else if(do_expand) {
				mauto.expand(evalops);
			}
			if(CALCULATOR->aborted()) mauto.setAborted();
			CALCULATOR->stopControl();
		}
		CALCULATOR->endTemporaryStopMessages(!mauto.isAborted(), &autocalc_messages);
		if(!mauto.isAborted()) {
			mstruct->set(mauto);
			autocalc_history_timeout_id = g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE, AUTOCALC_HISTORY_TIMEOUT, do_autocalc_history_timeout, NULL, NULL);
		}
	} else {
		do_timeout_bak = do_timeout;
		do_timeout = false;
	}
	if(!recalculate || !mauto.isAborted()) {
	
		CALCULATOR->beginTemporaryStopMessages();
	
		CALCULATOR->startControl(100);
		
		Number save_nbase(CALCULATOR->customOutputBase());
		int save_base = printops.base;
		bool save_pre = printops.use_unit_prefixes;
		bool save_cur = printops.use_prefixes_for_currencies;
		bool save_allu = printops.use_prefixes_for_all_units;
		bool save_all = printops.use_all_prefixes;
		bool save_den = printops.use_denominator_prefix;
		int save_bin = CALCULATOR->usesBinaryPrefixes();
		NumberFractionFormat save_format = printops.number_fraction_format;
		bool save_restrict_fraction_length = printops.restrict_fraction_length;
		bool do_to = false;
		if(to_base != 0 || to_fraction || to_prefix != 0) {
			if(to_base != 0 && (to_base != printops.base || (to_base == BASE_CUSTOM && to_nbase != CALCULATOR->customOutputBase()))) {
				printops.base = to_base;
				if(to_base == BASE_CUSTOM) CALCULATOR->setCustomOutputBase(to_nbase);
				do_to = true;
			}
			if(to_fraction && (printops.restrict_fraction_length || (mstruct->isNumber() && printops.number_fraction_format != FRACTION_COMBINED) || (!mstruct->isNumber() && printops.number_fraction_format != FRACTION_FRACTIONAL))) {
				printops.restrict_fraction_length = false;
				if(mstruct->isNumber()) printops.number_fraction_format = FRACTION_COMBINED;
				else printops.number_fraction_format = FRACTION_FRACTIONAL;
				do_to = true;
			}
			if(to_prefix != 0) {
				bool new_pre = printops.use_unit_prefixes;
				bool new_cur = printops.use_prefixes_for_currencies;
				bool new_allu = printops.use_prefixes_for_all_units;
				bool new_all = printops.use_all_prefixes;
				bool new_den = printops.use_denominator_prefix;
				int new_bin = CALCULATOR->usesBinaryPrefixes();
				new_pre = true;
				if(to_prefix == 'b') {
					int i = has_information_unit(*mstruct);
					new_bin = (i > 0 ? 1 : 2);
					if(i == 1) {
						new_den = false;
					} else if(i > 1) {
						new_den = true;
					} else {
						new_cur = true;
						new_allu = true;
					}
				} else {
					new_cur = true;
					new_allu = true;
					if(to_prefix == 'a') new_all = true;
					else if(to_prefix == 'd') new_bin = 0;
				}
				if(printops.use_unit_prefixes != new_pre || printops.use_prefixes_for_currencies != new_cur || printops.use_prefixes_for_all_units != new_allu || printops.use_all_prefixes != new_all || printops.use_denominator_prefix != new_den || CALCULATOR->usesBinaryPrefixes() != new_bin) {
					printops.use_unit_prefixes = new_pre;
					printops.use_all_prefixes = new_all;
					printops.use_prefixes_for_currencies = new_cur;
					printops.use_prefixes_for_all_units = new_allu;
					printops.use_denominator_prefix = new_den;
					CALCULATOR->useBinaryPrefixes(new_bin);
					do_to = true;
				}
			}
		}
	
		MathStructure *displayed_mstruct_pre = new MathStructure();
		displayed_mstruct_pre->set(*mstruct);
		if(printops.interval_display == INTERVAL_DISPLAY_INTERVAL) replace_interval_with_function(*displayed_mstruct_pre);
	
		printops.allow_non_usable = true;
		printops.can_display_unicode_string_arg = (void*) resultview;

		date_map.clear();
		number_map.clear();
		number_base_map.clear();
		number_exp_map.clear();
		number_exp_minus_map.clear();
		number_approx_map.clear();
		
		displayed_mstruct_pre->removeDefaultAngleUnit(evalops);
		displayed_mstruct_pre->format(printops);
		tmp_surface = draw_structure(*displayed_mstruct_pre, printops, complex_angle_form, top_ips, NULL, 0);
		if(tmp_surface && CALCULATOR->aborted()) {
			CALCULATOR->endTemporaryStopMessages();
			cairo_surface_destroy(tmp_surface);
			tmp_surface = NULL;
			clearresult();
			displayed_mstruct_pre->unref();
		} else if(tmp_surface) {
			CALCULATOR->endTemporaryStopMessages(true);
			scale_n = 0;
			showing_first_time_message = FALSE;
			if(surface_result) cairo_surface_destroy(surface_result);
			if(displayed_mstruct) displayed_mstruct->unref();
			displayed_mstruct = displayed_mstruct_pre;
			displayed_printops = printops;
			displayed_caf = complex_angle_form;
			result_autocalculated = true;
			display_aborted = false;
			surface_result = tmp_surface;
			first_draw_of_result = TRUE;
			gtk_widget_queue_draw(resultview);
			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "menu_item_save_image")), true);
			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_save_image")), true);
			result_text = displayed_mstruct->print();
			if(complex_angle_form) replace_result_cis(result_text);
			PrintOptions printops_long = printops;
			printops_long.abbreviate_names = false; 
			printops_long.short_multiplication = false;
			printops_long.excessive_parenthesis = true;
			printops_long.is_approximate = NULL;
			result_text = displayed_mstruct->print(printops_long);
			result_text_approximate = printops_long.is_approximate;
			if(CALCULATOR->aborted()) {
				result_text = "";
			} else {
				result_text_long = displayed_mstruct->print(printops_long);
				if(complex_angle_form) replace_result_cis(result_text_long);
			}
			if(CALCULATOR->aborted()) {
				result_text_long = "";
				gtk_widget_set_tooltip_text(resultview, "");
			} else {
				string eqstr;
				if(result_text_approximate && !mstruct->isApproximate()) {
					eqstr = "=";
				} else {
					if(printops.use_unicode_signs && can_display_unicode_string_function(SIGN_ALMOST_EQUAL, (void*) historyview)) {
						eqstr = SIGN_ALMOST_EQUAL;
					} else {
						eqstr = "= ";
						eqstr += _("approx.");
					}
				}
				gtk_widget_set_tooltip_text(resultview, result_text_long.length() < 1000 ? (eqstr + result_text_long).c_str() : "");
			}
			update_expression_icons();
			display_errors(NULL, NULL, NULL, 1);
			result_bin = ""; result_oct = "", result_dec = "", result_hex = "";
			if(max_bases.isZero()) {max_bases = 2; max_bases ^= 64; min_bases = -max_bases;}
			if(visible_keypad == 1 && !CALCULATOR->aborted() && ((displayed_mstruct->isNumber() && displayed_mstruct->number() < max_bases && displayed_mstruct->number() > min_bases) || (displayed_mstruct->isNegate() && (*displayed_mstruct)[0].isNumber() && (*displayed_mstruct)[0].number() < max_bases && (*displayed_mstruct)[0].number() > min_bases))) {
				Number nr;
				if(displayed_mstruct->isNumber()) {
					nr = displayed_mstruct->number();
				} else {
					nr = (*displayed_mstruct)[0].number();
					nr.negate();
				}
				nr.round(printops.round_halfway_to_even);
				PrintOptions po = printops;
				po.show_ending_zeroes = false;
				po.min_exp = 0;
				if(printops.base != 2) {
					po.base = 2;
					result_bin = nr.print(po);
				}
				if(printops.base != 8) {
					po.base = 8;
					result_oct = nr.print(po);
					size_t i = result_oct.find_first_of(NUMBERS);
					if(i != string::npos && result_oct.length() > i + 1 && result_oct[i] == '0' && is_in(NUMBERS, result_oct[i + 1])) result_oct.erase(i, 1);
				}
				if(printops.base != 10) {
					po.base = 10;
					result_dec = nr.print(po);
				}
				if(printops.base != 16) {
					po.base = 16;
					result_hex = nr.print(po);
					gsub("0x", "", result_hex);
				}
			}
			update_result_bases();
		} else {
			displayed_mstruct_pre->unref();
			CALCULATOR->endTemporaryStopMessages();
			clearresult();
		}

		printops.can_display_unicode_string_arg = NULL;
		printops.allow_non_usable = false;
		
		if(do_to) {
			printops.base = save_base;
			CALCULATOR->setCustomOutputBase(save_nbase);
			printops.use_unit_prefixes = save_pre;
			printops.use_all_prefixes = save_all;
			printops.use_prefixes_for_currencies = save_cur;
			printops.use_prefixes_for_all_units = save_allu;
			printops.use_denominator_prefix = save_den;
			CALCULATOR->useBinaryPrefixes(save_bin);
			printops.number_fraction_format = save_format;
			printops.restrict_fraction_length = save_restrict_fraction_length;
		}

		CALCULATOR->stopControl();
	} else {
		clearresult();
	}
	do_timeout = do_timeout_bak;
}
void print_auto_calc() {
	do_auto_calc(false);
}

void display_parse_status() {
	if(!display_expression_status) return;
	if(block_display_parse) return;
	GtkTextIter istart, iend, ipos;
	gtk_text_buffer_get_start_iter(expressionbuffer, &istart);
	gtk_text_buffer_get_end_iter(expressionbuffer, &iend);
	gchar *gtext = gtk_text_buffer_get_text(expressionbuffer, &istart, &iend, FALSE);
	string text = gtext, str_f;
	g_free(gtext);
	if(text.empty()) {
		set_status_text("", true, false, false);
		parsed_expression = "";
		expression_has_changed2 = false;
		return;
	}
	remove_duplicate_blanks(text);
	size_t i = text.find_first_of(SPACES LEFT_PARENTHESIS);
	if(i != string::npos) {
		str_f = text.substr(0, i);
		if(str_f == "factor" || equalsIgnoreCase(str_f, "factorize") || equalsIgnoreCase(str_f, _("factorize"))) {
			text = text.substr(i + 1);
			str_f = _("factorize");
		} else if(equalsIgnoreCase(str_f, "expand") || equalsIgnoreCase(str_f, _("expand"))) {
			text = text.substr(i + 1);
			str_f = _("expand");
		} else {
			str_f = "";
		}
	}
	GtkTextMark *mark = gtk_text_buffer_get_insert(expressionbuffer);
	if(mark) gtk_text_buffer_get_iter_at_mark(expressionbuffer, &ipos, mark);
	else ipos = iend;
	MathStructure mparse, mfunc;
	bool full_parsed = false;
	string str_e, str_u, str_w;
	bool had_errors = false, had_warnings = false;
	evalops.parse_options.preserve_format = true;
	if(!gtk_text_iter_is_start(&ipos)) {
		evalops.parse_options.unended_function = &mfunc;
		CALCULATOR->beginTemporaryStopMessages();
		if(!gtk_text_iter_is_end(&ipos)) {
			gtext = gtk_text_buffer_get_text(expressionbuffer, &istart, &ipos, FALSE);
			str_e = CALCULATOR->unlocalizeExpression(gtext, evalops.parse_options);
			bool b = CALCULATOR->separateToExpression(str_e, str_u, evalops, false, true);
			b = CALCULATOR->separateWhereExpression(str_e, str_w, evalops) || b;
			if(!b) {
				CALCULATOR->parse(&mparse, str_e, evalops.parse_options);
			}
			g_free(gtext);
		} else {
			str_e = CALCULATOR->unlocalizeExpression(text, evalops.parse_options);
			bool b = CALCULATOR->separateToExpression(str_e, str_u, evalops, false, true);
			b = CALCULATOR->separateWhereExpression(str_e, str_w, evalops) || b;
			if(!b) {
				CALCULATOR->parse(&mparse, str_e, evalops.parse_options);
				full_parsed = true;
			}
		}
		int warnings_count;
		had_errors = CALCULATOR->endTemporaryStopMessages(NULL, &warnings_count) > 0;
		had_warnings = warnings_count > 0;
		evalops.parse_options.unended_function = NULL;
	}
	bool b_func = false;
	if(mfunc.isFunction()) {
		if(mfunc.countChildren() == 0) {
			b_func = display_function_hint(mfunc.function(), 1);
		} else {
			b_func = display_function_hint(mfunc.function(), mfunc.countChildren());
		}
	}
	if(expression_has_changed2) {
		if(!full_parsed) {
			CALCULATOR->beginTemporaryStopMessages();
			str_e = CALCULATOR->unlocalizeExpression(text, evalops.parse_options);
			CALCULATOR->separateToExpression(str_e, str_u, evalops, false, true);
			CALCULATOR->separateWhereExpression(str_e, str_w, evalops);
			if(!str_e.empty()) CALCULATOR->parse(&mparse, str_e, evalops.parse_options);
			int warnings_count;
			had_errors = CALCULATOR->endTemporaryStopMessages(NULL, &warnings_count) > 0;
			had_warnings = warnings_count > 0;
		}
		PrintOptions po;
		po.preserve_format = true;
		po.show_ending_zeroes = evalops.parse_options.read_precision != DONT_READ_PRECISION && !CALCULATOR->usesIntervalArithmetic() && evalops.parse_options.base > BASE_CUSTOM;
		po.lower_case_e = printops.lower_case_e;
		po.lower_case_numbers = printops.lower_case_numbers;
		po.base_display = printops.base_display;
		po.twos_complement = printops.twos_complement;
		po.hexadecimal_twos_complement = printops.hexadecimal_twos_complement;
		po.base = evalops.parse_options.base;
		Number nr_base;
		if(po.base == BASE_CUSTOM && (CALCULATOR->usesIntervalArithmetic() || CALCULATOR->customInputBase().isRational()) && (CALCULATOR->customInputBase().isInteger() || !CALCULATOR->customInputBase().isNegative()) && (CALCULATOR->customInputBase() > 1 || CALCULATOR->customInputBase() < -1)) {
			nr_base = CALCULATOR->customOutputBase();
			CALCULATOR->setCustomOutputBase(CALCULATOR->customInputBase());
		} else if(po.base == BASE_CUSTOM || (po.base < BASE_CUSTOM && !CALCULATOR->usesIntervalArithmetic() && po.base != BASE_UNICODE && po.base != BASE_BIJECTIVE_26)) {
			po.base = 10;
			po.min_exp = 6;
			po.use_max_decimals = true;
			po.max_decimals = 5;
			po.preserve_format = false;
		}
		po.abbreviate_names = false;
		po.hide_underscore_spaces = true;
		po.use_unicode_signs = printops.use_unicode_signs;
		po.digit_grouping = printops.digit_grouping;
		po.multiplication_sign = printops.multiplication_sign;
		po.division_sign = printops.division_sign;
		po.short_multiplication = false;
		po.excessive_parenthesis = true;
		po.improve_division_multipliers = false;
		po.can_display_unicode_string_function = &can_display_unicode_string_function;
		po.can_display_unicode_string_arg = (void*) statuslabel_l;
		po.spell_out_logical_operators = printops.spell_out_logical_operators;
		po.restrict_to_parent_precision = false;
		po.interval_display = INTERVAL_DISPLAY_PLUSMINUS;
		if(str_e.empty()) {
			parsed_expression = "";
		} else {
			CALCULATOR->beginTemporaryStopMessages();
			mparse.format(po);
			parsed_expression = mparse.print(po);
			CALCULATOR->endTemporaryStopMessages();
		}
		if(!str_w.empty()) {
			CALCULATOR->beginTemporaryStopMessages();
			CALCULATOR->parse(&mparse, str_w, evalops.parse_options);
			int warnings_count;
			had_errors = CALCULATOR->endTemporaryStopMessages(NULL, &warnings_count) > 0 || had_errors;
			had_warnings = warnings_count > 0 || had_warnings || (!mparse.isLogicalAnd() && !mparse.isComparison());
			parsed_expression += CALCULATOR->localWhereString();
			CALCULATOR->beginTemporaryStopMessages();
			mparse.format(po);
			parsed_expression += mparse.print(po);
			CALCULATOR->endTemporaryStopMessages();
		}
		if(!str_u.empty()) {
			if(parsed_expression.empty()) {
				parsed_expression += CALCULATOR->localToString(false);
				parsed_expression += " ";
			} else {
				parsed_expression += CALCULATOR->localToString();
			}
			remove_duplicate_blanks(str_u);
			string to_str1, to_str2;
			size_t ispace = str_u.find_first_of(SPACES);
			if(ispace != string::npos) {
				to_str1 = str_u.substr(0, ispace);
				remove_blank_ends(to_str1);
				to_str2 = str_u.substr(ispace + 1);
				remove_blank_ends(to_str2);
			}
			if(equalsIgnoreCase(str_u, "hex") || equalsIgnoreCase(str_u, "hexadecimal") || equalsIgnoreCase(str_u, _("hexadecimal"))) {
				parsed_expression += _("hexadecimal number");
			} else if(equalsIgnoreCase(str_u, "oct") || equalsIgnoreCase(str_u, "octal") || equalsIgnoreCase(str_u, _("octal"))) {
				parsed_expression += _("octal number");
			} else if(equalsIgnoreCase(str_u, "dec") || equalsIgnoreCase(str_u, "decimal") || equalsIgnoreCase(str_u, _("decimal"))) {
				parsed_expression += _("decimal number");
			} else if(equalsIgnoreCase(str_u, "duo") || equalsIgnoreCase(str_u, "duodecimal") || equalsIgnoreCase(str_u, _("duodecimal"))) {
				parsed_expression += _("duodecimal number");
			} else if(equalsIgnoreCase(str_u, "bin") || equalsIgnoreCase(str_u, "binary") || equalsIgnoreCase(str_u, _("binary"))) {
				parsed_expression += _("binary number");
			} else if(equalsIgnoreCase(str_u, "roman") || equalsIgnoreCase(str_u, _("roman"))) {
				parsed_expression += _("roman numerals");
			} else if(equalsIgnoreCase(str_u, "bijective") || equalsIgnoreCase(str_u, _("bijective"))) {
				parsed_expression += _("bijective base-26");
			} else if(equalsIgnoreCase(str_u, "sexa") || equalsIgnoreCase(str_u, "sexagesimal") || equalsIgnoreCase(str_u, _("sexagesimal"))) {
				parsed_expression += _("sexagesimal number");
			} else if(equalsIgnoreCase(str_u, "time") || equalsIgnoreCase(str_u, _("time"))) {
				parsed_expression += _("time format");
			} else if(equalsIgnoreCase(str_u, "unicode")) {
				parsed_expression += _("Unicode");
			} else if(equalsIgnoreCase(str_u, "bases") || equalsIgnoreCase(str_u, _("bases"))) {
				parsed_expression += _("number bases");
			} else if(equalsIgnoreCase(str_u, "calendars") || equalsIgnoreCase(str_u, _("calendars"))) {
				parsed_expression += _("calendars");
			} else if(equalsIgnoreCase(str_u, "optimal") || equalsIgnoreCase(str_u, _("optimal"))) {
				parsed_expression += _("optimal unit");
			} else if(equalsIgnoreCase(str_u, "base") || equalsIgnoreCase(str_u, _("base"))) {
				parsed_expression += _("base units");
			} else if(equalsIgnoreCase(str_u, "mixed") || equalsIgnoreCase(str_u, _("mixed"))) {
				parsed_expression += _("mixed units");
			} else if(equalsIgnoreCase(str_u, "fraction") || equalsIgnoreCase(str_u, _("fraction"))) {
				parsed_expression += _("fraction");
			} else if(equalsIgnoreCase(str_u, "factors") || equalsIgnoreCase(str_u, _("factors")) || equalsIgnoreCase(str_u, "factor")) {
				parsed_expression += _("factors");
			} else if(equalsIgnoreCase(str_u, "partial fraction") || equalsIgnoreCase(str_u, _("partial fraction"))) {
				parsed_expression += _("expanded partial fractions");
			} else if(equalsIgnoreCase(str_u, "rectangular") || equalsIgnoreCase(str_u, "cartesian") || equalsIgnoreCase(str_u, _("rectangular")) || equalsIgnoreCase(str_u, _("cartesian"))) {
				parsed_expression += _("complex rectangular form");
			} else if(equalsIgnoreCase(str_u, "exponential") || equalsIgnoreCase(str_u, _("exponential"))) {
				parsed_expression += _("complex exponential form");
			} else if(equalsIgnoreCase(str_u, "polar") || equalsIgnoreCase(str_u, _("polar"))) {
				parsed_expression += _("complex polar form");
			} else if(str_u == "cis") {
				parsed_expression += _("complex cis form");
			} else if(equalsIgnoreCase(str_u, "angle") || equalsIgnoreCase(str_u, _("angle"))) {
				parsed_expression += _("complex angle notation");
			} else if(equalsIgnoreCase(str_u, "phasor") || equalsIgnoreCase(str_u, _("phasor"))) {
				parsed_expression += _("complex phasor notation");
			} else if(equalsIgnoreCase(str_u, "utc") || equalsIgnoreCase(str_u, "gmt")) {
				parsed_expression += _("UTC time zone");
			} else if(str_u.length() > 3 && (equalsIgnoreCase(str_u.substr(0, 3), "utc") || equalsIgnoreCase(str_u.substr(0, 3), "gmt"))) {
				str_u = str_u.substr(3);
				parsed_expression += "UTC";
				remove_blanks(str_u);
				bool b_minus = false;
				if(str_u[0] == '+') {
					str_u.erase(0, 1);
				} else if(str_u[0] == '-') {
					b_minus = true;
					str_u.erase(0, 1);
				} else if(str_u.find(SIGN_MINUS) == 0) {
					b_minus = true;
					str_u.erase(0, strlen(SIGN_MINUS));
				}
				unsigned int tzh = 0, tzm = 0;
				int itz = 0;
				if(!str_u.empty() && sscanf(str_u.c_str(), "%2u:%2u", &tzh, &tzm) > 0) {
					itz = tzh * 60 + tzm;
				} else {
					had_errors = true;
				}
				if(itz > 0) {
					if(b_minus) parsed_expression += '-';
					else parsed_expression += '+';
					if(itz < 60) {
						parsed_expression += "00";
					} else {
						if(itz < 60 * 10) parsed_expression += '0';
						parsed_expression += i2s(itz / 60);
					}
					if(itz % 60 > 0) {
						parsed_expression += ":";
						if(itz % 60 < 10) parsed_expression += '0';
						parsed_expression += i2s(itz % 60);
					}
				}
			} else if(str_u == "CET") {
				parsed_expression += "UTC";
				parsed_expression += "+01";
			} else if(equalsIgnoreCase(to_str1, "base") || equalsIgnoreCase(to_str1, _("base"))) {
				gchar *gstr = g_strdup_printf(_("number base %s"), to_str2.c_str());
				parsed_expression += gstr;
				g_free(gstr);
			} else {
				Variable *v = CALCULATOR->getVariable(str_u);
				if(v && (!v->isKnown() || ((KnownVariable*) v)->unit().empty())) v = NULL;
				if(v && CALCULATOR->getUnit(str_u)) v = NULL;
				if(v) {
					mparse = v;
				} else {
					CALCULATOR->beginTemporaryStopMessages();
					CompositeUnit cu("", "temporary_composite_parse", "", str_u);
					int warnings_count;
					had_errors = CALCULATOR->endTemporaryStopMessages(NULL, &warnings_count) > 0 || had_errors;
					had_warnings = had_warnings || warnings_count > 0;
					mparse = cu.generateMathStructure(!printops.negative_exponents);
					mparse.format(po);
				}
				CALCULATOR->beginTemporaryStopMessages();
				parsed_expression += mparse.print(po);
				CALCULATOR->endTemporaryStopMessages();
			}
		}
		if(po.base == BASE_CUSTOM) CALCULATOR->setCustomOutputBase(nr_base);
		parsed_had_errors = had_errors; parsed_had_warnings = had_warnings;
		if(!str_f.empty()) {str_f += " "; parsed_expression.insert(0, str_f);}
		gsub("&", "&amp;", parsed_expression);
		gsub(">", "&gt;", parsed_expression);
		gsub("<", "&lt;", parsed_expression);
		if(!b_func) set_status_text(parsed_expression.c_str(), true, had_errors, had_warnings);
		expression_has_changed2 = false;
	} else if(!b_func) {
		set_status_text(parsed_expression.c_str(), true, parsed_had_errors, parsed_had_warnings);
	}
	evalops.parse_options.preserve_format = false;
}


void highlight_parentheses() {
	GtkTextMark *mcur = gtk_text_buffer_get_insert(expressionbuffer);
	if(!mcur) return;
	GtkTextIter icur, istart, iend;
	gtk_text_buffer_get_iter_at_mark(expressionbuffer, &icur, mcur);
	gtk_text_buffer_get_start_iter(expressionbuffer, &istart);
	gtk_text_buffer_get_end_iter(expressionbuffer, &iend);
	gtk_text_buffer_remove_tag(expressionbuffer, expression_par_tag, &istart, &iend);
	bool b = false;
	b = (gtk_text_iter_get_char(&icur) == ')');
	if(!b && gtk_text_iter_backward_char(&icur)) {
		b = (gtk_text_iter_get_char(&icur) == ')');
		if(!b) gtk_text_iter_forward_char(&icur);
	}
	if(b) {
		GtkTextIter ipar2 = icur;
		int pars = 1;
		while(gtk_text_iter_backward_char(&ipar2)) {
			if(gtk_text_iter_get_char(&ipar2) == ')') {
				pars++;
			} else if(gtk_text_iter_get_char(&ipar2) == '(') {
				pars--;
				if(pars == 0) break;
			}
		}
		if(pars == 0) {
			GtkTextIter inext = icur;
			gtk_text_iter_forward_char(&inext);
			gtk_text_buffer_apply_tag(expressionbuffer, expression_par_tag, &icur, &inext);
			inext = ipar2;
			gtk_text_iter_forward_char(&inext);
			gtk_text_buffer_apply_tag(expressionbuffer, expression_par_tag, &ipar2, &inext);
		}
	} else {
		b = (gtk_text_iter_get_char(&icur) == '(');
		if(!b && gtk_text_iter_backward_char(&icur)) {
			b = (gtk_text_iter_get_char(&icur) == '(');
			if(!b) gtk_text_iter_forward_char(&icur);
		}
		if(b) {
			GtkTextIter ipar2 = icur;
			int pars = 1;
			while(gtk_text_iter_forward_char(&ipar2)) {
				if(gtk_text_iter_get_char(&ipar2) == '(') {
					pars++;
				} else if(gtk_text_iter_get_char(&ipar2) == ')') {
					pars--;
					if(pars == 0) break;
				}
			}
			if(pars == 0) {
				GtkTextIter inext = icur;
				gtk_text_iter_forward_char(&inext);
				gtk_text_buffer_apply_tag(expressionbuffer, expression_par_tag, &icur, &inext);
				inext = ipar2;
				gtk_text_iter_forward_char(&inext);
				gtk_text_buffer_apply_tag(expressionbuffer, expression_par_tag, &ipar2, &inext);
			}
		}
	}
}

void on_expressionbuffer_cursor_position_notify() {
	if(expression_has_changed_pos) {
		expression_has_changed_pos = false;
		return;
	}
	gtk_widget_hide(completion_window);
	if(!check_expression_position) return;
	highlight_parentheses();
	display_parse_status();
	if(auto_calc_stopped_at_operator) do_auto_calc();
}

/*
	set focus on expression entry without losing selection
*/
void focus_keeping_selection() {
	if(gtk_widget_is_focus(expressiontext)) return;
	gtk_widget_grab_focus(expressiontext);
}

MathFunction *get_selected_function() {
	return selected_function;
}

MathFunction *get_edited_function() {
	return edited_function;
}
Unit *get_edited_unit() {
	return edited_unit;
}
DataSet *get_edited_dataset() {
	return edited_dataset;
}
DataProperty *get_edited_dataproperty() {
	return edited_dataproperty;
}
KnownVariable *get_edited_variable() {
	return edited_variable;
}
UnknownVariable *get_edited_unknown() {
	return edited_unknown;
}
KnownVariable *get_edited_matrix() {
	return edited_matrix;
}

Argument *get_edited_argument() {
	return edited_argument;
}
Argument *get_selected_argument() {
	return selected_argument;
}
size_t get_selected_subfunction() {
	return selected_subfunction;
}

Variable *get_selected_variable() {
	return selected_variable;
}

Unit *get_selected_unit() {
	return selected_unit;
}

Unit *get_selected_to_unit() {
	return selected_to_unit;
}

void generate_units_tree_struct() {
	size_t cat_i, cat_i_prev; 
	bool b;	
	string str, cat, cat_sub;
	Unit *u = NULL;
	unit_cats.items.clear();
	unit_cats.objects.clear();
	unit_cats.parent = NULL;	
	ia_units.clear();
	list<tree_struct>::iterator it;	
	for(size_t i = 0; i < CALCULATOR->units.size(); i++) {
		if(!CALCULATOR->units[i]->isActive()) {
			b = false;
			for(size_t i3 = 0; i3 < ia_units.size(); i3++) {
				u = (Unit*) ia_units[i3];
				if(string_is_less(CALCULATOR->units[i]->title(), u->title())) {
					b = true;
					ia_units.insert(ia_units.begin() + i3, (void*) CALCULATOR->units[i]);
					break;
				}
			}
			if(!b) ia_units.push_back((void*) CALCULATOR->units[i]);
		} else {
			tree_struct *item = &unit_cats;
			if(!CALCULATOR->units[i]->category().empty()) {
				cat = CALCULATOR->units[i]->category();
				cat_i = cat.find("/"); cat_i_prev = 0;
				b = false;
				while(true) {
					if(cat_i == string::npos) {
						cat_sub = cat.substr(cat_i_prev, cat.length() - cat_i_prev);
					} else {
						cat_sub = cat.substr(cat_i_prev, cat_i - cat_i_prev);
					}
					b = false;
					for(it = item->items.begin(); it != item->items.end(); ++it) {
						if(cat_sub == it->item) {
							item = &*it;
							b = true;
							break;
						}
					}
					if(!b) {
						tree_struct cat;		
						item->items.push_back(cat);
						it = item->items.end();
						--it;
						it->parent = item;
						item = &*it;
						item->item = cat_sub;
					}
					if(cat_i == string::npos) {
						break;
					}
					cat_i_prev = cat_i + 1;
					cat_i = cat.find("/", cat_i_prev);
				}
			}
			b = false;
			for(size_t i3 = 0; i3 < item->objects.size(); i3++) {
				u = (Unit*) item->objects[i3];
				if(string_is_less(CALCULATOR->units[i]->title(), u->title())) {
					b = true;
					item->objects.insert(item->objects.begin() + i3, (void*) CALCULATOR->units[i]);
					break;
				}
			}
			if(!b) item->objects.push_back((void*) CALCULATOR->units[i]);		
		}
	}
	
	unit_cats.sort();

}
void generate_variables_tree_struct() {

	size_t cat_i, cat_i_prev; 
	bool b;	
	string str, cat, cat_sub;
	Variable *v = NULL;
	variable_cats.items.clear();
	variable_cats.objects.clear();
	variable_cats.parent = NULL;
	ia_variables.clear();
	list<tree_struct>::iterator it;	
	for(size_t i = 0; i < CALCULATOR->variables.size(); i++) {
		if(!CALCULATOR->variables[i]->isActive()) {
			//deactivated variable
			b = false;
			for(size_t i3 = 0; i3 < ia_variables.size(); i3++) {
				v = (Variable*) ia_variables[i3];
				if(string_is_less(CALCULATOR->variables[i]->title(), v->title())) {
					b = true;
					ia_variables.insert(ia_variables.begin() + i3, (void*) CALCULATOR->variables[i]);
					break;
				}
			}
			if(!b) ia_variables.push_back((void*) CALCULATOR->variables[i]);											
		} else {
			tree_struct *item = &variable_cats;
			if(!CALCULATOR->variables[i]->category().empty()) {
				cat = CALCULATOR->variables[i]->category();
				cat_i = cat.find("/"); cat_i_prev = 0;
				b = false;
				while(true) {
					if(cat_i == string::npos) {
						cat_sub = cat.substr(cat_i_prev, cat.length() - cat_i_prev);
					} else {
						cat_sub = cat.substr(cat_i_prev, cat_i - cat_i_prev);
					}
					b = false;
					for(it = item->items.begin(); it != item->items.end(); ++it) {
						if(cat_sub == it->item) {
							item = &*it;
							b = true;
							break;
						}
					}
					if(!b) {
						tree_struct cat;		
						item->items.push_back(cat);
						it = item->items.end();
						--it;
						it->parent = item;
						item = &*it;
						item->item = cat_sub;
					}
					if(cat_i == string::npos) {
						break;
					}
					cat_i_prev = cat_i + 1;
					cat_i = cat.find("/", cat_i_prev);
				}
			}
			b = false;
			for(size_t i3 = 0; i3 < item->objects.size(); i3++) {
				v = (Variable*) item->objects[i3];
				if(string_is_less(CALCULATOR->variables[i]->title(), v->title())) {
					b = true;
					item->objects.insert(item->objects.begin() + i3, (void*) CALCULATOR->variables[i]);
					break;
				}
			}
			if(!b) item->objects.push_back((void*) CALCULATOR->variables[i]);		
		}
	}
	
	variable_cats.sort();

}
void generate_functions_tree_struct() {

	size_t cat_i, cat_i_prev; 
	bool b;	
	string str, cat, cat_sub;
	MathFunction *f = NULL;
	function_cats.items.clear();
	function_cats.objects.clear();
	function_cats.parent = NULL;
	ia_functions.clear();
	list<tree_struct>::iterator it;

	for(size_t i = 0; i < CALCULATOR->functions.size(); i++) {
		if(!CALCULATOR->functions[i]->isActive()) {
			//deactivated function
			b = false;
			for(size_t i3 = 0; i3 < ia_functions.size(); i3++) {
				f = (MathFunction*) ia_functions[i3];
				if(string_is_less(CALCULATOR->functions[i]->title(), f->title())) {
					b = true;
					ia_functions.insert(ia_functions.begin() + i3, (void*) CALCULATOR->functions[i]);
					break;
				}
			}
			if(!b) ia_functions.push_back((void*) CALCULATOR->functions[i]);								
		} else {
			tree_struct *item = &function_cats;
			if(!CALCULATOR->functions[i]->category().empty()) {
				cat = CALCULATOR->functions[i]->category();
				cat_i = cat.find("/"); cat_i_prev = 0;
				b = false;
				while(true) {
					if(cat_i == string::npos) {
						cat_sub = cat.substr(cat_i_prev, cat.length() - cat_i_prev);
					} else {
						cat_sub = cat.substr(cat_i_prev, cat_i - cat_i_prev);
					}
					b = false;
					for(it = item->items.begin(); it != item->items.end(); ++it) {
						if(cat_sub == it->item) {
							item = &*it;
							b = true;
							break;
						}
					}
					if(!b) {
						tree_struct cat;		
						item->items.push_back(cat);
						it = item->items.end();
						--it;
						it->parent = item;
						item = &*it;
						item->item = cat_sub;
					}
					if(cat_i == string::npos) {
						break;
					}
					cat_i_prev = cat_i + 1;
					cat_i = cat.find("/", cat_i_prev);
				}
			}
			b = false;
			for(size_t i3 = 0; i3 < item->objects.size(); i3++) {
				f = (MathFunction*) item->objects[i3];
				if(string_is_less(CALCULATOR->functions[i]->title(), f->title())) {
					b = true;
					item->objects.insert(item->objects.begin() + i3, (void*) CALCULATOR->functions[i]);
					break;
				}
			}
			if(!b) item->objects.push_back((void*) CALCULATOR->functions[i]);
		}
	}
	
	function_cats.sort();
	
}

/*
	generate the function categories tree in manage functions dialog
*/
void update_functions_tree() {
	if(!functions_builder) return;
	GtkTreeIter iter, iter2, iter3;
	GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(tFunctionCategories));
	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tFunctionCategories));
	g_signal_handlers_block_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tFunctionCategories_selection_changed, NULL);
	gtk_tree_store_clear(tFunctionCategories_store);
	g_signal_handlers_unblock_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tFunctionCategories_selection_changed, NULL);
	gtk_tree_store_append(tFunctionCategories_store, &iter3, NULL);
	gtk_tree_store_set(tFunctionCategories_store, &iter3, 0, _("All"), 1, _("All"), -1);
	string str;
	tree_struct *item, *item2;
	function_cats.it = function_cats.items.begin();
	if(function_cats.it != function_cats.items.end()) {
		item = &*function_cats.it;
		++function_cats.it;
		item->it = item->items.begin();
	} else {
		item = NULL;
	}
	str = "";
	iter2 = iter3;
	while(item) {
		gtk_tree_store_append(tFunctionCategories_store, &iter, &iter2);
		str += "/";
		str += item->item;
		gtk_tree_store_set(tFunctionCategories_store, &iter, 0, item->item.c_str(), 1, str.c_str(), -1);
		if(str == selected_function_category) {
			EXPAND_TO_ITER(model, tFunctionCategories, iter)
			gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tFunctionCategories)), &iter);
		}
		while(item && item->it == item->items.end()) {
			size_t str_i = str.rfind("/");
			if(str_i == string::npos) {
				str = "";
			} else {
				str = str.substr(0, str_i);
			}
			item = item->parent;
			gtk_tree_model_iter_parent(model, &iter2, &iter);
			iter = iter2;
		}
		if(item) {
			item2 = &*item->it;
			if(item->it == item->items.begin()) iter2 = iter;
			++item->it;
			item = item2;
			item->it = item->items.begin();	
		}
	}
	if(!function_cats.objects.empty()) {
		//add "Uncategorized" category if there are functions without category
		gtk_tree_store_append(tFunctionCategories_store, &iter, &iter3);
		EXPAND_TO_ITER(model, tFunctionCategories, iter)
		gtk_tree_store_set(tFunctionCategories_store, &iter, 0, _("Uncategorized"), 1, _("Uncategorized"), -1);
		if(selected_function_category == _("Uncategorized")) {
			gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tFunctionCategories)), &iter);
		}
	}	
	if(!ia_functions.empty()) {
		//add "Inactive" category if there are inactive functions
		gtk_tree_store_append(tFunctionCategories_store, &iter, NULL);
		EXPAND_TO_ITER(model, tFunctionCategories, iter)
		gtk_tree_store_set(tFunctionCategories_store, &iter, 0, _("Inactive"), 1, _("Inactive"), -1);
		if(selected_function_category == _("Inactive")) {
			gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tFunctionCategories)), &iter);
		}
	}		
	if(!gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(tFunctionCategories)), &model, &iter)) {
		//if no category has been selected (previously selected has been renamed/deleted), select "All"
		selected_function_category = _("All");
		gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tFunctionCategories_store), &iter);
		EXPAND_ITER(model, tFunctionCategories, iter)
		gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tFunctionCategories)), &iter);
	}
}

void setFunctionTreeItem(GtkTreeIter &iter2, MathFunction *f) {
	gtk_list_store_append(tFunctions_store, &iter2);
	gtk_list_store_set(tFunctions_store, &iter2, 0, f->title(true).c_str(), 1, (gpointer) f, 2, TRUE, -1);
	GtkTreeIter iter;
	if(f == selected_function && gtk_tree_model_filter_convert_child_iter_to_iter(GTK_TREE_MODEL_FILTER(tFunctions_store_filter), &iter, &iter2)) {
		gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tFunctions)), &iter);
	}
}

/*
	generate the function tree in manage functions dialog when category selection has changed
*/
void on_tFunctionCategories_selection_changed(GtkTreeSelection *treeselection, gpointer) {
	GtkTreeModel *model, *model2;
	GtkTreeIter iter, iter2;
	bool no_cat = false, b_all = false, b_inactive = false;
	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tFunctions));
	g_signal_handlers_block_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_functions_entry_search_changed, NULL);
	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(functions_builder, "functions_entry_search")), "");
	g_signal_handlers_unblock_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_functions_entry_search_changed, NULL);
	g_signal_handlers_block_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tFunctions_selection_changed, NULL);
	gtk_list_store_clear(tFunctions_store);
	g_signal_handlers_unblock_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tFunctions_selection_changed, NULL);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functions_builder, "functions_button_edit")), FALSE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functions_builder, "functions_button_insert")), FALSE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functions_builder, "functions_button_delete")), FALSE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functions_builder, "functions_button_deactivate")), FALSE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functions_builder, "functions_button_apply")), FALSE);
	if(gtk_tree_selection_get_selected(treeselection, &model, &iter)) {
		gchar *gstr;
		gtk_tree_model_get(model, &iter, 1, &gstr, -1);
		selected_function_category = gstr;
		if(selected_function_category == _("All")) {
			b_all = true;
		} else if(selected_function_category == _("Uncategorized")) {
			no_cat = true;
		} else if(selected_function_category == _("Inactive")) {
			b_inactive = true;
		}
		if(!b_all && !no_cat && !b_inactive && selected_function_category[0] == '/') {
			string str = selected_function_category.substr(1, selected_function_category.length() - 1);
			for(size_t i = 0; i < CALCULATOR->functions.size(); i++) {
				if(CALCULATOR->functions[i]->isActive() && CALCULATOR->functions[i]->category().substr(0, selected_function_category.length() - 1) == str) {
					setFunctionTreeItem(iter2, CALCULATOR->functions[i]);
				}
			}
		} else {			
			for(size_t i = 0; i < CALCULATOR->functions.size(); i++) {
				if((b_inactive && !CALCULATOR->functions[i]->isActive()) || (CALCULATOR->functions[i]->isActive() && (b_all || (no_cat && CALCULATOR->functions[i]->category().empty()) || (!b_inactive && CALCULATOR->functions[i]->category() == selected_function_category)))) {
					setFunctionTreeItem(iter2, CALCULATOR->functions[i]);
				}
			}
		}
		if(!selected_function || !gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(tFunctions)), &model2, &iter2)) {
			if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tFunctions_store_filter), &iter2)) {
				gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tFunctions)), &iter2);
			}
		}
		g_free(gstr);
	} else {
		selected_function_category = "";
	}
}

/*
	function selection has changed
*/
void on_tFunctions_selection_changed(GtkTreeSelection *treeselection, gpointer) {
	GtkTreeModel *model;
	GtkTreeIter iter;
	if(gtk_tree_selection_get_selected(treeselection, &model, &iter)) {
		MathFunction *f;
		gtk_tree_model_get(model, &iter, 1, &f, -1);
		//remember the new selection
		selected_function = f;
		for(size_t i = 0; i < CALCULATOR->functions.size(); i++) {
			if(CALCULATOR->functions[i] == selected_function) {
				GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtk_builder_get_object(functions_builder, "functions_textview_description")));
				gtk_text_buffer_set_text(buffer, "", -1);
				GtkTextIter iter;
				f = CALCULATOR->functions[i];
				Argument *arg;
				Argument default_arg;
				string str, str2;
				const ExpressionName *ename = &f->preferredName(false, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) gtk_builder_get_object(functions_builder, "functions_textview_description"));
				str += ename->name;
				gtk_text_buffer_get_end_iter(buffer, &iter);
				gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, str.c_str(), -1, "bold", "italic", NULL);
				str = "";
				int iargs = f->maxargs();
				if(iargs < 0) {
					iargs = f->minargs() + 1;
				}
				str += "(";				
				if(iargs != 0) {
					for(int i2 = 1; i2 <= iargs; i2++) {	
						if(i2 > f->minargs()) {
							str += "[";
						}
						if(i2 > 1) {
							str += CALCULATOR->getComma();
							str += " ";
						}
						arg = f->getArgumentDefinition(i2);
						if(arg && !arg->name().empty()) {
							str2 = arg->name();
						} else {
							str2 = _("argument");
							str2 += " ";
							str2 += i2s(i2);
						}
						str += str2;
						if(i2 > f->minargs()) {
							str += "]";
						}
					}
					if(f->maxargs() < 0) {
						str += CALCULATOR->getComma();
						str += " …";
					}
				}
				str += ")";
				for(size_t i2 = 1; i2 <= f->countNames(); i2++) {
					if(&f->getName(i2) != ename) {
						str += "\n";
						str += f->getName(i2).name;
					}
				}
				gtk_text_buffer_get_end_iter(buffer, &iter);
				gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, str.c_str(), -1, "italic", NULL);
				str = "";
				str += "\n";
				if(f->subtype() == SUBTYPE_DATA_SET) {
					str += "\n";
					gchar *gstr = g_strdup_printf(_("Retrieves data from the %s data set for a given object and property. If \"info\" is typed as property, a dialog window will pop up with all properties of the object."), f->title().c_str());
					str += gstr;
					g_free(gstr);
					str += "\n";
				}
				if(!f->description().empty()) {
					str += "\n";
					str += f->description();
					str += "\n";
				}
				if(!f->example(true).empty()) {
					str += "\n";
					str += _("Example:");
					str += " ";
					str += f->example(false, ename->name);
					str += "\n";
				}
				if(f->subtype() == SUBTYPE_DATA_SET && !((DataSet*) f)->copyright().empty()) {
					str += "\n";
					str += ((DataSet*) f)->copyright();
					str += "\n";
				}
				gtk_text_buffer_get_end_iter(buffer, &iter);
				gtk_text_buffer_insert(buffer, &iter, str.c_str(), -1);
				if(iargs) {
					str = "\n";
					str += _("Arguments");
					str += "\n";
					gtk_text_buffer_get_end_iter(buffer, &iter);
					gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, str.c_str(), -1, "bold", NULL);
					for(int i2 = 1; i2 <= iargs; i2++) {	
						arg = f->getArgumentDefinition(i2);
						if(arg && !arg->name().empty()) {
							str = arg->name();
						} else {
							str = i2s(i2);	
						}
						str += ": ";
						if(arg) {
							str2 = arg->printlong();
						} else {
							str2 = default_arg.printlong();
						}
						if(i2 > f->minargs()) {
							str2 += " (";
							//optional argument
							str2 += _("optional");
							if(!f->getDefaultValue(i2).empty()) {
								str2 += ", ";
								//argument default, in description
								str2 += _("default: ");
								str2 += f->getDefaultValue(i2);
							}
							str2 += ")";
						}
						str2 += "\n";
						gtk_text_buffer_get_end_iter(buffer, &iter);
						gtk_text_buffer_insert(buffer, &iter, str.c_str(), -1);
						gtk_text_buffer_get_end_iter(buffer, &iter);
						gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, str2.c_str(), -1, "italic", NULL);
					}
				}
				if(!f->condition().empty()) {
					str = "\n";
					str += _("Requirement");
					str += ": ";
					str += f->printCondition();
					str += "\n";
					gtk_text_buffer_get_end_iter(buffer, &iter);
					gtk_text_buffer_insert(buffer, &iter, str.c_str(), -1);
				}
				if(f->subtype() == SUBTYPE_DATA_SET) {
					DataSet *ds = (DataSet*) f;
					str = "\n";
					str += _("Properties");
					str += "\n";
					gtk_text_buffer_get_end_iter(buffer, &iter);
					gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, str.c_str(), -1, "bold", NULL);
					DataPropertyIter it;
					DataProperty *dp = ds->getFirstProperty(&it);
					while(dp) {	
						if(!dp->isHidden()) {
							if(!dp->title(false).empty()) {
								str = dp->title();	
								str += ": ";
							}
							for(size_t i = 1; i <= dp->countNames(); i++) {
								if(i > 1) str += ", ";
								str += dp->getName(i);
							}
							if(dp->isKey()) {
								str += " (";
								//indicating that the property is a data set key
								str += _("key");
								str += ")";
							}
							str += "\n";
							gtk_text_buffer_get_end_iter(buffer, &iter);
							gtk_text_buffer_insert(buffer, &iter, str.c_str(), -1);
							if(!dp->description().empty()) {
								str = dp->description();
								str += "\n";
								gtk_text_buffer_get_end_iter(buffer, &iter);
								gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, str.c_str(), -1, "italic", NULL);
							}
						}
						dp = ds->getNextProperty(&it);
					}
				}
				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functions_builder, "functions_button_edit")), !CALCULATOR->functions[i]->isBuiltin());
				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functions_builder, "functions_button_deactivate")), TRUE);
				if(CALCULATOR->functions[i]->isActive()) {
					gtk_label_set_text_with_mnemonic(GTK_LABEL(gtk_builder_get_object(functions_builder, "functions_buttonlabel_deactivate")), _("Deacti_vate"));
				} else {
					gtk_label_set_text_with_mnemonic(GTK_LABEL(gtk_builder_get_object(functions_builder, "functions_buttonlabel_deactivate")), _("Acti_vate"));
				}
				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functions_builder, "functions_button_insert")), CALCULATOR->functions[i]->isActive());
				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functions_builder, "functions_button_apply")), CALCULATOR->functions[i]->isActive() && (CALCULATOR->functions[i]->minargs() <= 1 || rpn_mode));
				//user cannot delete global definitions
				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functions_builder, "functions_button_delete")), CALCULATOR->functions[i]->isLocal());
			}
		}
	} else {
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functions_builder, "functions_button_edit")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functions_builder, "functions_button_insert")), FALSE);		
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functions_builder, "functions_button_delete")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functions_builder, "functions_button_deactivate")), FALSE);
		gtk_text_buffer_set_text(gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtk_builder_get_object(functions_builder, "functions_textview_description"))), "", -1);
		selected_function = NULL;
	}
}

/*
	generate the variable categories tree in manage variables dialog
*/
void update_variables_tree() {
	if(!variables_builder) return;
	GtkTreeIter iter, iter2, iter3;
	GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(tVariableCategories));
	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tVariableCategories));
	g_signal_handlers_block_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tVariableCategories_selection_changed, NULL);
	gtk_tree_store_clear(tVariableCategories_store);
	g_signal_handlers_unblock_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tVariableCategories_selection_changed, NULL);
	gtk_tree_store_append(tVariableCategories_store, &iter3, NULL);
	gtk_tree_store_set(tVariableCategories_store, &iter3, 0, _("All"), 1, _("All"), -1);
	string str;
	tree_struct *item, *item2;
	variable_cats.it = variable_cats.items.begin();
	if(variable_cats.it != variable_cats.items.end()) {
		item = &*variable_cats.it;
		++variable_cats.it;
		item->it = item->items.begin();
	} else {
		item = NULL;
	}
	str = "";
	iter2 = iter3;
	while(item) {
		gtk_tree_store_append(tVariableCategories_store, &iter, &iter2);
		str += "/";
		str += item->item;
		gtk_tree_store_set(tVariableCategories_store, &iter, 0, item->item.c_str(), 1, str.c_str(), -1);
		if(str == selected_variable_category) {
			EXPAND_TO_ITER(model, tVariableCategories, iter)
			gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tVariableCategories)), &iter);
		}

		while(item && item->it == item->items.end()) {
			size_t str_i = str.rfind("/");
			if(str_i == string::npos) {
				str = "";
			} else {
				str = str.substr(0, str_i);
			}
			item = item->parent;
			gtk_tree_model_iter_parent(model, &iter2, &iter);
			iter = iter2;
		}
		if(item) {
			item2 = &*item->it;
			if(item->it == item->items.begin()) iter2 = iter;
			++item->it;
			item = item2;
			item->it = item->items.begin();	
		}
	}

	if(!variable_cats.objects.empty()) {	
		//add "Uncategorized" category if there are variables without category
		gtk_tree_store_append(tVariableCategories_store, &iter, &iter3);
		EXPAND_TO_ITER(model, tVariableCategories, iter)
		gtk_tree_store_set(tVariableCategories_store, &iter, 0, _("Uncategorized"), 1, _("Uncategorized"), -1);
		if(selected_variable_category == _("Uncategorized")) {
			gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tVariableCategories)), &iter);
		}
	}
	if(!ia_variables.empty()) {
		//add "Inactive" category if there are inactive variables
		gtk_tree_store_append(tVariableCategories_store, &iter, NULL);
		EXPAND_TO_ITER(model, tVariableCategories, iter)
		gtk_tree_store_set(tVariableCategories_store, &iter, 0, _("Inactive"), 1, _("Inactive"), -1);
		if(selected_variable_category == _("Inactive")) {
			gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tVariableCategories)), &iter);
		}
	}	
	if(!gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(tVariableCategories)), &model, &iter)) {
		//if no category has been selected (previously selected has been renamed/deleted), select "All"
		selected_variable_category = _("All");
		gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tVariableCategories_store), &iter);
		EXPAND_ITER(model, tVariableCategories, iter)
		gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tVariableCategories)), &iter);
	}
}

void setVariableTreeItem(GtkTreeIter &iter2, Variable *v) {
	gtk_list_store_append(tVariables_store, &iter2);
	string value = "";
	if(is_answer_variable(v)) {
		value = _("a previous result");
	} else if(v->isKnown()) {
		if(((KnownVariable*) v)->isExpression()) {
			value = CALCULATOR->localizeExpression(((KnownVariable*) v)->expression());
			bool is_relative = false;
			if(!((KnownVariable*) v)->uncertainty(&is_relative).empty()) {
				if(is_relative) {
					value.insert(0, "(");
					value.insert(0, CALCULATOR->f_uncertainty->referenceName());
					value += CALCULATOR->getComma();
					value += " ";
					value += CALCULATOR->localizeExpression(((KnownVariable*) v)->uncertainty());
					value += CALCULATOR->getComma();
					value += " 1)";
				} else {
					value += SIGN_PLUSMINUS;
					value += CALCULATOR->localizeExpression(((KnownVariable*) v)->uncertainty());
				}
			}
			if(!((KnownVariable*) v)->unit().empty()) {value += " "; value += ((KnownVariable*) v)->unit();}
		} else {
			if(((KnownVariable*) v)->get().isMatrix()) {
				value = _("matrix");
			} else if(((KnownVariable*) v)->get().isVector()) {
				value = _("vector");
			} else {
				PrintOptions po;
				po.interval_display = INTERVAL_DISPLAY_PLUSMINUS;
				value = CALCULATOR->print(((KnownVariable*) v)->get(), 30, po);
			}
		}
	} else {
		if(((UnknownVariable*) v)->assumptions()) {
			switch(((UnknownVariable*) v)->assumptions()->sign()) {
				case ASSUMPTION_SIGN_POSITIVE: {value = _("positive"); break;}
				case ASSUMPTION_SIGN_NONPOSITIVE: {value = _("non-positive"); break;}
				case ASSUMPTION_SIGN_NEGATIVE: {value = _("negative"); break;}
				case ASSUMPTION_SIGN_NONNEGATIVE: {value = _("non-negative"); break;}
				case ASSUMPTION_SIGN_NONZERO: {value = _("non-zero"); break;}
				default: {}
			}
			if(!value.empty() && ((UnknownVariable*) v)->assumptions()->type() != ASSUMPTION_TYPE_NONE) value += " ";
			switch(((UnknownVariable*) v)->assumptions()->type()) {
				case ASSUMPTION_TYPE_INTEGER: {value += _("integer"); break;}
				case ASSUMPTION_TYPE_RATIONAL: {value += _("rational"); break;}
				case ASSUMPTION_TYPE_REAL: {value += _("real"); break;}
				case ASSUMPTION_TYPE_COMPLEX: {value += _("complex"); break;}
				case ASSUMPTION_TYPE_NUMBER: {value += _("number"); break;}
				case ASSUMPTION_TYPE_NONMATRIX: {value += _("(not matrix)"); break;}
				default: {}
			}
			if(value.empty()) value = _("unknown");
		} else {
			value = _("default assumptions");
		}		
	}
	gtk_list_store_set(tVariables_store, &iter2, 0, v->title(true).c_str(), 1, value.c_str(), 2, (gpointer) v, 3, TRUE, -1);
	GtkTreeIter iter;
	if(v == selected_variable && gtk_tree_model_filter_convert_child_iter_to_iter(GTK_TREE_MODEL_FILTER(tVariables_store_filter), &iter, &iter2)) {
		gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tVariables)), &iter);
	}
}

/*
	generate the variable tree in manage variables dialog when category selection has changed
*/
void on_tVariableCategories_selection_changed(GtkTreeSelection *treeselection, gpointer) {
	GtkTreeModel *model, *model2;
	GtkTreeIter iter, iter2;
	bool no_cat = false, b_all = false, b_inactive = false;
	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tVariables));
	g_signal_handlers_block_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_variables_entry_search_changed, NULL);
	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(variables_builder, "variables_entry_search")), "");
	g_signal_handlers_unblock_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_variables_entry_search_changed, NULL);
	g_signal_handlers_block_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tVariables_selection_changed, NULL);
	gtk_list_store_clear(tVariables_store);
	g_signal_handlers_unblock_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tVariables_selection_changed, NULL);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_button_edit")), FALSE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_button_insert")), FALSE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_button_delete")), FALSE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_button_deactivate")), FALSE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_button_export")), FALSE);

	if(gtk_tree_selection_get_selected(treeselection, &model, &iter)) {
		gchar *gstr;
		gtk_tree_model_get(model, &iter, 1, &gstr, -1);
		selected_variable_category = gstr;		
		if(selected_variable_category == _("All")) {
			b_all = true;
		} else if(selected_variable_category == _("Uncategorized")) {
			no_cat = true;
		} else if(selected_variable_category == _("Inactive")) {
			b_inactive = true;
		}

		if(!b_all && !no_cat && !b_inactive && selected_variable_category[0] == '/') {
			string str = selected_variable_category.substr(1, selected_variable_category.length() - 1);
			for(size_t i = 0; i < CALCULATOR->variables.size(); i++) {
				if(CALCULATOR->variables[i]->isActive() && CALCULATOR->variables[i]->category().substr(0, selected_variable_category.length() - 1) == str) {
					setVariableTreeItem(iter2, CALCULATOR->variables[i]);
				}
			}			
		} else {			
			for(size_t i = 0; i < CALCULATOR->variables.size(); i++) {
				if((b_inactive && !CALCULATOR->variables[i]->isActive()) || (CALCULATOR->variables[i]->isActive() && (b_all || (no_cat && CALCULATOR->variables[i]->category().empty()) || (!b_inactive && CALCULATOR->variables[i]->category() == selected_variable_category)))) {
					setVariableTreeItem(iter2, CALCULATOR->variables[i]);
				}
			}
		}

		if(!selected_variable || !gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(tVariables)), &model2, &iter2)) {
			if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tVariables_store_filter), &iter2)) {
				gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tVariables)), &iter2);
			}
		}
		g_free(gstr);

	} else {
		selected_variable_category = "";
	}

}

/*
	variable selection has changed
*/
void on_tVariables_selection_changed(GtkTreeSelection *treeselection, gpointer) {
	GtkTreeModel *model;
	GtkTreeIter iter;
	if(gtk_tree_selection_get_selected(treeselection, &model, &iter)) {
		Variable *v;
		gtk_tree_model_get(model, &iter, 2, &v, -1);
		if(!CALCULATOR->stillHasVariable(v)) {
			show_message(_("Variable does not exist anymore."), GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_dialog")));
			selected_variable = NULL;
			update_vmenu();
			return;
		}
		//remember selection
		selected_variable = v;
		for(size_t i = 0; i < CALCULATOR->variables.size(); i++) {
			if(CALCULATOR->variables[i] == selected_variable) {
				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_button_edit")), !CALCULATOR->variables[i]->isBuiltin() && !is_answer_variable(CALCULATOR->variables[i]));
				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_button_insert")), CALCULATOR->variables[i]->isActive());
				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_button_deactivate")), !is_answer_variable(CALCULATOR->variables[i]));
				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_button_export")), CALCULATOR->variables[i]->isKnown());
				if(CALCULATOR->variables[i]->isActive()) {
					gtk_label_set_text_with_mnemonic(GTK_LABEL(gtk_builder_get_object(variables_builder, "variables_buttonlabel_deactivate")), _("Deacti_vate"));
				} else {
					gtk_label_set_text_with_mnemonic(GTK_LABEL(gtk_builder_get_object(variables_builder, "variables_buttonlabel_deactivate")), _("Acti_vate"));
				}
				//user cannot delete global definitions
				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_button_delete")), CALCULATOR->variables[i]->isLocal() && !is_answer_variable(CALCULATOR->variables[i]) && CALCULATOR->variables[i] != CALCULATOR->v_x && CALCULATOR->variables[i] != CALCULATOR->v_y && CALCULATOR->variables[i] != CALCULATOR->v_z);
			}
		}
	} else {
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_button_edit")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_button_insert")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_button_delete")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_button_deactivate")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_button_export")), FALSE);
		selected_variable = NULL;
	}
}


/*
	generate the unit categories tree in manage units dialog
*/
void update_units_tree() {
	if(!units_builder) return;
	GtkTreeIter iter, iter2, iter3;
	GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(tUnitCategories));
	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitCategories));
	g_signal_handlers_block_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tUnitCategories_selection_changed, NULL);
	gtk_tree_store_clear(tUnitCategories_store);
	g_signal_handlers_unblock_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tUnitCategories_selection_changed, NULL);
	gtk_tree_store_append(tUnitCategories_store, &iter3, NULL);
	gtk_tree_store_set(tUnitCategories_store, &iter3, 0, _("All"), 1, _("All"), -1);
	string str;
	tree_struct *item, *item2;
	unit_cats.it = unit_cats.items.begin();
	if(unit_cats.it != unit_cats.items.end()) {
		item = &*unit_cats.it;
		++unit_cats.it;
		item->it = item->items.begin();
	} else {
		item = NULL;
	}
	str = "";
	iter2 = iter3;
	while(item) {
		gtk_tree_store_append(tUnitCategories_store, &iter, &iter2);
		str += "/";
		str += item->item;
		gtk_tree_store_set(tUnitCategories_store, &iter, 0, item->item.c_str(), 1, str.c_str(), -1);
		if(str == selected_unit_category) {
			EXPAND_TO_ITER(model, tUnitCategories, iter)
			gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitCategories)), &iter);
		}
		while(item && item->it == item->items.end()) {
			size_t str_i = str.rfind("/");
			if(str_i == string::npos) {
				str = "";
			} else {
				str = str.substr(0, str_i);
			}
			item = item->parent;
			gtk_tree_model_iter_parent(model, &iter2, &iter);
			iter = iter2;
		}
		if(item) {
			item2 = &*item->it;
			if(item->it == item->items.begin()) iter2 = iter;
			++item->it;
			item = item2;
			item->it = item->items.begin();	
		}
	}
	if(!unit_cats.objects.empty()) {	
		//add "Uncategorized" category if there are units without category
		gtk_tree_store_append(tUnitCategories_store, &iter, &iter3);
		gtk_tree_store_set(tUnitCategories_store, &iter, 0, _("Uncategorized"), 1, _("Uncategorized"), -1);
		if(selected_unit_category == _("Uncategorized")) {
			EXPAND_TO_ITER(model, tUnitCategories, iter)
			gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitCategories)), &iter);
		}
	}	
	if(!ia_units.empty()) {
		gtk_tree_store_append(tUnitCategories_store, &iter, NULL);
		gtk_tree_store_set(tUnitCategories_store, &iter, 0, _("Inactive"), 1, _("Inactive"), -1);
		if(selected_unit_category == _("Inactive")) {
			EXPAND_TO_ITER(model, tUnitCategories, iter)
			gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitCategories)), &iter);
		}	
	}
	if(!gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitCategories)), &model, &iter)) {
		//if no category has been selected (previously selected has been renamed/deleted), select "All"
		selected_unit_category = _("All");
		gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tUnitCategories_store), &iter);
		EXPAND_ITER(model, tUnitCategories, iter)
		gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitCategories)), &iter);
	}
}

void setUnitTreeItem(GtkTreeIter &iter2, Unit *u) {
	gtk_list_store_append(tUnits_store, &iter2);
	string snames, sbase;
	//display name, plural name and short name in the second column
	AliasUnit *au;
	for(size_t i = 1; i <= u->countNames(); i++) {
		if(i > 1) snames += " / ";
		snames += u->getName(i).name;
	}
	//depending on unit type display relation to base unit(s)
	switch(u->subtype()) {
		case SUBTYPE_COMPOSITE_UNIT: {
			snames = "";
			sbase = ((CompositeUnit*) u)->print(false, true, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) tUnits);
			break;
		}
		case SUBTYPE_ALIAS_UNIT: {
			au = (AliasUnit*) u;
			sbase = au->firstBaseUnit()->preferredDisplayName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) tUnits).name;
			if(au->firstBaseExponent() != 1) {
				sbase += POWER;
				sbase += i2s(au->firstBaseExponent());
			}
			break;
		}
		case SUBTYPE_BASE_UNIT: {
			sbase = "";
			break;
		}
	}
	//display descriptive name (title), or name if no title defined
	gtk_list_store_set(tUnits_store, &iter2, UNITS_TITLE_COLUMN, u->title(true).c_str(), UNITS_NAMES_COLUMN, snames.c_str(), UNITS_BASE_COLUMN, sbase.c_str(), UNITS_POINTER_COLUMN, (gpointer) u, UNITS_VISIBLE_COLUMN, TRUE, UNITS_VISIBLE_COLUMN_CONVERT, TRUE, -1);
	if(u->isCurrency()) {
		unordered_map<string, GdkPixbuf*>::const_iterator it_flag = flag_images.find(u->referenceName()); 
		if(it_flag != flag_images.end()) {
			gtk_list_store_set(tUnits_store, &iter2, UNITS_FLAG_COLUMN, it_flag->second, -1);
		}
	}
	GtkTreeIter iter;
	if(u == selected_unit && gtk_tree_model_filter_convert_child_iter_to_iter(GTK_TREE_MODEL_FILTER(tUnits_store_filter), &iter, &iter2)) {
		gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnits)), &iter);
	}
}

/*
	generate the unit tree and units conversion menu in manage units dialog when category selection has changed
*/
void on_tUnitCategories_selection_changed(GtkTreeSelection *treeselection, gpointer) {
	GtkTreeModel *model, *model2;
	GtkTreeIter iter, iter2;
	//make sure that no unit conversion is done in the dialog until everthing is updated
	block_unit_convert = true;
	bool no_cat = false, b_all = false, b_inactive = false;
	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnits));
	g_signal_handlers_block_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_units_entry_search_changed, NULL);
	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(units_builder, "units_entry_search")), "");
	g_signal_handlers_unblock_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_units_entry_search_changed, NULL);
	g_signal_handlers_block_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_units_convert_search_changed, NULL);
	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(units_builder, "units_convert_search")), "");
	g_signal_handlers_unblock_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_units_convert_search_changed, NULL);
	g_signal_handlers_block_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tUnits_selection_changed, NULL);
	gtk_list_store_clear(tUnits_store);
	g_signal_handlers_unblock_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tUnits_selection_changed, NULL);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_button_edit")), FALSE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_button_insert")), FALSE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_button_delete")), FALSE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_button_deactivate")), FALSE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_button_convert_to")), FALSE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_frame_convert")), FALSE);
	bool b_sel = false;
	if(gtk_tree_selection_get_selected(treeselection, &model, &iter)) {
		bool b_currencies = false;
		gchar *gstr;
		gtk_tree_model_get(model, &iter, 1, &gstr, -1);
		selected_unit_category = gstr;
		if(selected_unit_category == _("All")) {
			b_all = true;
		} else if(selected_unit_category == _("Uncategorized")) {
			no_cat = true;
		} else if(selected_unit_category == _("Inactive")) {
			b_inactive = true;
		}
		if(!b_all && !no_cat && !b_inactive && selected_unit_category[0] == '/') {
			string str = selected_unit_category.substr(1, selected_unit_category.length() - 1);
			for(size_t i = 0; i < CALCULATOR->units.size(); i++) {	
				if(CALCULATOR->units[i]->isActive() && CALCULATOR->units[i]->category().substr(0, selected_unit_category.length() - 1) == str) {
					if(CALCULATOR->units[i]->isCurrency()) b_currencies = true;
					setUnitTreeItem(iter2, CALCULATOR->units[i]);
					if(!b_sel && selected_to_unit == CALCULATOR->units[i]) b_sel = true;
				}
			}
		} else {
			for(size_t i = 0; i < CALCULATOR->units.size(); i++) {
				if((b_inactive && !CALCULATOR->units[i]->isActive()) || (CALCULATOR->units[i]->isActive() && (b_all || (no_cat && CALCULATOR->units[i]->category().empty()) || (!b_inactive && CALCULATOR->units[i]->category() == selected_unit_category)))) {
					if(!b_all && !no_cat && !b_inactive && !b_currencies && CALCULATOR->units[i]->isCurrency()) b_currencies = true;
					setUnitTreeItem(iter2, CALCULATOR->units[i]);
					if(!b_sel && selected_to_unit == CALCULATOR->units[i]) b_sel = true;
				}
			}
		}
		if(!selected_unit || !gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnits)), &model2, &iter2)) {
			if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tUnits_store_filter), &iter2)) {
				gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnits)), &iter2);
			}
		}
		gtk_tree_view_column_set_visible(units_flag_column, b_currencies);
		gtk_cell_renderer_set_visible(units_convert_flag_renderer, b_currencies);
		g_free(gstr);
	} else {
		selected_unit_category = "";
	}
	if(!b_sel) {
		if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(units_convert_filter), &iter2)) {
			GtkTreePath *path = gtk_tree_model_get_path(units_convert_filter, &iter2);
			on_units_convert_view_row_activated(GTK_TREE_VIEW(units_convert_view), path, NULL, NULL);
			gtk_tree_path_free(path);
		}
	}
	block_unit_convert = false;
	//update conversion display
	convert_in_wUnits();
}

/*
	unit selection has changed
*/
void on_tUnits_selection_changed(GtkTreeSelection *treeselection, gpointer) {
	GtkTreeModel *model;
	GtkTreeIter iter;
	if(gtk_tree_selection_get_selected(treeselection, &model, &iter)) {
		Unit *u;
		gtk_tree_model_get(model, &iter, UNITS_POINTER_COLUMN, &u, -1);
		selected_unit = u;
		for(size_t i = 0; i < CALCULATOR->units.size(); i++) {
			if(CALCULATOR->units[i] == selected_unit) {
				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_frame_convert")), TRUE);				
				gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(units_builder, "units_label_from_unit")), CALCULATOR->units[i]->print(true, printops.abbreviate_names, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) gtk_builder_get_object(units_builder, "units_label_from_unit")).c_str());
				//user cannot delete global definitions
				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_button_delete")), CALCULATOR->units[i]->isLocal());
				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_button_convert_to")), TRUE);
				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_button_insert")), CALCULATOR->units[i]->isActive());
				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_button_edit")), !CALCULATOR->units[i]->isBuiltin());
				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_button_deactivate")), TRUE);
				if(CALCULATOR->units[i]->isActive()) {
					gtk_label_set_text_with_mnemonic(GTK_LABEL(gtk_builder_get_object(units_builder, "units_buttonlabel_deactivate")), _("Deacti_vate"));
				} else {
					gtk_label_set_text_with_mnemonic(GTK_LABEL(gtk_builder_get_object(units_builder, "units_buttonlabel_deactivate")), _("Acti_vate"));
				}
			}
		}
	} else {
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_button_edit")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_button_insert")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_button_delete")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_button_deactivate")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_button_convert_to")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_frame_convert")), FALSE);
		selected_unit = NULL;
	}
	if(!block_unit_convert) convert_in_wUnits();
}

void update_unit_selector_tree() {
	GtkTreeIter iter, iter2, iter3;
	GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(tUnitSelectorCategories));
	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitSelectorCategories));
	g_signal_handlers_block_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tUnitSelectorCategories_selection_changed, NULL);
	gtk_tree_store_clear(tUnitSelectorCategories_store);
	g_signal_handlers_unblock_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tUnitSelectorCategories_selection_changed, NULL);
	gtk_tree_store_append(tUnitSelectorCategories_store, &iter3, NULL);
	gtk_tree_store_set(tUnitSelectorCategories_store, &iter3, 0, _("All"), 1, _("All"), -1);
	string str;
	tree_struct *item, *item2;
	unit_cats.it = unit_cats.items.begin();
	if(unit_cats.it != unit_cats.items.end()) {
		item = &*unit_cats.it;
		++unit_cats.it;
		item->it = item->items.begin();
	} else {
		item = NULL;
	}
	str = "";
	iter2 = iter3;
	convert_category_map.clear();
	while(item) {
		gtk_tree_store_append(tUnitSelectorCategories_store, &iter, &iter2);
		if(!str.empty()) str += "/";
		str += item->item;
		gtk_tree_store_set(tUnitSelectorCategories_store, &iter, 0, item->item.c_str(), 1, str.c_str(), -1);
		if(str == selected_unit_category) {
			EXPAND_TO_ITER(model, tUnitSelectorCategories, iter)
			gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitSelectorCategories)), &iter);
		}
		convert_category_map[str] = iter;
		while(item && item->it == item->items.end()) {
			size_t str_i = str.rfind("/");
			if(str_i == string::npos) {
				str = "";
			} else {
				str = str.substr(0, str_i);
			}
			item = item->parent;
			gtk_tree_model_iter_parent(model, &iter2, &iter);
			iter = iter2;
		}
		if(item) {
			item2 = &*item->it;
			if(item->it == item->items.begin()) iter2 = iter;
			++item->it;
			item = item2;
			item->it = item->items.begin();	
		}
	}
	if(!unit_cats.objects.empty()) {	
		//add "Uncategorized" category if there are units without category
		gtk_tree_store_append(tUnitSelectorCategories_store, &iter, &iter3);
		gtk_tree_store_set(tUnitSelectorCategories_store, &iter, 0, _("Uncategorized"), 1, _("Uncategorized"), -1);
		convert_category_map[_("Uncategorized")] = iter;
		if(selected_unit_category == _("Uncategorized")) {
			EXPAND_TO_ITER(model, tUnitSelectorCategories, iter)
			gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitSelectorCategories)), &iter);
		}
	}	
	if(!gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitSelectorCategories)), &model, &iter)) {
		//if no category has been selected (previously selected has been renamed/deleted), select "All"
		selected_unit_category = _("All");
		gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tUnitSelectorCategories_store), &iter);
		EXPAND_ITER(model, tUnitSelectorCategories, iter)
		gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitSelectorCategories)), &iter);
	}
}

void on_functions_entry_search_changed(GtkEntry *w, gpointer) {
	GtkTreeIter iter;
	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tFunctions));
	g_signal_handlers_block_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tFunctions_selection_changed, NULL);
	if(!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tFunctions_store), &iter)) return;
	string str = gtk_entry_get_text(w);
	remove_blank_ends(str);
	do {
		bool b = str.empty();
		MathFunction *u = NULL;
		if(!b) gtk_tree_model_get(GTK_TREE_MODEL(tFunctions_store), &iter, 1, &u, -1);
		if(u) {
			string title = u->title(true);
			remove_blank_ends(title);
			while(title.length() >= str.length()) {
				if(equalsIgnoreCase(str, title.substr(0, str.length()))) {
					b = true;
					break;
				}
				size_t i = title.find(' ');
				if(i == string::npos) break;
				title = title.substr(i + 1);
				remove_blank_ends(title);
			}
			for(size_t i2 = 1; i2 <= u->countNames(); i2++) {
				if(u->getName(i2).case_sensitive) {
					if(str == u->getName(i2).name.substr(0, str.length())) {
						b = true;
						break;
					}
				} else {
					if(equalsIgnoreCase(str, u->getName(i2).name.substr(0, str.length()))) {
						b = true;
						break;
					}
				}
			}
		}
		gtk_list_store_set(tFunctions_store, &iter, 2, b, -1);
	} while(gtk_tree_model_iter_next(GTK_TREE_MODEL(tFunctions_store), &iter));
	g_signal_handlers_unblock_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tFunctions_selection_changed, NULL);
	if(str.empty()) {
		gtk_widget_grab_focus(tFunctions);
	} else {
		if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tFunctions_store_filter), &iter)) {
			gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(tFunctions)));
			gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tFunctions)), &iter);
			GtkTreePath *path = gtk_tree_model_get_path(tFunctions_store_filter, &iter);
			if(path) {
				gtk_tree_view_set_cursor(GTK_TREE_VIEW(tFunctions), path, NULL, FALSE);
				gtk_tree_path_free(path);
			}
		}
	}
}
void on_variables_entry_search_changed(GtkEntry *w, gpointer) {
	GtkTreeIter iter;
	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tVariables));
	g_signal_handlers_block_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tVariables_selection_changed, NULL);
	if(!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tVariables_store), &iter)) return;
	string str = gtk_entry_get_text(w);
	remove_blank_ends(str);
	do {
		bool b = str.empty();
		Variable *u = NULL;
		if(!b) gtk_tree_model_get(GTK_TREE_MODEL(tVariables_store), &iter, 2, &u, -1);
		if(u) {
			string title = u->title(true);
			remove_blank_ends(title);
			while(title.length() >= str.length()) {
				if(equalsIgnoreCase(str, title.substr(0, str.length()))) {
					b = true;
					break;
				}
				size_t i = title.find(' ');
				if(i == string::npos) break;
				title = title.substr(i + 1);
				remove_blank_ends(title);
			}
			for(size_t i2 = 1; i2 <= u->countNames(); i2++) {
				if(u->getName(i2).case_sensitive) {
					if(str == u->getName(i2).name.substr(0, str.length())) {
						b = true;
						break;
					}
				} else {
					if(equalsIgnoreCase(str, u->getName(i2).name.substr(0, str.length()))) {
						b = true;
						break;
					}
				}
			}
		}
		gtk_list_store_set(tVariables_store, &iter, 3, b, -1);
	} while(gtk_tree_model_iter_next(GTK_TREE_MODEL(tVariables_store), &iter));
	g_signal_handlers_unblock_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tVariables_selection_changed, NULL);
	if(str.empty()) {
		gtk_widget_grab_focus(tVariables);
	} else {
		if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tVariables_store_filter), &iter)) {
			gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(tVariables)));
			gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tVariables)), &iter);
			GtkTreePath *path = gtk_tree_model_get_path(tVariables_store_filter, &iter);
			if(path) {
				gtk_tree_view_set_cursor(GTK_TREE_VIEW(tVariables), path, NULL, FALSE);
				gtk_tree_path_free(path);
			}
		}
	}
}

void on_units_entry_search_changed(GtkEntry *w, gpointer) {
	GtkTreeIter iter;
	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnits));
	g_signal_handlers_block_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tUnits_selection_changed, NULL);
	if(!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tUnits_store), &iter)) return;
	string str = gtk_entry_get_text(w);
	remove_blank_ends(str);
	do {
		bool b = str.empty();
		Unit *u = NULL;
		if(!b) gtk_tree_model_get(GTK_TREE_MODEL(tUnits_store), &iter, UNITS_POINTER_COLUMN, &u, -1);
		if(u) {
			b = name_matches(u, str);
			if(!b) b = title_matches(u, str);
			if(!b) b = country_matches(u, str);
		}
		gtk_list_store_set(tUnits_store, &iter, UNITS_VISIBLE_COLUMN, b, -1);
	} while(gtk_tree_model_iter_next(GTK_TREE_MODEL(tUnits_store), &iter));
	g_signal_handlers_unblock_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tUnits_selection_changed, NULL);
	if(str.empty()) {
		gtk_widget_grab_focus(tUnits);
	} else {
		if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tUnits_store_filter), &iter)) {
			gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnits)));
			gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnits)), &iter);
			GtkTreePath *path = gtk_tree_model_get_path(tUnits_store_filter, &iter);
			if(path) {
				gtk_tree_view_set_cursor(GTK_TREE_VIEW(tUnits), path, NULL, FALSE);
				gtk_tree_path_free(path);
			}
		}
	}
}

void on_units_convert_search_changed(GtkEntry *w, gpointer) {
	GtkTreeIter iter;
	if(!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tUnits_store), &iter)) return;
	string str = gtk_entry_get_text(w);
	remove_blank_ends(str);
	do {
		bool b = str.empty();
		Unit *u = NULL;
		if(!b) gtk_tree_model_get(GTK_TREE_MODEL(tUnits_store), &iter, UNITS_POINTER_COLUMN, &u, -1);
		if(u) {
			b = name_matches(u, str);
			if(!b) b = title_matches(u, str);
			if(!b) b = country_matches(u, str);
		}
		gtk_list_store_set(tUnits_store, &iter, UNITS_VISIBLE_COLUMN_CONVERT, b, -1);
	} while(gtk_tree_model_iter_next(GTK_TREE_MODEL(tUnits_store), &iter));
	if(!str.empty()) {
		if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(units_convert_filter), &iter)) {
			gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(units_convert_view)));
			gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(units_convert_view)), &iter);
		}
	}
	while(gtk_events_pending()) gtk_main_iteration();
	//if(gtk_widget_is_visible(units_convert_window)) units_convert_resize_popup();
}

void on_convert_entry_search_changed(GtkEntry *w, gpointer) {
	GtkTreeIter iter;
	int count = 0;
	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitSelector));
	g_signal_handlers_block_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tUnitSelector_selection_changed, NULL);
	if(!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tUnitSelector_store), &iter)) return;
	string str = gtk_entry_get_text(w);
	remove_blank_ends(str);
	do {
		bool b = str.empty();
		Unit *u = NULL;
		if(!b) gtk_tree_model_get(GTK_TREE_MODEL(tUnitSelector_store), &iter, 1, &u, -1);
		if(u) {			
			b = name_matches(u, str);
			if(!b) b = title_matches(u, str);
			if(!b) b = country_matches(u, str);
		}
		if(b) count++;
		gtk_list_store_set(tUnitSelector_store, &iter, 3, b, -1);
	} while(gtk_tree_model_iter_next(GTK_TREE_MODEL(tUnitSelector_store), &iter));
	/*if(str.empty() && count < 30) {
		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "convert_entry_search")));
		gtk_widget_grab_focus(tUnitSelector);
	}*/
	g_signal_handlers_unblock_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tUnitSelector_selection_changed, NULL);
	if(!str.empty()) {
		if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tUnitSelector_store_filter), &iter)) {
			gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitSelector)));
			gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitSelector)), &iter);
			GtkTreePath *path = gtk_tree_model_get_path(tUnitSelector_store_filter, &iter);
			if(path) {
				gtk_tree_view_set_cursor(GTK_TREE_VIEW(tUnitSelector), path, NULL, FALSE);
				gtk_tree_path_free(path);
			}
		}
	}
}

void setUnitSelectorTreeItem(GtkTreeIter &iter2, Unit *u) {
	gtk_list_store_append(tUnitSelector_store, &iter2);
	string snames, sbase;
	if(u->isCurrency()) {
		unordered_map<string, GdkPixbuf*>::const_iterator it_flag = flag_images.find(u->referenceName()); 
		gtk_list_store_set(tUnitSelector_store, &iter2, 0, u->title(true).c_str(), 1, (gpointer) u, 2, it_flag == flag_images.end() ? NULL : it_flag->second, 3, TRUE, -1);
	} else {
		gtk_list_store_set(tUnitSelector_store, &iter2, 0, u->title(true).c_str(), 1, (gpointer) u, 3, TRUE, -1);
	}
}

/*
	generate the unit tree in conversion tab when category selection has changed
*/
void on_tUnitSelectorCategories_selection_changed(GtkTreeSelection *treeselection, gpointer) {

	block_unit_selector_convert = true;

	GtkTreeModel *model;
	GtkTreeIter iter, iter2;

	bool no_cat = false, b_all = false;
	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitSelector));
	g_signal_handlers_block_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_convert_entry_search_changed, NULL);
	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(main_builder, "convert_entry_search")), "");
	g_signal_handlers_unblock_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_convert_entry_search_changed, NULL);
	g_signal_handlers_block_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tUnitSelector_selection_changed, NULL);
	gtk_list_store_clear(tUnitSelector_store);
	g_signal_handlers_unblock_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tUnitSelector_selection_changed, NULL);
	int count = 0;
	if(gtk_tree_selection_get_selected(treeselection, &model, &iter)) {
		gchar *gstr;
		gtk_tree_model_get(model, &iter, 1, &gstr, -1);
		selected_unit_selector_category = gstr;
		if(selected_unit_selector_category == _("All")) {
			b_all = true;
		} else if(selected_unit_selector_category == _("Uncategorized")) {
			no_cat = true;
		}
		bool b_currencies = false;
		if(!b_all && !no_cat && selected_unit_selector_category[0] == '/') {
			string str = selected_unit_selector_category.substr(1, selected_unit_selector_category.length() - 1);
			for(size_t i = 0; i < CALCULATOR->units.size(); i++) {	
				if(CALCULATOR->units[i]->isActive() && (!CALCULATOR->units[i]->isHidden() || CALCULATOR->units[i]->isCurrency()) && CALCULATOR->units[i]->category().substr(0, selected_unit_selector_category.length() - 1) == str) {
					if(!b_currencies && CALCULATOR->units[i]->isCurrency()) b_currencies = true;
					setUnitSelectorTreeItem(iter2, CALCULATOR->units[i]);
					count++;
				}
			}
		} else {
			bool list_empty = true;
			for(size_t i = 0; i < CALCULATOR->units.size(); i++) {
				if(CALCULATOR->units[i]->isActive() && (!CALCULATOR->units[i]->isHidden() || CALCULATOR->units[i]->isCurrency()) && (b_all || (no_cat && CALCULATOR->units[i]->category().empty()) || CALCULATOR->units[i]->category() == selected_unit_selector_category)) {
					if(!b_currencies && !b_all && !no_cat && CALCULATOR->units[i]->isCurrency()) b_currencies = true;
					setUnitSelectorTreeItem(iter2, CALCULATOR->units[i]);
					count++;
					list_empty = false;
				}
			}
			bool collapse_all = true;
			if(list_empty && !b_all && !no_cat) {
				for(size_t i = 0; i < CALCULATOR->units.size(); i++) {
					if(CALCULATOR->units[i]->isActive() && (!CALCULATOR->units[i]->isHidden() || CALCULATOR->units[i]->isCurrency()) && CALCULATOR->units[i]->category().length() > selected_unit_selector_category.length() && CALCULATOR->units[i]->category()[selected_unit_selector_category.length()] == '/' && CALCULATOR->units[i]->category().substr(0, selected_unit_selector_category.length()) == selected_unit_selector_category) {
						if(!b_currencies && !b_all && !no_cat && CALCULATOR->units[i]->isCurrency()) b_currencies = true;
						setUnitSelectorTreeItem(iter2, CALCULATOR->units[i]);
						count++;
					}
				}
			} else if(!b_all && !no_cat) {
				GtkTreePath *path = gtk_tree_model_get_path(model, &iter);
				collapse_all = !gtk_tree_view_expand_row(GTK_TREE_VIEW(tUnitSelectorCategories), path, FALSE);
				gtk_tree_path_free(path);
			}
			if(collapse_all) {
				GtkTreePath *path = gtk_tree_model_get_path(model, &iter);
				if(gtk_tree_path_get_depth(path) == 2) {
					GtkTreeIter iter3;
					gtk_tree_model_get_iter_first(model, &iter3);
					if(gtk_tree_model_iter_children(model, &iter2, &iter3)) {
						do {
							GtkTreePath *path2 = gtk_tree_model_get_path(model, &iter2);
							if(gtk_tree_path_compare(path, path2) != 0) gtk_tree_view_collapse_row(GTK_TREE_VIEW(tUnitSelectorCategories), path2);
							gtk_tree_path_free(path2);
						} while(gtk_tree_model_iter_next(model, &iter2));
					}
					gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(tUnitSelectorCategories), path, NULL, FALSE, 0, 0);
				}
				gtk_tree_path_free(path);
			}
		}
		gtk_tree_view_column_set_visible(flag_column, b_currencies);
		g_free(gstr);
	} else {
		selected_unit_selector_category = "";
	}	
	//gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "convert_entry_search")), count >= 30);
	block_unit_selector_convert = false;
	
}

void on_tUnitSelector_selection_changed(GtkTreeSelection *treeselection, gpointer) {
	GtkTreeModel *model;
	GtkTreeIter iter;
	if(gtk_tree_selection_get_selected(treeselection, &model, &iter)) {
		Unit *u;
		gtk_tree_model_get(model, &iter, 1, &u, -1);
		keep_unit_selection = true;
		for(size_t i = 0; i < CALCULATOR->units.size(); i++) {
			if(CALCULATOR->units[i] == u) {
				if(u->subtype() == SUBTYPE_COMPOSITE_UNIT) {
					gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(main_builder, "convert_entry_unit")), ((CompositeUnit*) u)->print(true, printops.abbreviate_names, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) gtk_builder_get_object(main_builder, "convert_entry_unit")).c_str());
				} else {
					gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(main_builder, "convert_entry_unit")), u->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) gtk_builder_get_object(main_builder, "convert_entry_unit")).name.c_str());
				}
				if(!block_unit_selector_convert) convert_from_convert_entry_unit();
			}
		}
		keep_unit_selection = false;
	}
}


void update_datasets_tree() {
	if(!datasets_builder) return;
	GtkTreeIter iter;
	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tDatasets));
	g_signal_handlers_block_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tDatasets_selection_changed, NULL);
	gtk_list_store_clear(tDatasets_store);
	DataSet *ds;
	bool b = false;
	for(size_t i = 1; ; i++) {
		ds = CALCULATOR->getDataSet(i);
		if(!ds) break;
		gtk_list_store_append(tDatasets_store, &iter);
		gtk_list_store_set(tDatasets_store, &iter, 0, ds->title().c_str(), 1, (gpointer) ds, -1);
		if(ds == selected_dataset) {
			g_signal_handlers_unblock_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tDatasets_selection_changed, NULL);
			gtk_tree_selection_select_iter(select, &iter);
			g_signal_handlers_block_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tDatasets_selection_changed, NULL);
			b = true;
		}
	}
	g_signal_handlers_unblock_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tDatasets_selection_changed, NULL);
	if(!b) {
		gtk_tree_selection_unselect_all(select);
		selected_dataset = NULL;
	}
}

void on_tDatasets_selection_changed(GtkTreeSelection *treeselection, gpointer) {
	GtkTreeModel *model, *model2;
	GtkTreeIter iter, iter2;
	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tDataObjects));
	gtk_tree_selection_unselect_all(select);
	g_signal_handlers_block_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tDataObjects_selection_changed, NULL);
	gtk_list_store_clear(tDataObjects_store);
	g_signal_handlers_unblock_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tDataObjects_selection_changed, NULL);
	if(gtk_tree_selection_get_selected(treeselection, &model, &iter)) {
		DataSet *ds = NULL;
		gtk_tree_model_get(model, &iter, 1, &ds, -1);
		selected_dataset = ds;
		if(!ds) return;
		DataObjectIter it;
		DataPropertyIter pit;
		DataProperty *dp;
		DataObject *o = ds->getFirstObject(&it);
		bool b = false;
		while(o) {
			b = true;
			gtk_list_store_append(tDataObjects_store, &iter2);
			dp = ds->getFirstProperty(&pit);
			size_t index = 0;
			while(dp) {
				if(!dp->isHidden() && dp->isKey()) {
					gtk_list_store_set(tDataObjects_store, &iter2, index, o->getPropertyDisplayString(dp).c_str(), -1);
					index++;
					if(index > 2) break;
				}
				dp = ds->getNextProperty(&pit);
			}
			while(index < 3) {
				gtk_list_store_set(tDataObjects_store, &iter2, index, "", -1);
				index++;
			}
			gtk_list_store_set(tDataObjects_store, &iter2, 3, (gpointer) o, -1);
			if(o == selected_dataobject) {
				gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tDataObjects)), &iter2);
			}
			o = ds->getNextObject(&it);
		}
		if(b && (!selected_dataobject || !gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(tDataObjects)), &model2, &iter2))) {
			gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tDataObjects_store), &iter2);
			gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tDataObjects)), &iter2);
		}
		GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtk_builder_get_object(datasets_builder, "datasets_textview_description")));
		gtk_text_buffer_set_text(buffer, "", -1);
		GtkTextIter iter;
		string str, str2;
		if(!ds->description().empty()) {
			str = ds->description();
			str += "\n";
			str += "\n";
			gtk_text_buffer_get_end_iter(buffer, &iter);
			gtk_text_buffer_insert(buffer, &iter, str.c_str(), -1);
		}	
		str = _("Properties");
		str += "\n";
		gtk_text_buffer_get_end_iter(buffer, &iter);
		gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, str.c_str(), -1, "bold", NULL);
		dp = ds->getFirstProperty(&pit);
		while(dp) {	
			if(!dp->isHidden()) {
				str = "";
				if(!dp->title(false).empty()) {
					str += dp->title();	
					str += ": ";
				}
				for(size_t i = 1; i <= dp->countNames(); i++) {
					if(i > 1) str += ", ";
					str += dp->getName(i);
				}
				if(dp->isKey()) {
					str += " (";
					str += _("key");
					str += ")";
				}
				str += "\n";
				gtk_text_buffer_get_end_iter(buffer, &iter);
				gtk_text_buffer_insert(buffer, &iter, str.c_str(), -1);
				if(!dp->description().empty()) {
					str = dp->description();
					str += "\n";
					gtk_text_buffer_get_end_iter(buffer, &iter);
					gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, str.c_str(), -1, "italic", NULL);
				}
			}
			dp = ds->getNextProperty(&pit);
		}
		str = "\n";
		str += _("Data Retrieval Function");
		gtk_text_buffer_get_end_iter(buffer, &iter);
		gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, str.c_str(), -1, "bold", NULL);
		Argument *arg;
		Argument default_arg;
		const ExpressionName *ename = &ds->preferredName(false, true, false, false, &can_display_unicode_string_function, (void*) gtk_builder_get_object(datasets_builder, "datasets_textview_description"));
		str = "\n";
		str += ename->name;
		gtk_text_buffer_get_end_iter(buffer, &iter);
		gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, str.c_str(), -1, "bold", "italic", NULL);
		str = "";
		int iargs = ds->maxargs();
		if(iargs < 0) {
			iargs = ds->minargs() + 1;
		}
		str += "(";				
		if(iargs != 0) {
			for(int i2 = 1; i2 <= iargs; i2++) {	
				if(i2 > ds->minargs()) {
					str += "[";
				}
				if(i2 > 1) {
					str += CALCULATOR->getComma();
					str += " ";
				}
				arg = ds->getArgumentDefinition(i2);
				if(arg && !arg->name().empty()) {
					str2 = arg->name();
				} else {
					str2 = _("argument");
					str2 += " ";
					str2 += i2s(i2);
				}
				str += str2;
				if(i2 > ds->minargs()) {
					str += "]";
				}
			}
			if(ds->maxargs() < 0) {
				str += CALCULATOR->getComma();
				str += " …";
			}
		}
		str += ")";
		for(size_t i2 = 1; i2 <= ds->countNames(); i2++) {
			if(&ds->getName(i2) != ename) {
				str += "\n";
				str += ds->getName(i2).name;
			}
		}
		str += "\n\n";
		gtk_text_buffer_get_end_iter(buffer, &iter);
		gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, str.c_str(), -1, "italic", NULL);
		if(!ds->copyright().empty()) {
			str = "\n";
			str = ds->copyright();
			str += "\n";
			gtk_text_buffer_get_end_iter(buffer, &iter);
			gtk_text_buffer_insert(buffer, &iter, str.c_str(), -1);
		}
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasets_builder, "datasets_button_editset")), TRUE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasets_builder, "datasets_button_delset")), ds->isLocal());
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasets_builder, "datasets_button_newobject")), TRUE);
	} else {
		gtk_text_buffer_set_text(gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtk_builder_get_object(datasets_builder, "datasets_textview_description"))), "", -1);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasets_builder, "datasets_button_editset")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasets_builder, "datasets_button_delset")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasets_builder, "datasets_button_newobject")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasets_builder, "datasets_button_editobject")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasets_builder, "datasets_button_delobject")), FALSE);
		selected_dataset = NULL;
	}
}

void update_dataobjects() {
	on_tDatasets_selection_changed(gtk_tree_view_get_selection(GTK_TREE_VIEW(tDatasets)), NULL);
}

void on_dataset_button_function_clicked(GtkButton *w, gpointer user_data) {
	DataProperty *dp = (DataProperty*) user_data;
	DataObject *o = selected_dataobject;
	DataSet *ds = NULL;
	if(o) ds = dp->parentSet();
	if(ds && o) {
		string str = ds->preferredDisplayName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) w).name;
		str += "(";
		str += o->getProperty(ds->getPrimaryKeyProperty());
		str += CALCULATOR->getComma();
		str += " ";
		str += dp->getName();
		str += ")";
		insert_text(str.c_str());
	}
}
void on_tDataObjects_selection_changed(GtkTreeSelection *treeselection, gpointer) {
	GtkTreeModel *model;
	GtkTreeIter iter;
	GtkWidget *ptable = GTK_WIDGET(gtk_builder_get_object(datasets_builder, "datasets_grid_properties"));
	GList *childlist = gtk_container_get_children(GTK_CONTAINER(ptable));
	for(guint i = 0; ; i++) {
		GtkWidget *w = (GtkWidget*) g_list_nth_data(childlist, i);
		if(!w) break;
		gtk_widget_destroy(w);
	}
	g_list_free(childlist);
	if(gtk_tree_selection_get_selected(treeselection, &model, &iter)) {
		DataObject *o = NULL;
		gtk_tree_model_get(model, &iter, 3, &o, -1);
		selected_dataobject = o;
		if(!o) return;
		DataSet *ds = o->parentSet();
		if(!ds) return;
		DataPropertyIter it;
		DataProperty *dp = ds->getFirstProperty(&it);
		string sval;
		int rows = 1;
		gtk_grid_remove_column(GTK_GRID(ptable), 0);
		gtk_grid_remove_column(GTK_GRID(ptable), 1);
		gtk_grid_remove_column(GTK_GRID(ptable), 2);
		GtkWidget *button, *label;
		string str;
		while(dp) {
			if(!dp->isHidden()) {
				sval = o->getPropertyDisplayString(dp);
				if(!sval.empty()) {
					label = gtk_label_new(NULL);
					str = "<span weight=\"bold\">"; str += dp->title(); str += ":"; str += "</span>";
					gtk_label_set_markup(GTK_LABEL(label), str.c_str()); gtk_widget_set_halign(label, GTK_ALIGN_START); gtk_label_set_selectable(GTK_LABEL(label), FALSE);
					gtk_widget_set_margin_end(label, 20);
					gtk_grid_attach(GTK_GRID(ptable), label, 0, rows - 1, 1 , 1);
					label = gtk_label_new(NULL);
					gtk_widget_set_hexpand(label, TRUE);
					gtk_label_set_markup(GTK_LABEL(label), sval.c_str()); gtk_widget_set_halign(label, GTK_ALIGN_START); gtk_label_set_selectable(GTK_LABEL(label), TRUE);
					gtk_grid_attach(GTK_GRID(ptable), label, 1, rows - 1, 1, 1);
					button = gtk_button_new();
					gtk_container_add(GTK_CONTAINER(button), gtk_image_new_from_icon_name("edit-paste", GTK_ICON_SIZE_BUTTON));
					gtk_widget_set_halign(button, GTK_ALIGN_END);
					//gtk_widget_set_valign(button, GTK_ALIGN_CENTER);
					gtk_grid_attach(GTK_GRID(ptable), button, 2, rows - 1, 1, 1);
					g_signal_connect((gpointer) button, "clicked", G_CALLBACK(on_dataset_button_function_clicked), (gpointer) dp);
					rows++;
				}
			}
			dp = ds->getNextProperty(&it);
		}
		gtk_widget_show_all(ptable);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasets_builder, "datasets_button_editobject")), TRUE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasets_builder, "datasets_button_delobject")), o->isUserModified());
	} else {
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasets_builder, "datasets_button_editobject")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasets_builder, "datasets_button_delobject")), FALSE);
		selected_dataobject = NULL;
	}
}

void on_tDataProperties_selection_changed(GtkTreeSelection *treeselection, gpointer) {
	GtkTreeModel *model;
	GtkTreeIter iter;
	selected_dataproperty = NULL;
	if(gtk_tree_selection_get_selected(treeselection, &model, &iter)) {
		gtk_tree_model_get(model, &iter, 3, &selected_dataproperty, -1);
	}
	if(selected_dataproperty) {
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasetedit_builder, "dataset_edit_button_edit_property")), selected_dataproperty->isUserModified());
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasetedit_builder, "dataset_edit_button_del_property")), selected_dataproperty->isUserModified());
	} else {
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasetedit_builder, "dataset_edit_button_edit_property")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasetedit_builder, "dataset_edit_button_del_property")), FALSE);
	}
}


void on_tPlotFunctions_selection_changed(GtkTreeSelection *treeselection, gpointer) {
	GtkTreeModel *model;
	GtkTreeIter iter;
	selected_argument = NULL;
	if(gtk_tree_selection_get_selected(treeselection, &model, &iter)) {
		gchar *gstr1, *gstr2, *gstr3;
		gint type, smoothing, style, axis, rows;
		gtk_tree_model_get(model, &iter, 0, &gstr1, 1, &gstr2, 2, &style, 3, &smoothing, 4, &type, 5, &axis, 6, &rows, 9, &gstr3, -1);
		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_expression")), gstr2);
		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_variable")), gstr3);
		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_title")), gstr1);
		gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(plot_builder, "plot_combobox_style")), style);
		gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(plot_builder, "plot_combobox_smoothing")), smoothing);
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_radiobutton_vector")), type == 1);
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_radiobutton_paired")), type == 2);
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_radiobutton_yaxis1")), axis != 2);
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_radiobutton_yaxis2")), axis == 2);
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_checkbutton_rows")), rows);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_button_remove")), TRUE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_button_modify")), TRUE);		
		g_free(gstr1);
		g_free(gstr2);
		g_free(gstr3);
	} else {
		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_expression")), "");
		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_variable")), "");
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_button_modify")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_button_remove")), FALSE);
	}
}

void on_tSubfunctions_selection_changed(GtkTreeSelection *treeselection, gpointer) {
	GtkTreeModel *model;
	GtkTreeIter iter;
	selected_subfunction = 0;
	if(gtk_tree_selection_get_selected(treeselection, &model, &iter)) {
		gboolean g_b = FALSE;
		guint index = 0;
		gchar *gstr;
		gtk_tree_model_get(model, &iter, 1, &gstr, 3, &index, 4, &g_b, -1);
		selected_subfunction = index;
		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(functionedit_builder, "function_edit_entry_subexpression")), gstr);
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(functionedit_builder, "function_edit_checkbutton_precalculate")), g_b);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_button_modify_subfunction")), TRUE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_button_remove_subfunction")), TRUE);
		g_free(gstr);
	} else {
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_button_modify_subfunction")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_button_remove_subfunction")), FALSE);
	}
}

void on_tFunctionArguments_selection_changed(GtkTreeSelection *treeselection, gpointer) {
	GtkTreeModel *model;
	GtkTreeIter iter;
	selected_argument = NULL;
	if(gtk_tree_selection_get_selected(treeselection, &model, &iter)) {
		Argument *arg;
		gtk_tree_model_get(model, &iter, 2, &arg, -1);
		selected_argument = arg;
		int menu_index = MENU_ARGUMENT_TYPE_FREE;
		if(selected_argument) {
			gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(functionedit_builder, "function_edit_entry_argument_name")), selected_argument->name().c_str());
			switch(selected_argument->type()) {
				case ARGUMENT_TYPE_TEXT: {
					menu_index = MENU_ARGUMENT_TYPE_TEXT;
					break;
				}
				case ARGUMENT_TYPE_SYMBOLIC: {
					menu_index = MENU_ARGUMENT_TYPE_SYMBOLIC;
					break;
				}
				case ARGUMENT_TYPE_DATE: {
					menu_index = MENU_ARGUMENT_TYPE_DATE;				
					break;
				}
				case ARGUMENT_TYPE_INTEGER: {
					menu_index = MENU_ARGUMENT_TYPE_INTEGER;
					break;
				}
				case ARGUMENT_TYPE_NUMBER: {
					menu_index = MENU_ARGUMENT_TYPE_NUMBER;
					break;
				}
				case ARGUMENT_TYPE_VECTOR: {
					menu_index = MENU_ARGUMENT_TYPE_VECTOR;
					break;
				}
				case ARGUMENT_TYPE_MATRIX: {
					menu_index = MENU_ARGUMENT_TYPE_MATRIX;
					break;
				}
				case ARGUMENT_TYPE_EXPRESSION_ITEM: {
					menu_index = MENU_ARGUMENT_TYPE_EXPRESSION_ITEM;
					break;
				}					
				case ARGUMENT_TYPE_FUNCTION: {
					menu_index = MENU_ARGUMENT_TYPE_FUNCTION;
					break;
				}
				case ARGUMENT_TYPE_UNIT: {
					menu_index = MENU_ARGUMENT_TYPE_UNIT;
					break;
				}
				case ARGUMENT_TYPE_VARIABLE: {
					menu_index = MENU_ARGUMENT_TYPE_VARIABLE;
					break;
				}
				case ARGUMENT_TYPE_FILE: {
					menu_index = MENU_ARGUMENT_TYPE_FILE;
					break;
				}					
				case ARGUMENT_TYPE_BOOLEAN: {
					menu_index = MENU_ARGUMENT_TYPE_BOOLEAN;
					break;
				}
				case ARGUMENT_TYPE_ANGLE: {
					menu_index = MENU_ARGUMENT_TYPE_ANGLE;
					break;
				}
				case ARGUMENT_TYPE_DATA_OBJECT: {
					menu_index = MENU_ARGUMENT_TYPE_DATA_OBJECT;
					break;
				}
				case ARGUMENT_TYPE_DATA_PROPERTY: {
					menu_index = MENU_ARGUMENT_TYPE_DATA_PROPERTY;
					break;
				}
			}			
		} else {
			gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(functionedit_builder, "function_edit_entry_argument_name")), "");
		}
		gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(functionedit_builder, "function_edit_combobox_argument_type")), menu_index);
		if(!(get_edited_function() && get_edited_function()->isBuiltin())) {
			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_button_rules")), TRUE);	
			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_button_remove_argument")), TRUE);
		}
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_button_modify_argument")), TRUE);		
	} else {
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_button_modify_argument")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_button_remove_argument")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_button_rules")), FALSE);	
	}
}
void update_function_arguments_list(MathFunction *f) {
	if(!functionedit_builder) return;
	selected_argument = NULL;
	gtk_list_store_clear(tFunctionArguments_store);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_button_modify_argument")), FALSE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_button_remove_argument")), FALSE);	
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_button_rules")), FALSE);
	if(f) {
		GtkTreeIter iter;
		Argument *arg;
		int args = f->maxargs();
		if(args < 0) {
			args = f->minargs() + 1;	
		}
		Argument defarg;
		string str, str2;
		for(int i = 1; i <= args; i++) {
			gtk_list_store_append(tFunctionArguments_store, &iter);
			arg = f->getArgumentDefinition(i);
			if(arg) {
				arg = arg->copy();
				str = arg->printlong();
				str2 = arg->name();
			} else {
				str = defarg.printlong();
				str2 = "";
			}			
			gtk_list_store_set(tFunctionArguments_store, &iter, 0, str2.c_str(), 1, str.c_str(), 2, (gpointer) arg, -1);
		}
	}
}

void on_tNames_selection_changed(GtkTreeSelection *treeselection, gpointer) {
	GtkTreeModel *model;
	GtkTreeIter iter;
	selected_subfunction = 0;
	if(gtk_tree_selection_get_selected(treeselection, &model, &iter)) {
		gboolean abbreviation = FALSE, suffix = FALSE, unicode = FALSE, plural = FALSE, reference = FALSE, avoid_input = FALSE, case_sensitive = FALSE, completion_only = FALSE;
		gchar *name;
		gtk_tree_model_get(model, &iter, NAMES_NAME_COLUMN, &name, NAMES_ABBREVIATION_COLUMN, &abbreviation, NAMES_SUFFIX_COLUMN, &suffix, NAMES_UNICODE_COLUMN, &unicode, NAMES_PLURAL_COLUMN, &plural, NAMES_REFERENCE_COLUMN, &reference, NAMES_AVOID_INPUT_COLUMN, &avoid_input, NAMES_CASE_SENSITIVE_COLUMN, &case_sensitive, NAMES_COMPLETION_ONLY_COLUMN, &completion_only, -1);
		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(namesedit_builder, "names_edit_entry_name")), name);
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_abbreviation")), abbreviation);
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_suffix")), suffix);
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_unicode")), unicode);
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_plural")), plural);
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_reference")), reference);
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_avoid_input")), avoid_input);
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_case_sensitive")), case_sensitive);
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_completion_only")), completion_only);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(namesedit_builder, "names_edit_button_modify")), TRUE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(namesedit_builder, "names_edit_button_remove")), TRUE);
		g_free(name);
	} else {
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(namesedit_builder, "names_edit_button_modify")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(namesedit_builder, "names_edit_button_remove")), FALSE);
	}
}



/*
	generate unit submenu in expression menu
*/
void create_umenu() {
	GtkWidget *item;
	GtkWidget *sub, *sub2, *sub3;
	item = GTK_WIDGET(gtk_builder_get_object(main_builder, "units_menu"));
	sub = gtk_menu_new(); gtk_widget_show (sub); gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), sub);
	
	u_menu = sub;
	sub2 = sub;
	Unit *u;
	tree_struct *titem, *titem2;
	unit_cats.rit = unit_cats.items.rbegin();
	if(unit_cats.rit != unit_cats.items.rend()) {
		titem = &*unit_cats.rit;
		++unit_cats.rit;
		titem->rit = titem->items.rbegin();
	} else {
		titem = NULL;
	}
	stack<GtkWidget*> menus;
	menus.push(sub);
	sub3 = sub;
	while(titem) {
		bool b_empty = titem->items.size() == 0;
		if(b_empty) {
			for(size_t i = 0; i < titem->objects.size(); i++) {
				u = (Unit*) titem->objects[i];
				if(u->isActive() && !u->isHidden()) {
					b_empty = false;
					break;
				}
			}
		}
		if(!b_empty) {
			SUBMENU_ITEM_PREPEND(titem->item.c_str(), sub3)
			menus.push(sub);
			sub3 = sub;
			bool is_currencies = false;
			for(size_t i = 0; i < titem->objects.size(); i++) {
				u = (Unit*) titem->objects[i];
				if(!is_currencies && u->isCurrency()) is_currencies = true;
				if(u->isActive() && !u->isHidden()) {
					if(is_currencies) {MENU_ITEM_WITH_POINTER_AND_FLAG(u->title(true).c_str(), insert_unit, u)}
					else {MENU_ITEM_WITH_POINTER(u->title(true).c_str(), insert_unit, u)}
				}
			}
			if(is_currencies) {
				SUBMENU_ITEM_PREPEND(_("more"), sub3)
				for(size_t i = 0; i < titem->objects.size(); i++) {
					u = (Unit*) titem->objects[i];
					if(u->isActive() && u->isHidden()) {
						MENU_ITEM_WITH_POINTER_AND_FLAG(u->title(true).c_str(), insert_unit, u)
					}
				}
			}
		} else {
			titem = titem->parent;
		}
		while(titem && titem->rit == titem->items.rend()) {
			titem = titem->parent;
			menus.pop();
			if(menus.size() > 0) sub3 = menus.top();
		}	
		if(titem) {
			titem2 = &*titem->rit;
			++titem->rit;
			titem = titem2;
			titem->rit = titem->items.rbegin();	
		}
	}
	sub = sub2;
	for(size_t i = 0; i < unit_cats.objects.size(); i++) {
		u = (Unit*) unit_cats.objects[i];
		if(u->isActive() && !u->isHidden()) {
			MENU_ITEM_WITH_POINTER(u->title(true).c_str(), insert_unit, u)
		}
	}		
	
	MENU_SEPARATOR	
	item = gtk_menu_item_new_with_label(_("Prefixes"));
	gtk_widget_show (item);
	gtk_menu_shell_append(GTK_MENU_SHELL(sub), item);
	create_pmenu(item);		
	
}

/*
	generate unit submenu in result menu
*/
void create_umenu2() {
	GtkWidget *item;
	GtkWidget *sub, *sub2, *sub3;
	item = GTK_WIDGET(gtk_builder_get_object(main_builder, "menu_item_result_units"));
	sub = gtk_menu_new(); gtk_widget_show (sub); gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), sub);	
	u_menu2 = sub;
	sub2 = sub;
	Unit *u;
	tree_struct *titem, *titem2;
	unit_cats.rit = unit_cats.items.rbegin();
	if(unit_cats.rit != unit_cats.items.rend()) {
		titem = &*unit_cats.rit;
		++unit_cats.rit;
		titem->rit = titem->items.rbegin();
	} else {
		titem = NULL;
	}
	stack<GtkWidget*> menus;
	menus.push(sub);
	sub3 = sub;
	while(titem) {
		bool b_empty = titem->items.size() == 0;
		if(b_empty) {
			for(size_t i = 0; i < titem->objects.size(); i++) {
				u = (Unit*) titem->objects[i];
				if(u->isActive() && !u->isHidden()) {
					b_empty = false;
					break;
				}
			}
		}
		if(!b_empty) {
			SUBMENU_ITEM_PREPEND(titem->item.c_str(), sub3)
			menus.push(sub);
			sub3 = sub;
			bool is_currencies = false;
			for(size_t i = 0; i < titem->objects.size(); i++) {
				u = (Unit*) titem->objects[i];
				if(!is_currencies && u->isCurrency()) is_currencies = true;
				if(u->isActive() && !u->isHidden()) {
					if(is_currencies) {MENU_ITEM_WITH_POINTER_AND_FLAG(u->title(true).c_str(), convert_to_unit, u)}
					else {MENU_ITEM_WITH_POINTER(u->title(true).c_str(), convert_to_unit, u)}
				}
			}
			if(is_currencies) {
				SUBMENU_ITEM_PREPEND(_("more"), sub3)
				for(size_t i = 0; i < titem->objects.size(); i++) {
					u = (Unit*) titem->objects[i];
					if(u->isActive() && u->isHidden()) {
						MENU_ITEM_WITH_POINTER_AND_FLAG(u->title(true).c_str(), convert_to_unit, u)
					}
				}
			}
		} else {
			titem = titem->parent;
		}
		while(titem && titem->rit == titem->items.rend()) {
			titem = titem->parent;
			menus.pop();
			if(menus.size() > 0) sub3 = menus.top();
		}	
		if(titem) {
			titem2 = &*titem->rit;
			++titem->rit;
			titem = titem2;
			titem->rit = titem->items.rbegin();	
		}
	}
	sub = sub2;
	for(size_t i = 0; i < unit_cats.objects.size(); i++) {
		u = (Unit*) unit_cats.objects[i];
		if(u->isActive() && !u->isHidden()) {
			MENU_ITEM_WITH_POINTER(u->title(true).c_str(), convert_to_unit, u)
		}
	}		
}

/*
	recreate unit menus and update unit manager (when units have changed)
*/
void update_umenus() {
	gtk_widget_destroy(u_menu);
	gtk_widget_destroy(u_menu2);
	generate_units_tree_struct();
	create_umenu();
	recreate_recent_units();
	create_umenu2();
	update_units_tree();
	update_unit_selector_tree();
	update_completion();
}

/*
	generate variables submenu in expression menu
*/
void create_vmenu() {

	GtkWidget *item;
	GtkWidget *sub, *sub2, *sub3;
	item = GTK_WIDGET(gtk_builder_get_object(main_builder, "variables_menu"));
	sub = gtk_menu_new(); gtk_widget_show (sub); gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), sub);
	
	v_menu = sub;
	sub2 = sub;
	Variable *v;
	tree_struct *titem, *titem2;
	variable_cats.rit = variable_cats.items.rbegin();
	if(variable_cats.rit != variable_cats.items.rend()) {
		titem = &*variable_cats.rit;
		++variable_cats.rit;
		titem->rit = titem->items.rbegin();
	} else {
		titem = NULL;
	}

	stack<GtkWidget*> menus;
	menus.push(sub);
	sub3 = sub;
	while(titem) {
		bool b_empty = titem->items.size() == 0;
		if(b_empty) {
			for(size_t i = 0; i < titem->objects.size(); i++) {
				v = (Variable*) titem->objects[i];
				if(v->isActive() && !v->isHidden()) {
					b_empty = false;
					break;
				}
			}
		}
		if(!b_empty) {
			SUBMENU_ITEM_PREPEND(titem->item.c_str(), sub3)
			menus.push(sub);
			sub3 = sub;			
			for(size_t i = 0; i < titem->objects.size(); i++) {
				v = (Variable*) titem->objects[i];
				if(v->isActive() && !v->isHidden()) {
					MENU_ITEM_WITH_POINTER(v->title(true).c_str(), insert_variable, v);
				}
			}
		} else {
			titem = titem->parent;
		}
		while(titem && titem->rit == titem->items.rend()) {
			titem = titem->parent;
			menus.pop();
			if(menus.size() > 0) sub3 = menus.top();
		}	
		if(titem) {
			titem2 = &*titem->rit;
			++titem->rit;
			titem = titem2;
			titem->rit = titem->items.rbegin();	
		}
	}
	sub = sub2;

	for(size_t i = 0; i < variable_cats.objects.size(); i++) {
		v = (Variable*) variable_cats.objects[i];
		if(v->isActive() && !v->isHidden()) {
			MENU_ITEM_WITH_POINTER(v->title(true).c_str(), insert_variable, v);
		}
	}		

}


/*
	generate prefixes submenu in expression menu
*/
void create_pmenu(GtkWidget *item) {
//	GtkWidget *item;
	GtkWidget *sub;
//	item = GTK_WIDGET(gtk_builder_get_object(main_builder, "menu_item_expression_prefixes"));
	sub = gtk_menu_new(); gtk_widget_show (sub); gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), sub);
	PangoFontDescription *font_desc;
	gtk_style_context_get(gtk_widget_get_style_context(item), GTK_STATE_FLAG_NORMAL, GTK_STYLE_PROPERTY_FONT, &font_desc, NULL);
	int index = 0;
	Prefix *p = CALCULATOR->getPrefix(index);
	while(p) {
		gchar *gstr = NULL;
		switch(p->type()) {
			case PREFIX_DECIMAL: {
				gstr = g_strdup_printf("%s (10<span size=\"x-small\" rise=\"%i\">%i</span>)", p->name(false, true, &can_display_unicode_string_function, (void*) item).c_str(), (int) (pango_font_description_get_size(font_desc) / 1.5), ((DecimalPrefix*) p)->exponent());
				break;
			}
			case PREFIX_BINARY: {
				gstr = g_strdup_printf("%s (2<span size=\"x-small\" rise=\"%i\">%i</span>)", p->name(false, true, &can_display_unicode_string_function, (void*) item).c_str(), (int) (pango_font_description_get_size(font_desc) / 1.5), ((BinaryPrefix*) p)->exponent());
				break;
			}
			case PREFIX_NUMBER: {				
				gstr = g_strdup_printf("%s", p->name(false, true, &can_display_unicode_string_function, (void*) item).c_str());
				break;
			}			
		}
		MENU_ITEM_WITH_POINTER(gstr, insert_prefix, p)
		gtk_label_set_use_markup(GTK_LABEL(gtk_bin_get_child(GTK_BIN(item))), TRUE);
		g_free(gstr);			
		index++;
		p = CALCULATOR->getPrefix(index);
	}
	pango_font_description_free(font_desc);
}

/*
	generate prefixes submenu in result menu
*/
void create_pmenu2() {
	GtkWidget *item;
	GtkWidget *sub;
	item = GTK_WIDGET(gtk_builder_get_object(main_builder, "menu_item_result_prefixes"));
	sub = gtk_menu_new(); gtk_widget_show (sub); gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), sub);	
	int index = 0;
	MENU_ITEM_WITH_POINTER(_("No Prefix"), on_menu_item_set_prefix_activate, CALCULATOR->decimal_null_prefix)
	MENU_ITEM_WITH_POINTER(_("Optimal Prefix"), on_menu_item_set_prefix_activate, NULL)
	Prefix *p = CALCULATOR->getPrefix(index);
	while(p) {
		gchar *gstr = NULL;
		switch(p->type()) {
			case PREFIX_DECIMAL: {
				gstr = g_strdup_printf("%s (10<sup>%i</sup>)", p->name(false, true, &can_display_unicode_string_function, (void*) item).c_str(), ((DecimalPrefix*) p)->exponent());
				break;
			}
			case PREFIX_BINARY: {
				gstr = g_strdup_printf("%s (2<sup>%i</sup>)", p->name(false, true, &can_display_unicode_string_function, (void*) item).c_str(), ((BinaryPrefix*) p)->exponent());
				break;
			}
			case PREFIX_NUMBER: {				
				gstr = g_strdup_printf("%s", p->name(false, true, &can_display_unicode_string_function, (void*) item).c_str());
				break;
			}			
		}
		MENU_ITEM_WITH_POINTER(gstr, on_menu_item_set_prefix_activate, p)
		gtk_label_set_use_markup(GTK_LABEL(gtk_bin_get_child(GTK_BIN(item))), TRUE);
		g_free(gstr);			
		index++;
		p = CALCULATOR->getPrefix(index);
	}	
}

/*
	recreate variables menu and update variable manager (when variables have changed)
*/
void update_vmenu() {
	gtk_widget_destroy(v_menu);
	generate_variables_tree_struct();
	create_vmenu();
	recreate_recent_variables();
	update_variables_tree();
	update_completion();
	update_mb_sto_menu();
}

/*
	generate functions submenu in expression menu
*/
void create_fmenu() {
	GtkWidget *item;
	GtkWidget *sub, *sub2, *sub3;
	item = GTK_WIDGET(gtk_builder_get_object(main_builder, "functions_menu"));
	sub = gtk_menu_new(); gtk_widget_show (sub); gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), sub);
	f_menu = sub;
	sub2 = sub;
	MathFunction *f;
	tree_struct *titem, *titem2;
	function_cats.rit = function_cats.items.rbegin();
	if(function_cats.rit != function_cats.items.rend()) {
		titem = &*function_cats.rit;
		++function_cats.rit;
		titem->rit = titem->items.rbegin();
	} else {
		titem = NULL;
	}
	stack<GtkWidget*> menus;
	menus.push(sub);
	sub3 = sub;
	while(titem) {
		bool b_empty = titem->items.size() == 0;
		if(b_empty) {
			for(size_t i = 0; i < titem->objects.size(); i++) {
				f = (MathFunction*) titem->objects[i];
				if(f->isActive() && !f->isHidden()) {
					b_empty = false;
					break;
				}
			}
		}
		if(!b_empty) {
			SUBMENU_ITEM_PREPEND(titem->item.c_str(), sub3)
			for(size_t i = 0; i < titem->objects.size(); i++) {
				f = (MathFunction*) titem->objects[i];
				if(f->isActive() && !f->isHidden()) {
					MENU_ITEM_WITH_POINTER(f->title(true).c_str(), insert_function, f)
				}
			}
			menus.push(sub);
			sub3 = sub;
		} else {
			titem = titem->parent;
		}		
		while(titem && titem->rit == titem->items.rend()) {
			titem = titem->parent;
			menus.pop();
			if(menus.size() > 0) sub3 = menus.top();
		}	
		if(titem) {
			titem2 = &*titem->rit;
			++titem->rit;
			titem = titem2;
			titem->rit = titem->items.rbegin();	
		}
	}
	sub = sub2;
	for(size_t i = 0; i < function_cats.objects.size(); i++) {
		f = (MathFunction*) function_cats.objects[i];
		if(f->isActive() && !f->isHidden()) {
			MENU_ITEM_WITH_POINTER(f->title(true).c_str(), insert_function, f)
		}
	}		
}

string sub_suffix(const ExpressionName *ename) {
	size_t i = ename->name.rfind('_');
	bool b = i == string::npos || i == ename->name.length() - 1 || i == 0;
	size_t i2 = 1;
	string str;
	if(b) {
		if(is_in(NUMBERS, ename->name[ename->name.length() - 1])) {
			while(ename->name.length() > i2 + 1 && is_in(NUMBERS, ename->name[ename->name.length() - 1 - i2])) {
					i2++;
			}
		}
		str += ename->name.substr(0, ename->name.length() - i2);
	} else {
		str += ename->name.substr(0, i);
	}
	str += "<span size=\"small\"><sub>";
	if(b) str += ename->name.substr(ename->name.length() - i2, i2);
	else str += ename->name.substr(i + 1, ename->name.length() - (i + 1));
	str += "</sub></span>";
	return str;
}

GtkTreeIter completion_separator_iter;

void update_completion() {

	GtkTreeIter iter;
	
	gtk_list_store_clear(completion_store);
	
	gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(completion_store), 1, GTK_SORT_ASCENDING);
	
	string str;
	for(size_t i = 0; i < CALCULATOR->functions.size(); i++) {
		if(CALCULATOR->functions[i]->isActive()) {
			gtk_list_store_append(completion_store, &iter);
			const ExpressionName *ename, *ename_r;
			ename_r = &CALCULATOR->functions[i]->preferredInputName(false, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext);
			if(ename_r->suffix && ename_r->name.length() > 1) {
				str = sub_suffix(ename_r);
			} else {
				str = ename_r->name;
			}
			str += "()";
			for(size_t name_i = 1; name_i <= CALCULATOR->functions[i]->countNames(); name_i++) {
				ename = &CALCULATOR->functions[i]->getName(name_i);
				if(ename && ename != ename_r && !ename->completion_only && !ename->plural && (!ename->unicode || can_display_unicode_string_function(ename->name.c_str(), (void*) expressiontext))) {
					str += " <i>";
					if(ename->suffix && ename->name.length() > 1) {
						str += sub_suffix(ename);
					} else {
						str += ename->name;
					}
					str += "()</i>";
				}
			}			
			gtk_list_store_set(completion_store, &iter, 0, str.c_str(), 1, CALCULATOR->functions[i]->title().c_str(), 2, CALCULATOR->functions[i], 3, FALSE, 4, 0, 6, PANGO_WEIGHT_NORMAL, 7, 0, 8, NULL, -1);
		}
	}
	for(size_t i = 0; i < CALCULATOR->variables.size(); i++) {
		if(CALCULATOR->variables[i]->isActive()) {
			gtk_list_store_append(completion_store, &iter);
			const ExpressionName *ename, *ename_r;
			bool b = false;
			ename_r = &CALCULATOR->variables[i]->preferredInputName(false, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext);
			for(size_t name_i = 1; name_i <= CALCULATOR->variables[i]->countNames(); name_i++) {
				ename = &CALCULATOR->variables[i]->getName(name_i);
				if(ename && ename != ename_r && !ename->completion_only && !ename->plural && (!ename->unicode || can_display_unicode_string_function(ename->name.c_str(), (void*) expressiontext))) {
					if(!b) {
						if(ename_r->suffix && ename_r->name.length() > 1) {
							str = sub_suffix(ename_r);
						} else {
							str = ename_r->name;
						}
						b = true;
					}
					str += " <i>";
					if(ename->suffix && ename->name.length() > 1) {
						str += sub_suffix(ename);
					} else {
						str += ename->name;
					}
					str += "</i>";
				}
			}
			if(!b && ename_r->suffix && ename_r->name.length() > 1) {
				str = sub_suffix(ename_r);
				b = true;
			}
			if(printops.use_unicode_signs && can_display_unicode_string_function("→", (void*) expressiontext)) {
				size_t pos = 0;
				if(b) {
					pos = str.find("_to_");
				} else {
					pos = ename_r->name.find("_to_");
					if(pos != string::npos) {
						str = ename_r->name;
						b = true;
					}
				}
				if(b) {
					while(pos != string::npos) {
						if((pos == 1 && str[0] == 'm') || (pos > 1 && str[pos - 1] == 'm' && str[pos - 2] == '>')) {
							str.replace(pos, 4, "<span size=\"small\"><sup>-1</sup></span>→");
						} else {
							str.replace(pos, 4, "→");
						}
						pos = str.find("_to_", pos);
					}
				}
			}
			if(!CALCULATOR->variables[i]->title(false).empty()) {
				if(b) gtk_list_store_set(completion_store, &iter, 0, str.c_str(), 1, CALCULATOR->variables[i]->title().c_str(), 2, CALCULATOR->variables[i], 3, FALSE, 4, 0, 6, PANGO_WEIGHT_NORMAL, 7, 0, 8, NULL, -1);
				else gtk_list_store_set(completion_store, &iter, 0, ename_r->name.c_str(), 1, CALCULATOR->variables[i]->title().c_str(), 2, CALCULATOR->variables[i], 3, FALSE, 4, 0, 6, PANGO_WEIGHT_NORMAL, 7, 0, 8, NULL, -1);
			} else {
				Variable *v = CALCULATOR->variables[i];
				string title;
				if(is_answer_variable(v)) {
					title = _("a previous result");
				} else if(v->isKnown()) {
					if(((KnownVariable*) v)->isExpression()) {
						title = CALCULATOR->localizeExpression(((KnownVariable*) v)->expression());
						if(!((KnownVariable*) v)->unit().empty()) {title += " "; title += ((KnownVariable*) v)->unit();}
					} else {
						if(((KnownVariable*) v)->get().isMatrix()) {
							title = _("matrix");
						} else if(((KnownVariable*) v)->get().isVector()) {
							title = _("vector");
						} else {
							PrintOptions po;
							po.interval_display = INTERVAL_DISPLAY_SIGNIFICANT_DIGITS;
							title = CALCULATOR->print(((KnownVariable*) v)->get(), 30, po);
						}
					}
				} else {
					if(((UnknownVariable*) v)->assumptions()) {
						switch(((UnknownVariable*) v)->assumptions()->sign()) {
							case ASSUMPTION_SIGN_POSITIVE: {title = _("positive"); break;}
							case ASSUMPTION_SIGN_NONPOSITIVE: {title = _("non-positive"); break;}
							case ASSUMPTION_SIGN_NEGATIVE: {title = _("negative"); break;}
							case ASSUMPTION_SIGN_NONNEGATIVE: {title = _("non-negative"); break;}
							case ASSUMPTION_SIGN_NONZERO: {title = _("non-zero"); break;}
							default: {}
						}
						if(!title.empty() && ((UnknownVariable*) v)->assumptions()->type() != ASSUMPTION_TYPE_NONE) title += " ";
						switch(((UnknownVariable*) v)->assumptions()->type()) {
							case ASSUMPTION_TYPE_INTEGER: {title += _("integer"); break;}
							case ASSUMPTION_TYPE_RATIONAL: {title += _("rational"); break;}
							case ASSUMPTION_TYPE_REAL: {title += _("real"); break;}
							case ASSUMPTION_TYPE_COMPLEX: {title += _("complex"); break;}
							case ASSUMPTION_TYPE_NUMBER: {title += _("number"); break;}
							case ASSUMPTION_TYPE_NONMATRIX: {title += _("(not matrix)"); break;}
							default: {}
						}
						if(title.empty()) title = _("unknown");
					} else {
						title = _("default assumptions");
					}		
				}
				if(b) gtk_list_store_set(completion_store, &iter, 0, str.c_str(), 1, title.c_str(), 2, CALCULATOR->variables[i], 3, FALSE, 4, 0, 6, PANGO_WEIGHT_NORMAL, 7, 0, 8, NULL, -1);
				else gtk_list_store_set(completion_store, &iter, 0, ename_r->name.c_str(), 1, title.c_str(), 2, CALCULATOR->variables[i], 3, FALSE, 4, 0, 6, PANGO_WEIGHT_NORMAL, 7, 0, 8, NULL, -1);
			}
		}
	}
	for(size_t i = 0; i < CALCULATOR->units.size(); i++) {
		Unit *u = CALCULATOR->units[i];
		if(u->isActive() && u->subtype() != SUBTYPE_COMPOSITE_UNIT) {
			gtk_list_store_append(completion_store, &iter);
			const ExpressionName *ename, *ename_r;
			bool b = false;
			ename_r = &u->preferredInputName(false, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext);
			for(size_t name_i = 1; name_i <= u->countNames(); name_i++) {
				ename = &u->getName(name_i);
				if(ename && ename != ename_r && !ename->completion_only && !ename->plural && (!ename->unicode || can_display_unicode_string_function(ename->name.c_str(), (void*) expressiontext))) {
					if(!b) {
						if(ename_r->suffix && ename_r->name.length() > 1) {
							str = sub_suffix(ename_r);
						} else {
							str = ename_r->name;
						}
						b = true;
					}
					str += " <i>";
					if(ename->suffix && ename->name.length() > 1) {
						str += sub_suffix(ename);
					} else {
						str += ename->name;
					}
					str += "</i>";
				}
			}
			if(!b && ename_r->suffix && ename_r->name.length() > 1) {
				str = sub_suffix(ename_r);
				b = true;
			}
			unordered_map<string, GdkPixbuf*>::const_iterator it_flag = flag_images.end();
			if(u->isCurrency()) it_flag = flag_images.find(u->referenceName()); 	
			if(b) gtk_list_store_set(completion_store, &iter, 0, str.c_str(), 1, u->title().c_str(), 2, u, 3, FALSE, 4, 0, 5, it_flag == flag_images.end() ? NULL : it_flag->second, 6, PANGO_WEIGHT_NORMAL, 7, 0, 8, NULL, -1);
			else gtk_list_store_set(completion_store, &iter, 0, ename_r->name.c_str(), 1, u->title().c_str(), 2, u, 3, FALSE, 4, 0, 5, it_flag == flag_images.end() ? NULL : it_flag->second, 6, PANGO_WEIGHT_NORMAL, 7, 0, 8, NULL, -1);
		}
	}
	PangoFontDescription *font_desc;
	gtk_style_context_get(gtk_widget_get_style_context(completion_view), GTK_STATE_FLAG_NORMAL, GTK_STYLE_PROPERTY_FONT, &font_desc, NULL);
	for(size_t i = 1; ; i++) {
		Prefix *p = CALCULATOR->getPrefix(i);
		if(!p) break;
		gtk_list_store_append(completion_store, &iter);
		str = "";
		for(size_t name_i = 1; name_i <= 3; name_i++) {
			const string *pstr;
			if(name_i == 1) pstr = &p->longName(false);
			else if(name_i == 2) pstr = &p->unicodeName(false);
			else pstr = &p->shortName(false);
			if(!pstr->empty()) {
				if(!str.empty()) {
					str += " <i>";
					str += *pstr;
					str += "</i>";
				} else {
					str += *pstr;
				}
			}
		}
		gchar *gstr = NULL;
		switch(p->type()) {
			case PREFIX_DECIMAL: {
				gstr = g_strdup_printf("%s: 10<span size=\"x-small\" rise=\"%i\">%i</span>", _("Prefix"), (int) (pango_font_description_get_size(font_desc) / 1.5), ((DecimalPrefix*) p)->exponent());
				break;
			}
			case PREFIX_BINARY: {
				gstr = g_strdup_printf("%s: 2<span size=\"x-small\" rise=\"%i\">%i</span>", _("Prefix"), (int) (pango_font_description_get_size(font_desc) / 1.5), ((BinaryPrefix*) p)->exponent());
				break;
			}
			case PREFIX_NUMBER: {				
				gstr = g_strdup_printf("%s: %s", _("Prefix"), ((NumberPrefix*) p)->value().print().c_str());
				break;
			}			
		}
		gtk_list_store_set(completion_store, &iter, 0, str.c_str(), 1, gstr, 2, NULL, 3, FALSE, 4, 0, 5, NULL, 6, PANGO_WEIGHT_NORMAL, 7, 0, 8, p, -1);
		g_free(gstr);
	}
	pango_font_description_free(font_desc);
	string str2;
#define COMPLETION_CONVERT_STRING(x) str = _(x); if(str != x) {str += " <i>"; str += x; str += "</i>";}
#define COMPLETION_CONVERT_STRING2(x, y) str = _(x); if(str != x) {str += " <i>"; str += x; str += "</i>";} str2 = _(y);  str += " <i>"; str += str2; str += "</i>"; if(str2 != y) {str += " <i>"; str += y; str += "</i>";}
	COMPLETION_CONVERT_STRING2("angle", "phasor") 
	gtk_list_store_append(completion_store, &iter); gtk_list_store_set(completion_store, &iter, 0, str.c_str(), 1, _("Complex angle/phasor notation"), 2, NULL, 3, FALSE, 4, 0, 6, PANGO_WEIGHT_NORMAL, 7, 0, 8, NULL, -1);
	COMPLETION_CONVERT_STRING("bases")
	gtk_list_store_append(completion_store, &iter); gtk_list_store_set(completion_store, &iter, 0, str.c_str(), 1, _("Number bases"), 2, NULL, 3, FALSE, 4, 0, 6, PANGO_WEIGHT_NORMAL, 7, 0, 8, NULL, -1);
	COMPLETION_CONVERT_STRING("base")
	gtk_list_store_append(completion_store, &iter); gtk_list_store_set(completion_store, &iter, 0, str.c_str(), 1, _("Base units"), 2, NULL, 3, FALSE, 4, 0, 6, PANGO_WEIGHT_NORMAL, 7, 0, 8, NULL, -1);
	COMPLETION_CONVERT_STRING("base ")
	gtk_list_store_append(completion_store, &iter); gtk_list_store_set(completion_store, &iter, 0, str.c_str(), 1, _("Number base"), 2, NULL, 3, FALSE, 4, 0, 6, PANGO_WEIGHT_NORMAL, 7, 0, 8, NULL, -1);
	COMPLETION_CONVERT_STRING("bijective")
	gtk_list_store_append(completion_store, &iter); gtk_list_store_set(completion_store, &iter, 0, str.c_str(), 1, _("Bijective base-26"), 2, NULL, 3, FALSE, 4, 0, 6, PANGO_WEIGHT_NORMAL, 7, 0, 8, NULL, -1);
	COMPLETION_CONVERT_STRING("binary") str += " <i>"; str += "bin"; str += "</i>";
	gtk_list_store_append(completion_store, &iter); gtk_list_store_set(completion_store, &iter, 0, str.c_str(), 1, _("Binary number"), 2, NULL, 3, FALSE, 4, 0, 6, PANGO_WEIGHT_NORMAL, 7, 0, 8, NULL, -1);
	COMPLETION_CONVERT_STRING("calendars")
	gtk_list_store_append(completion_store, &iter); gtk_list_store_set(completion_store, &iter, 0, str.c_str(), 1, _("Calendars"), 2, NULL, 3, FALSE, 4, 0, 6, PANGO_WEIGHT_NORMAL, 7, 0, 8, NULL, -1);
	COMPLETION_CONVERT_STRING("cis")
	gtk_list_store_append(completion_store, &iter); gtk_list_store_set(completion_store, &iter, 0, str.c_str(), 1, _("Complex cis form"), 2, NULL, 3, FALSE, 4, 0, 6, PANGO_WEIGHT_NORMAL, 7, 0, 8, NULL, -1);
	COMPLETION_CONVERT_STRING("duodecimal") str += " <i>"; str += "duo"; str += "</i>";
	gtk_list_store_append(completion_store, &iter); gtk_list_store_set(completion_store, &iter, 0, str.c_str(), 1, _("Duodecimal number"), 2, NULL, 3, FALSE, 4, 0, 6, PANGO_WEIGHT_NORMAL, 7, 0, 8, NULL, -1);
	COMPLETION_CONVERT_STRING("exponential")
	gtk_list_store_append(completion_store, &iter); gtk_list_store_set(completion_store, &iter, 0, str.c_str(), 1, _("Complex exponential form"), 2, NULL, 3, FALSE, 4, 0, 6, PANGO_WEIGHT_NORMAL, 7, 0, 8, NULL, -1);
	COMPLETION_CONVERT_STRING("factors")
	gtk_list_store_append(completion_store, &iter); gtk_list_store_set(completion_store, &iter, 0, str.c_str(), 1, _("Factors"), 2, NULL, 3, FALSE, 4, 0, 6, PANGO_WEIGHT_NORMAL, 7, 0, 8, NULL, -1);
	COMPLETION_CONVERT_STRING("fraction")
	gtk_list_store_append(completion_store, &iter); gtk_list_store_set(completion_store, &iter, 0, str.c_str(), 1, _("Fraction"), 2, NULL, 3, FALSE, 4, 0, 6, PANGO_WEIGHT_NORMAL, 7, 0, 8, NULL, -1);
	COMPLETION_CONVERT_STRING("hexadecimal") str += " <i>"; str += "hex"; str += "</i>";
	gtk_list_store_append(completion_store, &iter); gtk_list_store_set(completion_store, &iter, 0, str.c_str(), 1, _("Hexadecimal number"), 2, NULL, 3, FALSE, 4, 0, 6, PANGO_WEIGHT_NORMAL, 7, 0, 8, NULL, -1);
	COMPLETION_CONVERT_STRING("decimal") str += " <i>"; str += "dec"; str += "</i>";
	gtk_list_store_append(completion_store, &iter); gtk_list_store_set(completion_store, &iter, 0, str.c_str(), 1, _("Decimal number"), 2, NULL, 3, FALSE, 4, 0, 6, PANGO_WEIGHT_NORMAL, 7, 0, 8, NULL, -1);
	COMPLETION_CONVERT_STRING("mixed")
	gtk_list_store_append(completion_store, &iter); gtk_list_store_set(completion_store, &iter, 0, str.c_str(), 1, _("Mixed units"), 2, NULL, 3, FALSE, 4, 0, 6, PANGO_WEIGHT_NORMAL, 7, 0, 8, NULL, -1);
	COMPLETION_CONVERT_STRING("octal") str += " <i>"; str += "oct"; str += "</i>";
	gtk_list_store_append(completion_store, &iter); gtk_list_store_set(completion_store, &iter, 0, str.c_str(), 1, _("Octal number"), 2, NULL, 3, FALSE, 4, 0, 6, PANGO_WEIGHT_NORMAL, 7, 0, 8, NULL, -1);
	COMPLETION_CONVERT_STRING("optimal")
	gtk_list_store_append(completion_store, &iter); gtk_list_store_set(completion_store, &iter, 0, str.c_str(), 1, _("Optimal units"), 2, NULL, 3, FALSE, 4, 0, 6, PANGO_WEIGHT_NORMAL, 7, 0, 8, NULL, -1);
	COMPLETION_CONVERT_STRING("partial fraction")
	gtk_list_store_append(completion_store, &iter); gtk_list_store_set(completion_store, &iter, 0, str.c_str(), 1, _("Expanded partial fractions"), 2, NULL, 3, FALSE, 4, 0, 6, PANGO_WEIGHT_NORMAL, 7, 0, 8, NULL, -1);
	COMPLETION_CONVERT_STRING("polar")
	gtk_list_store_append(completion_store, &iter); gtk_list_store_set(completion_store, &iter, 0, str.c_str(), 1, _("Complex polar form"), 2, NULL, 3, FALSE, 4, 0, 6, PANGO_WEIGHT_NORMAL, 7, 0, 8, NULL, -1);
	COMPLETION_CONVERT_STRING2("rectangular", "cartesian") 
	gtk_list_store_append(completion_store, &iter); gtk_list_store_set(completion_store, &iter, 0, str.c_str(), 1, _("Complex rectangular form"), 2, NULL, 3, FALSE, 4, 0, 6, PANGO_WEIGHT_NORMAL, 7, 0, 8, NULL, -1);
	COMPLETION_CONVERT_STRING("roman")
	gtk_list_store_append(completion_store, &iter); gtk_list_store_set(completion_store, &iter, 0, str.c_str(), 1, _("Roman numerals"), 2, NULL, 3, FALSE, 4, 0, 6, PANGO_WEIGHT_NORMAL, 7, 0, 8, NULL, -1);
	COMPLETION_CONVERT_STRING("sexagesimal") str += " <i>"; str += "sexa"; str += "</i>";
	gtk_list_store_append(completion_store, &iter); gtk_list_store_set(completion_store, &iter, 0, str.c_str(), 1, _("Sexagesimal number"), 2, NULL, 3, FALSE, 4, 0, 6, PANGO_WEIGHT_NORMAL, 7, 0, 8, NULL, -1);
	COMPLETION_CONVERT_STRING("time")
	gtk_list_store_append(completion_store, &iter); gtk_list_store_set(completion_store, &iter, 0, str.c_str(), 1, _("Time format"), 2, NULL, 3, FALSE, 4, 0, 6, PANGO_WEIGHT_NORMAL, 7, 0, 8, NULL, -1);
	COMPLETION_CONVERT_STRING("unicode")
	gtk_list_store_append(completion_store, &iter); gtk_list_store_set(completion_store, &iter, 0, str.c_str(), 1, _("Unicode"), 2, NULL, 3, FALSE, 4, 0, 6, PANGO_WEIGHT_NORMAL, 7, 0, 8, NULL, -1);
	COMPLETION_CONVERT_STRING("utc")
	gtk_list_store_append(completion_store, &iter); gtk_list_store_set(completion_store, &iter, 0, str.c_str(), 1, _("UTC time zone"), 2, NULL, 3, FALSE, 4, 0, 6, PANGO_WEIGHT_NORMAL, 7, 0, 8, NULL, -1);
	gtk_list_store_append(completion_store, &completion_separator_iter); gtk_list_store_set(completion_store, &completion_separator_iter, 0, "", 1, "", 2, NULL, 3, FALSE, 4, 3, 6, PANGO_WEIGHT_NORMAL, 7, 0, 8, NULL, -1);
	gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(completion_store), GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, GTK_SORT_ASCENDING);
}

/*
	recreate functions menu and update function manager (when functions have changed)
*/
void update_fmenu() {
	gtk_widget_destroy(f_menu);
	generate_functions_tree_struct();
	create_fmenu();
	recreate_recent_functions();
	update_completion();
	update_functions_tree();
}


string get_value_string(const MathStructure &mstruct_, bool rlabel = false, Prefix *prefix = NULL) {
	printops.allow_non_usable = rlabel;
	printops.prefix = prefix;
	string str = CALCULATOR->print(mstruct_, 100, printops);
	printops.allow_non_usable = false;
	printops.prefix = NULL;
	return str;
}


void draw_background(cairo_t *cr, gint w, gint h) {
/*	GdkRGBA rgba;
	gtk_style_context_get_background_color(gtk_widget_get_style_context(resultview), gtk_widget_get_state_flags(resultview);, &rgba);
	gdk_cairo_set_source_rgba(cr, &rgba);
	cairo_rectangle(cr, 0, 0, w, h);
	cairo_fill(cr);*/
}

cairo_surface_t *get_left_parenthesis(gint arc_w, gint arc_h, int, GdkRGBA *color) {
	gint scalefactor = gtk_widget_get_scale_factor(expressiontext);
	gint par_h = 0, par_w = 0;
	PangoLayout *layout = gtk_widget_create_pango_layout(resultview, NULL);
	pango_layout_set_markup(layout, "<span font=\"100\">(</span>", -1);
	pango_layout_get_pixel_size(layout, &par_w, &par_h);
	cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, arc_w * scalefactor, arc_h * scalefactor);
	cairo_surface_set_device_scale(s, scalefactor, scalefactor);
	cairo_t *cr = cairo_create(s);
	cairo_scale(cr, (double) arc_w / (double) par_w, (double) arc_h / (double) par_h);
	gdk_cairo_set_source_rgba(cr, color);
	pango_cairo_show_layout(cr, layout);
	cairo_destroy(cr);
	return s;
}
cairo_surface_t *get_right_parenthesis(gint arc_w, gint arc_h, int, GdkRGBA *color) {
	gint scalefactor = gtk_widget_get_scale_factor(expressiontext);
	gint par_h = 0, par_w = 0;
	PangoLayout *layout = gtk_widget_create_pango_layout(resultview, NULL);
	pango_layout_set_markup(layout, "<span font=\"100\">)</span>", -1);
	pango_layout_get_pixel_size(layout, &par_w, &par_h);
	cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, arc_w * scalefactor, arc_h * scalefactor);
	cairo_surface_set_device_scale(s, scalefactor, scalefactor);
	cairo_t *cr = cairo_create(s);
	cairo_scale(cr, (double) arc_w / (double) par_w, (double) arc_h / (double) par_h);
	gdk_cairo_set_source_rgba(cr, color);
	pango_cairo_show_layout(cr, layout);
	cairo_destroy(cr);
	return s;
}

#define SHOW_WITH_ROOT_SIGN(x) (x.isFunction() && ((x.function() == CALCULATOR->f_sqrt && x.size() == 1) || (x.function() == CALCULATOR->f_cbrt && x.size() == 1) || (x.function() == CALCULATOR->f_root && x.size() == 2 && x[1].isNumber() && x[1].number().isInteger() && x[1].number().isPositive() && x[1].number().isLessThan(10))))

cairo_surface_t *draw_structure(MathStructure &m, PrintOptions po, bool caf, InternalPrintStruct ips, gint *point_central, int scaledown, GdkRGBA *color) {

	if(CALCULATOR->aborted()) return NULL;
	
	gint scalefactor = gtk_widget_get_scale_factor(expressiontext);

	if(ips.depth == 0 && po.is_approximate) *po.is_approximate = false;

	cairo_surface_t *surface = NULL;
	cairo_t *cr = NULL;
	GdkRGBA rgba;
	if(!color) {
		gtk_style_context_get_color(gtk_widget_get_style_context(resultview), gtk_widget_get_state_flags(resultview), &rgba);
		color = &rgba;
	}
	gint w, h;
	gint central_point = 0;

	InternalPrintStruct ips_n = ips;
	if(m.isApproximate()) ips_n.parent_approximate = true;
	if(m.precision() > 0 && (ips_n.parent_precision < 1 || m.precision() < ips_n.parent_precision)) ips_n.parent_precision = m.precision();
	
	// angle/phasor notation: x+y*i=a*cis(b)=a∠b
	if(caf && m.isMultiplication() && m.size() == 2 && (m[0].isNumber() || (m[0].isNegate() && m[0][0].isNumber())) && m[1].isFunction() && m[1].size() == 1 && m[1].function()->referenceName() == "cis" && (((m[1][0].isNumber() || (m[1][0].isNegate() && m[1][0][0].isNumber())) || (m[1][0].isMultiplication() && m[1][0].size() == 2 && (m[1][0][0].isNumber() || (m[1][0].isNegate() && m[1][0][0][0].isNumber())) && m[1][0][1].isUnit())) || (m[1][0].isNegate() && m[1][0][0].isMultiplication() && m[1][0][0].size() == 2 && m[1][0][0][0].isNumber() && m[1][0][0][1].isUnit()))) {

		ips_n.depth++;
		
		vector<cairo_surface_t*> surface_terms;
		
		vector<gint> hpt;
		vector<gint> wpt;
		vector<gint> cpt;
		gint sign_w, sign_h, wtmp, htmp, hetmp = 0, w = 0, h = 0, dh = 0, uh = 0, space_w = 0;
		
		PangoLayout *layout_sign = NULL;

		if(can_display_unicode_string_function_exact("∠", (void*) resultview)) {
			layout_sign = gtk_widget_create_pango_layout(resultview, NULL);
			PANGO_TTP(layout_sign, "∠");
			pango_layout_get_pixel_size(layout_sign, &sign_w, &sign_h);
			w = sign_w;
			uh = sign_h / 2 + sign_h % 2;
			dh = sign_h / 2;
		}
		for(size_t i = 0; i < 2; i++) {
			hetmp = 0;
			ips_n.wrap = false;
			surface_terms.push_back(draw_structure(i == 0 ? m[0] : m[1][0], po, caf, ips_n, &hetmp, scaledown, color));
			if(CALCULATOR->aborted()) {
				for(size_t i = 0; i < surface_terms.size(); i++) {
					if(surface_terms[i]) cairo_surface_destroy(surface_terms[i]);
				}
				return NULL;
			}
			wtmp = cairo_image_surface_get_width(surface_terms[i]) / scalefactor;
			htmp = cairo_image_surface_get_height(surface_terms[i]) / scalefactor;
			hpt.push_back(htmp);
			cpt.push_back(hetmp);
			wpt.push_back(wtmp);
			w += wtmp;
			if(htmp - hetmp > uh) {
				uh = htmp - hetmp;
			}
			if(hetmp > dh) {
				dh = hetmp;
			}
		}

		central_point = dh;
		h = dh + uh;
		
		if(!layout_sign) {
			space_w = 5;
			sign_h = (h * 6) / 10;
			sign_w = sign_h;
			w += sign_w;
		}
		
		w += space_w * 2;
		
		double divider = 1.0;
		if(ips.power_depth >= 1) divider = 1.5;
		surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
		cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
		cr = cairo_create(surface);
		w = 0;
		for(size_t i = 0; i < surface_terms.size(); i++) {
			if(!CALCULATOR->aborted()) {
				gdk_cairo_set_source_rgba(cr, color);
				if(i > 0) {
					w += space_w;
					if(layout_sign) {
						cairo_move_to(cr, w, uh - sign_h / 2 - sign_h % 2);
						pango_cairo_show_layout(cr, layout_sign);
					} else {
						cairo_move_to(cr, w, h - 2 / divider - (h - sign_h) / 2);
						cairo_line_to(cr, w + (sign_w * 3) / 4, (h - sign_h) / 2);
						cairo_move_to(cr, w, h - 2 / divider - (h - sign_h) / 2);
						cairo_line_to(cr, w + sign_w, h - 2 / divider - (h - sign_h) / 2);
						cairo_set_line_width(cr, 2 / divider);
						cairo_stroke(cr);
					}
					w += sign_w;
					w += space_w;
				}
				cairo_set_source_surface(cr, surface_terms[i], w, uh - (hpt[i] - cpt[i]));
				cairo_paint(cr);
				w += wpt[i];
			}
			cairo_surface_destroy(surface_terms[i]);
		}
		if(layout_sign) g_object_unref(layout_sign);
	} else {
		switch(m.type()) {
			case STRUCT_NUMBER: {
				string str;
				string exp = "";
				bool exp_minus = false;
				ips_n.exp = &exp;
				ips_n.exp_minus = &exp_minus;
				TTBP(str)
				unordered_map<void*, string>::iterator it = number_map.find((void*) &m.number());
				string value_str;
				if(it != number_map.end()) {
					value_str += it->second;
					if(number_approx_map.find((void*) &m.number()) != number_approx_map.end()) {
						if(po.is_approximate && !(*po.is_approximate) && number_approx_map[(void*) &m.number()]) *po.is_approximate = true;
					}
					if(number_exp_map.find((void*) &m.number()) != number_exp_map.end()) {
						exp = number_exp_map[(void*) &m.number()];
						exp_minus = number_exp_minus_map[(void*) &m.number()];
					}
				} else {
					value_str = m.number().print(po, ips_n);
					if(po.base == BASE_HEXADECIMAL && po.base_display == BASE_DISPLAY_NORMAL) {
						gsub("0x", "", value_str);
					} else if(po.base == BASE_OCTAL && po.base_display == BASE_DISPLAY_NORMAL) {
						if(str.length() > 1 && value_str[0] == '0' && is_in(NUMBERS, value_str[1])) value_str.erase(0, 1);
					}
					number_map[(void*) &m.number()] = value_str;
					number_exp_map[(void*) &m.number()] = exp;
					number_exp_minus_map[(void*) &m.number()] = exp_minus;
					if(po.is_approximate) {
						number_approx_map[(void*) &m.number()] = *po.is_approximate;
					} else {
						number_approx_map[(void*) &m.number()] = FALSE;
					}
					number_base_map[(void*) &m.number()] = "";
				}
				if((!use_e_notation || (po.base != BASE_DECIMAL && po.base >= 2 && po.base <= 36)) && !exp.empty()) {
					if(value_str == "1") {
						MathStructure mnr(m_one);
						mnr.raise(m_one);
						number_map[(void*) &mnr[0].number()] = (po.base != BASE_DECIMAL && po.base >= 2 && po.base <= 36) ? i2s(po.base) : "10";
						if(exp_minus) {
							mnr[1].transform(STRUCT_NEGATE);
							number_map[(void*) &mnr[1][0].number()] = exp;
						} else {
							number_map[(void*) &mnr[1].number()] = exp;
						}
						surface = draw_structure(mnr, po, caf, ips, point_central, scaledown, color);
						if(exp_minus) number_map.erase(&mnr[1][0].number());
						else number_map.erase(&mnr[1].number());
						number_map.erase(&mnr[0].number());
						return surface;
					} else {
						MathStructure mnr(m_one);
						mnr.multiply(m_one);
						number_map[(void*) &mnr[0].number()] = value_str;
						number_approx_map[(void*) &mnr[0].number()] = number_approx_map[(void*) &m.number()];
						mnr[1].raise(m_one);
						number_map[(void*) &mnr[1][0].number()] = (po.base != BASE_DECIMAL && po.base >= 2 && po.base <= 36) ? i2s(po.base) : "10";
						if(exp_minus) {
							mnr[1][1].transform(STRUCT_NEGATE);
							number_map[(void*) &mnr[1][1][0].number()] = exp;
						} else {
							number_map[(void*) &mnr[1][1].number()] = exp;
						}
						surface = draw_structure(mnr, po, caf, ips, point_central, scaledown, color);
						if(exp_minus) number_map.erase(&mnr[1][1][0].number());
						else number_map.erase(&mnr[1][1].number());
						number_map.erase(&mnr[1][0].number());
						number_map.erase(&mnr[0].number());
						number_approx_map.erase(&mnr[0].number());
						return surface;
					}
				}
				if(exp.empty() && (po.base == BASE_SEXAGESIMAL || po.base == BASE_TIME)) {
					string estr;
					if(po.lower_case_e) {TTP(estr, "e");}
					else {TTP_SMALL(estr, "E");}
					if(po.lower_case_e) gsub("e", estr, value_str);
					else gsub("E", estr, value_str);
				}
				str += value_str;
				PangoLayout *layout = gtk_widget_create_pango_layout(resultview, NULL);
				if(!exp.empty()) {
					if(po.lower_case_e) {TTP(str, "e");}
					else {TTP_SMALL(str, "E");}
					if(exp_minus) {
						str += "-";
					}
					str += exp;
				}
				bool twos = (((po.base == 2 && po.twos_complement) || (po.base == 16 && po.hexadecimal_twos_complement)) && m.number().isNegative() && value_str.find(SIGN_MINUS) == string::npos && value_str.find("-") == string::npos);
				if(po.base != BASE_DECIMAL && (twos || po.base_display != BASE_DISPLAY_ALTERNATIVE || (po.base != BASE_HEXADECIMAL && po.base != BASE_BINARY && po.base != BASE_OCTAL)) && (po.base > 0 || po.base <= BASE_CUSTOM) && po.base <= 36) {
					TTBP_SMALL(str)
					str += "<sub>";
					string str_base;
					if(it != number_map.end()) {
						str_base = number_base_map[(void*) &m.number()];
					} else {
						switch(po.base) {
							case BASE_GOLDEN_RATIO: {str_base = "<i>φ</i>"; break;}
							case BASE_SUPER_GOLDEN_RATIO: {str_base = "<i>ψ</i>"; break;}
							case BASE_PI: {str_base = "<i>π</i>"; break;}
							case BASE_E: {str_base = "<i>e</i>"; break;}
							case BASE_SQRT2: {str_base = "√2"; break;}
							case BASE_UNICODE: {str_base = "Unicode"; break;}
							case BASE_BIJECTIVE_26: {str_base = "b26"; break;}
							case BASE_CUSTOM: {str_base = CALCULATOR->customOutputBase().print(CALCULATOR->messagePrintOptions()); break;}
							default: {str_base = i2s(po.base);}
						}
						if(twos) str_base += '-';
						number_base_map[(void*) &m.number()] = str_base;
					}
					str += str_base;
					str += "</sub>";
					TTE(str)
				}
				TTE(str)
				pango_layout_set_markup(layout, str.c_str(), -1);
				PangoRectangle rect;
				pango_layout_get_pixel_size(layout, &w, &h);
				pango_layout_get_pixel_extents(layout, &rect, NULL);
				w = rect.width + rect.x;
				w += 1;
				central_point = h / 2;
				surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
				cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
				cr = cairo_create(surface);
				gdk_cairo_set_source_rgba(cr, color);
				cairo_move_to(cr, 1, 0);
				pango_cairo_show_layout(cr, layout);
				g_object_unref(layout);
				break;
			}
			case STRUCT_ABORTED: {}
			case STRUCT_SYMBOLIC: {
				PangoLayout *layout = gtk_widget_create_pango_layout(resultview, NULL);
				string str;
				str = "<i>";
				TTBP(str)
				str += m.symbol();
				TTE(str)
				str += "</i>";
				pango_layout_set_markup(layout, str.c_str(), -1);
				PangoRectangle rect;
				pango_layout_get_pixel_size(layout, &w, &h);
				pango_layout_get_pixel_extents(layout, &rect, NULL);
				w = rect.width + rect.x;
				w += 1;
				central_point = h / 2;
				surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
				cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
				cr = cairo_create(surface);
				gdk_cairo_set_source_rgba(cr, color);
				cairo_move_to(cr, 1, 0);
				pango_cairo_show_layout(cr, layout);
				g_object_unref(layout);
				break;
			}
			case STRUCT_DATETIME: {
				PangoLayout *layout = gtk_widget_create_pango_layout(resultview, NULL);
				string str;
				TTBP(str)
				unordered_map<void*, string>::iterator it = date_map.find((void*) m.datetime());
				if(it != date_map.end()) {
					str += it->second;
				} else {
					string value_str = m.datetime()->print(po);
					date_map[(void*) m.datetime()] = value_str;
					str += value_str;
				}
				TTE(str)
				pango_layout_set_markup(layout, str.c_str(), -1);
				PangoRectangle rect;
				pango_layout_get_pixel_size(layout, &w, &h);
				pango_layout_get_pixel_extents(layout, &rect, NULL);
				w = rect.width + rect.x;
				w += 1;
				central_point = h / 2;
				surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
				cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
				cr = cairo_create(surface);
				gdk_cairo_set_source_rgba(cr, color);
				cairo_move_to(cr, 1, 0);
				pango_cairo_show_layout(cr, layout);
				g_object_unref(layout);
				break;
			}
			case STRUCT_ADDITION: {
				ips_n.depth++;
				
				vector<cairo_surface_t*> surface_terms;
				vector<gint> hpt;
				vector<gint> wpt;
				vector<gint> cpt;
				gint plus_w, plus_h, minus_w, minus_h, wtmp, htmp, hetmp = 0, w = 0, h = 0, dh = 0, uh = 0;
				
				CALCULATE_SPACE_W
				PangoLayout *layout_plus = gtk_widget_create_pango_layout(resultview, NULL);
				PANGO_TTP(layout_plus, "+");
				pango_layout_get_pixel_size(layout_plus, &plus_w, &plus_h);
				PangoLayout *layout_minus = gtk_widget_create_pango_layout(resultview, NULL);
				if(po.use_unicode_signs && (!po.can_display_unicode_string_function || (*po.can_display_unicode_string_function) (SIGN_MINUS, po.can_display_unicode_string_arg))) {
					PANGO_TTP(layout_minus, SIGN_MINUS);
				} else {
					PANGO_TTP(layout_minus, "-");
				}
				pango_layout_get_pixel_size(layout_minus, &minus_w, &minus_h);
				for(size_t i = 0; i < m.size(); i++) {
					hetmp = 0;		
					if(m[i].type() == STRUCT_NEGATE && i > 0) {
						ips_n.wrap = m[i][0].needsParenthesis(po, ips_n, m, i + 1, ips.division_depth > 0 || ips.power_depth > 0, ips.power_depth > 0);
						surface_terms.push_back(draw_structure(m[i][0], po, caf, ips_n, &hetmp, scaledown, color));
					} else {
						ips_n.wrap = m[i].needsParenthesis(po, ips_n, m, i + 1, ips.division_depth > 0 || ips.power_depth > 0, ips.power_depth > 0);
						surface_terms.push_back(draw_structure(m[i], po, caf, ips_n, &hetmp, scaledown, color));
					}
					if(CALCULATOR->aborted()) {
						for(size_t i = 0; i < surface_terms.size(); i++) {
							if(surface_terms[i]) cairo_surface_destroy(surface_terms[i]);
						}
						g_object_unref(layout_minus);
						g_object_unref(layout_plus);
						return NULL;
					}
					wtmp = cairo_image_surface_get_width(surface_terms[i]) / scalefactor;
					htmp = cairo_image_surface_get_height(surface_terms[i]) / scalefactor;
					hpt.push_back(htmp);
					cpt.push_back(hetmp);
					wpt.push_back(wtmp);
					w += wtmp;
					if(m[i].type() == STRUCT_NEGATE && i > 0) {
						w += minus_w;
						if(minus_h / 2 > dh) {
							dh = minus_h / 2;
						}
						if(minus_h / 2 + minus_h % 2 > uh) {
							uh = minus_h / 2 + minus_h % 2;
						}						
					} else if(i > 0) {
						w += plus_w;
						if(plus_h / 2 > dh) {
							dh = plus_h / 2;
						}
						if(plus_h / 2 + plus_h % 2 > uh) {
							uh = plus_h / 2 + plus_h % 2;
						}					
					}
					if(htmp - hetmp > uh) {
						uh = htmp - hetmp;
					}
					if(hetmp > dh) {
						dh = hetmp;
					}				
				}
				w += space_w * (surface_terms.size() - 1) * 2;
				central_point = dh;
				h = dh + uh;
				surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
				cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
				cr = cairo_create(surface);
				w = 0;
				for(size_t i = 0; i < surface_terms.size(); i++) {
					if(!CALCULATOR->aborted()) {
						gdk_cairo_set_source_rgba(cr, color);
						if(i > 0) {
							w += space_w;
							if(m[i].type() == STRUCT_NEGATE) {
								cairo_move_to(cr, w, uh - minus_h / 2 - minus_h % 2);
								pango_cairo_show_layout(cr, layout_minus);
								w += minus_w;
							} else {
								cairo_move_to(cr, w, uh - plus_h / 2 - plus_h % 2);
								pango_cairo_show_layout(cr, layout_plus);
								w += plus_w;
							}
							w += space_w;
						}
						cairo_set_source_surface(cr, surface_terms[i], w, uh - (hpt[i] - cpt[i]));
						cairo_paint(cr);
						w += wpt[i];
					}
					cairo_surface_destroy(surface_terms[i]);
				}
				g_object_unref(layout_minus);
				g_object_unref(layout_plus);
				break;
			}
			case STRUCT_NEGATE: {
				ips_n.depth++;

				gint minus_w, minus_h, uh, dh, h, w, ctmp, htmp, wtmp, hpa, cpa;
				//gint wpa;
				
				PangoLayout *layout_minus = gtk_widget_create_pango_layout(resultview, NULL);
				
				if(po.use_unicode_signs && (!po.can_display_unicode_string_function || (*po.can_display_unicode_string_function) (SIGN_MINUS, po.can_display_unicode_string_arg))) {
					PANGO_TTP(layout_minus, SIGN_MINUS);
				} else {
					PANGO_TTP(layout_minus, "-");
				}
				pango_layout_get_pixel_size(layout_minus, &minus_w, &minus_h);

				w = minus_w + 1;
				uh = minus_h / 2 + minus_h % 2;
				dh = minus_h / 2;
				
				ips_n.wrap = m[0].needsParenthesis(po, ips_n, m, 1, ips.division_depth > 0 || ips.power_depth > 0, ips.power_depth > 0);
				cairo_surface_t *surface_arg = draw_structure(m[0], po, caf, ips_n, &ctmp, scaledown, color);
				if(!surface_arg) {
					g_object_unref(layout_minus);
					return NULL;
				}
				/*if(ips.depth == 0 && !ips.parent_approximate && !m[0].isApproximate() && m[0].isNumber() && po.number_fraction_format == FRACTION_DECIMAL && po.is_approximate && *po.is_approximate && m[0].number().isRational() && ips.depth == 0 && m[0].number().denominatorIsLessThan(10) && m[0].number().numeratorIsLessThan(21)) {
					cairo_surface_destroy(surface_arg);
					g_object_unref(layout_minus);
					MathStructure mprint(m[0].number().numerator());
					mprint.transform(STRUCT_DIVISION, m[0].number().denominator());
					mprint.transform(STRUCT_NEGATE);
					mprint.transform(STRUCT_COMPARISON);
					mprint.setComparisonType(COMPARISON_EQUALS);
					m.ref();
					mprint.addChild_nocopy(&m);
					surface = draw_structure(mprint, po, caf, ips, &central_point, scaledown, color);
					cr = cairo_create(surface);
					gint w, h, wle, hle, w_new, h_new;
					w = cairo_image_surface_get_width(surface) / scalefactor;
					h = cairo_image_surface_get_height(surface) / scalefactor;
					cairo_surface_t *surface_old = surface;
					PangoLayout *layout_equals = gtk_widget_create_pango_layout(resultview, NULL);
					PANGO_TT(layout_equals, "=");
					CALCULATE_SPACE_W
					pango_layout_get_pixel_size(layout_equals, &wle, &hle);
					w_new = w + wle + 1 + space_w;
					h_new = h;
					surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w_new * scalefactor, h_new * scalefactor);
					cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
					cr = cairo_create(surface);
					gdk_cairo_set_source_rgba(cr, color);
					cairo_move_to(cr, 1, h - central_point - hle / 2 - hle % 2);
					pango_cairo_show_layout(cr, layout_equals);
					cairo_set_source_surface(cr, surface_old, wle + 1 + space_w, 0);
					cairo_paint(cr);
					cairo_surface_destroy(surface_old);
					g_object_unref(layout_equals);
					if(cr) cairo_destroy(cr);
					if(point_central) *point_central = central_point;
					return surface;
				}*/
				wtmp = cairo_image_surface_get_width(surface_arg) / scalefactor;
				htmp = cairo_image_surface_get_height(surface_arg) / scalefactor;
				hpa = htmp;
				cpa = ctmp;
				//wpa = wtmp;
				w += wtmp;
				if(ctmp > dh) {
					dh = ctmp;
				}
				if(htmp - ctmp > uh) {
					uh = htmp - ctmp;
				}				
				
				h = uh + dh;
				central_point = dh;

				surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
				cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
				cr = cairo_create(surface);
				
				w = 0;
				gdk_cairo_set_source_rgba(cr, color);
				cairo_move_to(cr, w, uh - minus_h / 2 - minus_h % 2);
				pango_cairo_show_layout(cr, layout_minus);
				w += minus_w + 1;
				cairo_set_source_surface(cr, surface_arg, w, uh - (hpa - cpa));
				cairo_paint(cr);
				cairo_surface_destroy(surface_arg);

				g_object_unref(layout_minus);
				break;
			}
			case STRUCT_MULTIPLICATION: {
				
				ips_n.depth++;
				
				vector<cairo_surface_t*> surface_terms;
				vector<gint> hpt;
				vector<gint> wpt;
				vector<gint> cpt;
				gint mul_w, mul_h, wtmp, htmp, hetmp = 0, w = 0, h = 0, dh = 0, uh = 0;
				
				bool b_cis = (!caf && m.size() == 2 && (m[0].isNumber() || (m[0].isNegate() && m[0][0].isNumber())) && m[1].isFunction() && m[1].size() == 1 && m[1].function()->referenceName() == "cis" && (((m[1][0].isNumber() || (m[1][0].isNegate() && m[1][0][0].isNumber())) || (m[1][0].isMultiplication() && m[1][0].size() == 2 && (m[1][0][0].isNumber() || (m[1][0].isNegate() && m[1][0][0][0].isNumber())) && m[1][0][1].isUnit())) || (m[1][0].isNegate() && m[1][0][0].isMultiplication() && m[1][0][0].size() == 2 && m[1][0][0][0].isNumber() && m[1][0][0][1].isUnit())));
				
				CALCULATE_SPACE_W
				PangoLayout *layout_mul = gtk_widget_create_pango_layout(resultview, NULL);
				string str;
				if(b_cis) {
					TTP(str, "cis");
				} else if(po.use_unicode_signs && po.multiplication_sign == MULTIPLICATION_SIGN_DOT && (!po.can_display_unicode_string_function || (*po.can_display_unicode_string_function) (SIGN_MULTIDOT, po.can_display_unicode_string_arg))) {
					TTP_SMALL(str, SIGN_MULTIDOT);
				} else if(po.use_unicode_signs && (po.multiplication_sign == MULTIPLICATION_SIGN_DOT || po.multiplication_sign == MULTIPLICATION_SIGN_ALTDOT) && (!po.can_display_unicode_string_function || (*po.can_display_unicode_string_function) (SIGN_MIDDLEDOT, po.can_display_unicode_string_arg))) {
					TTP_SMALL(str, SIGN_MIDDLEDOT);
				} else if(po.use_unicode_signs && po.multiplication_sign == MULTIPLICATION_SIGN_X && (!po.can_display_unicode_string_function || (*po.can_display_unicode_string_function) (SIGN_MULTIPLICATION, po.can_display_unicode_string_arg))) {
					TTP_SMALL(str, SIGN_MULTIPLICATION);
				} else {
					TTP(str, "*");
				}
				pango_layout_set_markup(layout_mul, str.c_str(), -1);
				pango_layout_get_pixel_size(layout_mul, &mul_w, &mul_h);
				bool par_prev = false;
				vector<int> nm;
				for(size_t i = 0; i < m.size(); i++) {
					hetmp = 0;
					ips_n.wrap = b_cis ? (i == 1 && ((m[1][0].isMultiplication() && m[1][0][1].neededMultiplicationSign(po, ips_n, m[1][0], 2, false, false, false, false) != MULTIPLICATION_SIGN_NONE) || (m[1][0].isNegate() && m[1][0][0].isMultiplication() && m[1][0][0][1].neededMultiplicationSign(po, ips_n, m[1][0][0], 2, false, false, false, false) != MULTIPLICATION_SIGN_NONE))) : m[i].needsParenthesis(po, ips_n, m, i + 1, ips.division_depth > 0 || ips.power_depth > 0, ips.power_depth > 0);
					surface_terms.push_back(draw_structure((b_cis && i == 1) ? m[i][0] : m[i], po, caf, ips_n, &hetmp, scaledown, color));
					if(CALCULATOR->aborted()) {
						for(size_t i = 0; i < surface_terms.size(); i++) {
							if(surface_terms[i]) cairo_surface_destroy(surface_terms[i]);
						}
						g_object_unref(layout_mul);
						return NULL;
					}
					wtmp = cairo_image_surface_get_width(surface_terms[i]) / scalefactor;
					htmp = cairo_image_surface_get_height(surface_terms[i]) / scalefactor;
					hpt.push_back(htmp);
					cpt.push_back(hetmp);
					wpt.push_back(wtmp);
					w += wtmp;
					if(i > 0) {
						if(b_cis || !po.short_multiplication) {
							nm.push_back(MULTIPLICATION_SIGN_OPERATOR);
						} else {
							nm.push_back(m[i].neededMultiplicationSign(po, ips_n, m, i + 1, ips_n.wrap || (m[i].isPower() && m[i][0].needsParenthesis(po, ips_n, m[i], 1, ips.division_depth > 0 || ips.power_depth > 0, ips.power_depth > 0)), par_prev, ips.division_depth > 0 || ips.power_depth > 0, ips.power_depth > 0));
						}
						switch(nm[i]) {
							case MULTIPLICATION_SIGN_SPACE: {
								w += space_w;
								break;
							}
							case MULTIPLICATION_SIGN_OPERATOR: {
								w += mul_w + space_w * 2;
								if(mul_h / 2 > dh) {
									dh = mul_h / 2;
								}
								if(mul_h / 2 + mul_h % 2 > uh) {
									uh = mul_h / 2 + mul_h % 2;
								}
								break;
							}
							case MULTIPLICATION_SIGN_OPERATOR_SHORT: {
								w += mul_w;
								if(mul_h / 2 > dh) {
									dh = mul_h / 2;
								}
								if(mul_h / 2 + mul_h % 2 > uh) {
									uh = mul_h / 2 + mul_h % 2;
								}
								break;
							}
							default: {
								if(m[i - 1].isNumber()) w++;
							}
						}
					} else {
						nm.push_back(-1);
					}
					if(htmp - hetmp > uh) {
						uh = htmp - hetmp;
					}
					if(hetmp > dh) {
						dh = hetmp;
					}
					par_prev = ips_n.wrap;
				}
				cairo_surface_t *flag_s = NULL;
				gint flag_width = 0;
				size_t flag_i = 0;
				if(m.size() == 2 && ((m[0].isUnit() && m[0].unit()->isCurrency() && m[1].isNumber()) || (m[1].isUnit() && m[1].unit()->isCurrency() && m[0].isNumber()))) {
					size_t i_unit = 0;
					if(m[1].isUnit()) {
						i_unit = 1;
						flag_i = 1;
					} else if(nm[1] == MULTIPLICATION_SIGN_NONE) {
						flag_i = 1;
					}
					string imagefile = "/qalculate-gtk/flags/"; imagefile += m[i_unit].unit()->referenceName(); imagefile += ".png";
					GdkPixbuf *pixbuf = NULL;
					h = hpt[flag_i];
					if(h < 48) pixbuf = gdk_pixbuf_new_from_resource_at_scale(imagefile.c_str(), -1, h / 3, TRUE, NULL);
					else pixbuf = gdk_pixbuf_new_from_resource(imagefile.c_str(), NULL);
					if(pixbuf) {
						flag_s = gdk_cairo_surface_create_from_pixbuf(pixbuf, 1, NULL);
						flag_width = cairo_image_surface_get_width(flag_s);
						w += flag_width + 2;
						g_object_unref(pixbuf);
					}
				}
				central_point = dh;
				h = dh + uh;
				surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
				cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
				cr = cairo_create(surface);
				w = 0;
				for(size_t i = 0; i < surface_terms.size(); i++) {
					if(!CALCULATOR->aborted()) {
						gdk_cairo_set_source_rgba(cr, color);
						if(i > 0) {
							switch(nm[i]) {
								case MULTIPLICATION_SIGN_SPACE: {
									w += space_w;
									break;
								}
								case MULTIPLICATION_SIGN_OPERATOR: {
									w += space_w;
									cairo_move_to(cr, w, uh - mul_h / 2 - mul_h % 2);
									pango_cairo_show_layout(cr, layout_mul);
									w += mul_w;
									w += space_w;
									break;
								}
								case MULTIPLICATION_SIGN_OPERATOR_SHORT: {
									cairo_move_to(cr, w, uh - mul_h / 2 - mul_h % 2);
									pango_cairo_show_layout(cr, layout_mul);
									w += mul_w;
									break;
								}
								default: {
									if(m[i - 1].isNumber()) w++;
								}
							}
						}
						cairo_set_source_surface(cr, surface_terms[i], w, uh - (hpt[i] - cpt[i]));
						cairo_paint(cr);
						w += wpt[i];
						if(flag_s && i == 0 && flag_i == 0) {
							gdk_cairo_set_source_rgba(cr, color);
							cairo_set_source_surface(cr, flag_s, w + 2, uh - (hpt[i] - cpt[i]) + hpt[i] / 8);
							cairo_paint(cr);
							cairo_surface_destroy(flag_s);
							flag_s = NULL;
							w += flag_width + 2;
						}
					}
					cairo_surface_destroy(surface_terms[i]);
				}
				if(flag_s) {
					if(!CALCULATOR->aborted()) {
						gdk_cairo_set_source_rgba(cr, color);
						cairo_set_source_surface(cr, flag_s, w + 2, uh - (hpt.back() - cpt.back()) + hpt.back() / 8);
						cairo_paint(cr);
					}
					cairo_surface_destroy(flag_s);
				}
				g_object_unref(layout_mul);
				break;
			}
			case STRUCT_INVERSE: {}
			case STRUCT_DIVISION: {

				ips_n.depth++;
				ips_n.division_depth++;
				
				gint den_uh, den_w, den_dh, num_w, num_dh, num_uh, dh = 0, uh = 0, w = 0, h = 0, one_w = 0, one_h = 0;
				
				bool flat = ips.division_depth > 0 || ips.power_depth > 0;
				if(!flat && po.place_units_separately) {
					flat = true;
					size_t i = 0;
					if(m.isDivision()) {
						i = 1;
					}
					if(m[i].isMultiplication()) {
						for(size_t i2 = 0; i2 < m[i].size(); i2++) {
							if(!m[i][i2].isUnit_exp()) {
								flat = false;
								break;
							}
						}
					} else if(!m[i].isUnit_exp()) {
						flat = false;
					}
					if(flat) {
						ips_n.division_depth--;
					}
				}
				cairo_surface_t *num_surface = NULL, *den_surface = NULL, *surface_one = NULL;
				if(m.type() == STRUCT_DIVISION) {
					ips_n.wrap = (!m[0].isDivision() || !flat || ips.division_depth > 0 || ips.power_depth > 0) && m[0].needsParenthesis(po, ips_n, m, 1, flat, ips.power_depth > 0);
					num_surface = draw_structure(m[0], po, caf, ips_n, &num_dh, scaledown, color);
					if(!num_surface) {
						return NULL;
					}
					num_w = cairo_image_surface_get_width(num_surface) / scalefactor;
					h = cairo_image_surface_get_height(num_surface) / scalefactor;
					num_uh = h - num_dh;
				} else {
					MathStructure onestruct(1, 1);
					ips_n.wrap = false;
					surface_one = draw_structure(onestruct, po, caf, ips_n, NULL, scaledown, color);
					if(!surface_one) {
						return NULL;
					}
					one_w = cairo_image_surface_get_width(surface_one) / scalefactor;
					one_h = cairo_image_surface_get_height(surface_one) / scalefactor;
					num_w = one_w; num_dh = one_h / 2; num_uh = one_h - num_dh;
				}
				if(m.type() == STRUCT_DIVISION) {
					ips_n.wrap = m[1].needsParenthesis(po, ips_n, m, 2, flat, ips.power_depth > 0);
					den_surface = draw_structure(m[1], po, caf, ips_n, &den_dh, scaledown, color);
				} else {
					ips_n.wrap = m[0].needsParenthesis(po, ips_n, m, 2, flat, ips.power_depth > 0);
					den_surface = draw_structure(m[0], po, caf, ips_n, &den_dh, scaledown, color);
				}
				if(!den_surface) {
					if(num_surface) cairo_surface_destroy(num_surface);
					if(surface_one) cairo_surface_destroy(surface_one);
					return NULL;
				}
				den_w = cairo_image_surface_get_width(den_surface) / scalefactor;
				h = cairo_image_surface_get_height(den_surface) / scalefactor;
				den_uh = h - den_dh;
				h = 0;
				if(flat) {
					gint div_w, div_h;
					PangoLayout *layout_div = gtk_widget_create_pango_layout(resultview, NULL);
					CALCULATE_SPACE_W
					if(po.use_unicode_signs && po.division_sign == DIVISION_SIGN_DIVISION && (!po.can_display_unicode_string_function || (*po.can_display_unicode_string_function) (SIGN_DIVISION, po.can_display_unicode_string_arg))) {
						PANGO_TTP(layout_div, SIGN_DIVISION);
					} else if(po.use_unicode_signs && po.division_sign == DIVISION_SIGN_DIVISION_SLASH && (!po.can_display_unicode_string_function || (*po.can_display_unicode_string_function) (SIGN_DIVISION_SLASH, po.can_display_unicode_string_arg))) {
						PANGO_TTP(layout_div, SIGN_DIVISION_SLASH);
					} else {
						PANGO_TTP(layout_div, "/");
					}
					pango_layout_get_pixel_size(layout_div, &div_w, &div_h);
					w = num_w + den_w + space_w + space_w + div_w;
					dh = num_dh; uh = num_uh;
					if(den_dh > dh) h = den_dh;
					if(den_uh > uh) uh = den_uh;
					if(div_h / 2 > dh) {
						dh = div_h / 2;
					}
					if(div_h / 2 + div_h % 2 > uh) {
						uh = div_h / 2 + div_h % 2;
					}
					h = uh + dh;
					central_point = dh;
					surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
					cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
					cr = cairo_create(surface);
					gdk_cairo_set_source_rgba(cr, color);
					w = 0;
					if(m.type() == STRUCT_DIVISION) {
						cairo_set_source_surface(cr, num_surface, w, uh - num_uh);
						cairo_paint(cr);
					} else {
						cairo_set_source_surface(cr, surface_one, w, uh - one_h / 2 - one_h % 2);
						cairo_paint(cr);
					}
					w += num_w;
					w += space_w;
					gdk_cairo_set_source_rgba(cr, color);
					cairo_move_to(cr, w, uh - div_h / 2 - div_h % 2);
					pango_cairo_show_layout(cr, layout_div);
					w += div_w;
					w += space_w;
					cairo_set_source_surface(cr, den_surface, w, uh - den_uh);
					cairo_paint(cr);
					g_object_unref(layout_div);
				} else {
					gint wfr;
					dh = den_dh + den_uh + 3;
					uh = num_dh + num_uh + 3;
					wfr = den_w;
					if(num_w > wfr) wfr = num_w;
					wfr += 2;
					w = wfr;
					h = uh + dh;
					central_point = dh;
					surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
					cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
					cr = cairo_create(surface);
					gdk_cairo_set_source_rgba(cr, color);
					w = 0;
					if(m.type() == STRUCT_DIVISION) {
						cairo_set_source_surface(cr, num_surface, w + (wfr - num_w) / 2, uh - 3 - num_uh - num_dh);
						cairo_paint(cr);
					} else {
						cairo_set_source_surface(cr, surface_one, w + (wfr - one_w) / 2, uh - 3 - one_h);
						cairo_paint(cr);
					}
					gdk_cairo_set_source_rgba(cr, color);
					cairo_move_to (cr, w, uh - 1);
					cairo_line_to (cr, w + wfr, uh - 1);
					cairo_set_line_width(cr, 2);
					cairo_stroke(cr);
					cairo_set_source_surface(cr, den_surface, w + (wfr - den_w) / 2, uh + 3);
					cairo_paint(cr);
				}
				if(num_surface) cairo_surface_destroy(num_surface);
				if(den_surface) cairo_surface_destroy(den_surface);
				if(surface_one) cairo_surface_destroy(surface_one);
				break;
			}
			case STRUCT_POWER: {

				ips_n.depth++;
				
				gint base_w, base_h, exp_w, exp_h, w = 0, h = 0, ctmp = 0;
				CALCULATE_SPACE_W
				ips_n.wrap = m[0].needsParenthesis(po, ips_n, m, 1, ips.division_depth > 0, false);
				cairo_surface_t *surface_base = draw_structure(m[0], po, caf, ips_n, &central_point, scaledown, color);
				if(!surface_base) {
					return NULL;
				}
				base_w = cairo_image_surface_get_width(surface_base) / scalefactor;
				base_h = cairo_image_surface_get_height(surface_base) / scalefactor;
				
				ips_n.power_depth++;
				ips_n.wrap = false;
				PrintOptions po2 = po;
				po2.show_ending_zeroes = false;
				cairo_surface_t *surface_exp = draw_structure(m[1], po2, caf, ips_n, &ctmp, scaledown, color);
				if(!surface_exp) {
					cairo_surface_destroy(surface_base);
					return NULL;
				}
				exp_w = cairo_image_surface_get_width(surface_exp) / scalefactor;
				exp_h = cairo_image_surface_get_height(surface_exp) / scalefactor;
				h = base_h;
				w = base_w;
				if(exp_h < h) {
					h += exp_h / 3;
				} else {
					h += exp_h - base_h / 2;
				}
				w += exp_w;
				
				surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
				cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
				cr = cairo_create(surface);
				gdk_cairo_set_source_rgba(cr, color);
				w = 0;
				cairo_set_source_surface(cr, surface_base, w, h - base_h);
				cairo_paint(cr);
				cairo_surface_destroy(surface_base);
				w += base_w;
				gdk_cairo_set_source_rgba(cr, color);
				cairo_set_source_surface(cr, surface_exp, w, 0);
				cairo_paint(cr);
				cairo_surface_destroy(surface_exp);

				break;
			}
			case STRUCT_LOGICAL_AND: {
				if(!po.preserve_format && m.size() == 2 && m[0].isComparison() && m[1].isComparison() && m[0].comparisonType() != COMPARISON_EQUALS && m[0].comparisonType() != COMPARISON_NOT_EQUALS && m[1].comparisonType() != COMPARISON_EQUALS && m[1].comparisonType() != COMPARISON_NOT_EQUALS && m[0][0] == m[1][0]) {
					ips_n.depth++;
				
					vector<cairo_surface_t*> surface_terms;
					vector<gint> hpt;
					vector<gint> wpt;
					vector<gint> cpt;
					gint sign_w, sign_h, sign2_w, sign2_h, wtmp, htmp, hetmp = 0, w = 0, h = 0, dh = 0, uh = 0;
					CALCULATE_SPACE_W
				
					hetmp = 0;		
					ips_n.wrap = m[0][1].needsParenthesis(po, ips_n, m[0], 2, ips.division_depth > 0 || ips.power_depth > 0, ips.power_depth > 0);
					surface_terms.push_back(draw_structure(m[0][1], po, caf, ips_n, &hetmp, scaledown, color));
					if(CALCULATOR->aborted()) {
						return NULL;
					}
					wtmp = cairo_image_surface_get_width(surface_terms[0]) / scalefactor;
					htmp = cairo_image_surface_get_height(surface_terms[0]) / scalefactor;
					hpt.push_back(htmp);
					cpt.push_back(hetmp);
					wpt.push_back(wtmp);
					w += wtmp;
					if(htmp - hetmp > uh) {
						uh = htmp - hetmp;
					}
					if(hetmp > dh) {
						dh = hetmp;
					}
					hetmp = 0;		
					ips_n.wrap = m[0][0].needsParenthesis(po, ips_n, m[0], 1, ips.division_depth > 0 || ips.power_depth > 0, ips.power_depth > 0);
					surface_terms.push_back(draw_structure(m[0][0], po, caf, ips_n, &hetmp, scaledown, color));
					if(CALCULATOR->aborted()) {
						cairo_surface_destroy(surface_terms[0]);
						return NULL;
					}
					wtmp = cairo_image_surface_get_width(surface_terms[1]) / scalefactor;
					htmp = cairo_image_surface_get_height(surface_terms[1]) / scalefactor;
					hpt.push_back(htmp);
					cpt.push_back(hetmp);
					wpt.push_back(wtmp);
					w += wtmp;
					if(htmp - hetmp > uh) {
						uh = htmp - hetmp;
					}
					if(hetmp > dh) {
						dh = hetmp;
					}
					hetmp = 0;		
					ips_n.wrap = m[1][1].needsParenthesis(po, ips_n, m[1], 2, ips.division_depth > 0 || ips.power_depth > 0, ips.power_depth > 0);
					surface_terms.push_back(draw_structure(m[1][1], po, caf, ips_n, &hetmp, scaledown, color));
					if(CALCULATOR->aborted()) {
						cairo_surface_destroy(surface_terms[0]);
						cairo_surface_destroy(surface_terms[1]);
						return NULL;
					}
					wtmp = cairo_image_surface_get_width(surface_terms[2]) / scalefactor;
					htmp = cairo_image_surface_get_height(surface_terms[2]) / scalefactor;
					hpt.push_back(htmp);
					cpt.push_back(hetmp);
					wpt.push_back(wtmp);
					w += wtmp;
					if(htmp - hetmp > uh) {
						uh = htmp - hetmp;
					}
					if(hetmp > dh) {
						dh = hetmp;
					}
				
					PangoLayout *layout_sign = gtk_widget_create_pango_layout(resultview, NULL);
					string str;
					TTBP(str);
					switch(m[0].comparisonType()) {
						case COMPARISON_LESS: {
							str += "&gt;";
							break;
						}
						case COMPARISON_GREATER: {
							str += "&lt;";
							break;
						}
						case COMPARISON_EQUALS_LESS: {
							if(po.use_unicode_signs && (!po.can_display_unicode_string_function || (*po.can_display_unicode_string_function) (SIGN_GREATER_OR_EQUAL, po.can_display_unicode_string_arg))) {
								str += SIGN_GREATER_OR_EQUAL;
							} else {
								str += "&gt;=";
							}
							break;
						}
						case COMPARISON_EQUALS_GREATER: {
							if(po.use_unicode_signs && (!po.can_display_unicode_string_function || (*po.can_display_unicode_string_function) (SIGN_LESS_OR_EQUAL, po.can_display_unicode_string_arg))) {
								str += SIGN_LESS_OR_EQUAL;
							} else {
								str += "&lt;=";
							}
							break;
						}
						default: {}
					}
					TTE(str);
					pango_layout_set_markup(layout_sign, str.c_str(), -1);
					pango_layout_get_pixel_size(layout_sign, &sign_w, &sign_h);
					if(sign_h / 2 > dh) {
						dh = sign_h / 2;
					}
					if(sign_h / 2 + sign_h % 2 > uh) {
						uh = sign_h / 2 + sign_h % 2;
					}
					w += sign_w;
					
					PangoLayout *layout_sign2 = gtk_widget_create_pango_layout(resultview, NULL);
					str = "";
					TTBP(str);
					switch(m[1].comparisonType()) {
						case COMPARISON_GREATER: {
							str += "&gt;";
							break;
						}
						case COMPARISON_LESS: {
							str += "&lt;";
							break;
						}
						case COMPARISON_EQUALS_GREATER: {
							if(po.use_unicode_signs && (!po.can_display_unicode_string_function || (*po.can_display_unicode_string_function) (SIGN_GREATER_OR_EQUAL, po.can_display_unicode_string_arg))) {
								str += SIGN_GREATER_OR_EQUAL;
							} else {
								str += "&gt;=";
							}
							break;
						}
						case COMPARISON_EQUALS_LESS: {
							if(po.use_unicode_signs && (!po.can_display_unicode_string_function || (*po.can_display_unicode_string_function) (SIGN_LESS_OR_EQUAL, po.can_display_unicode_string_arg))) {
								str += SIGN_LESS_OR_EQUAL;
							} else {
								str += "&lt;=";
							}
							break;
						}
						default: {}
					}
					TTE(str);
					pango_layout_set_markup(layout_sign2, str.c_str(), -1);
					pango_layout_get_pixel_size(layout_sign2, &sign2_w, &sign2_h);
					if(sign2_h / 2 > dh) {
						dh = sign2_h / 2;
					}
					if(sign2_h / 2 + sign2_h % 2 > uh) {
						uh = sign2_h / 2 + sign2_h % 2;
					}
					w += sign2_w;
					
				
					w += space_w * (surface_terms.size() - 1) * 2;
				
					central_point = dh;
					h = dh + uh;
					surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
					cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
					cr = cairo_create(surface);
					w = 0;
					for(size_t i = 0; i < surface_terms.size(); i++) {
						gdk_cairo_set_source_rgba(cr, color);
						if(i > 0) {
							w += space_w;
							if(i == 1) {
								cairo_move_to(cr, w, uh - sign_h / 2 - sign_h % 2);
								pango_cairo_show_layout(cr, layout_sign);
								w += sign_w;
							} else {
								cairo_move_to(cr, w, uh - sign2_h / 2 - sign2_h % 2);
								pango_cairo_show_layout(cr, layout_sign2);
								w += sign2_w;
							}
							w += space_w;
						}
						cairo_set_source_surface(cr, surface_terms[i], w, uh - (hpt[i] - cpt[i]));
						cairo_paint(cr);
						w += wpt[i];
						cairo_surface_destroy(surface_terms[i]);
					}
					g_object_unref(layout_sign);
					g_object_unref(layout_sign2);
					break;
				}
			}
			case STRUCT_COMPARISON: {}
			case STRUCT_LOGICAL_XOR: {}
			case STRUCT_LOGICAL_OR: {}
			case STRUCT_BITWISE_AND: {}
			case STRUCT_BITWISE_XOR: {}
			case STRUCT_BITWISE_OR: {

				ips_n.depth++;
				
				vector<cairo_surface_t*> surface_terms;
				vector<gint> hpt;
				vector<gint> wpt;
				vector<gint> cpt;
				gint sign_w, sign_h, wtmp, htmp, hetmp = 0, w = 0, h = 0, dh = 0, uh = 0;
				CALCULATE_SPACE_W
				
				for(size_t i = 0; i < m.size(); i++) {
					hetmp = 0;		
					ips_n.wrap = m[i].needsParenthesis(po, ips_n, m, i + 1, ips.division_depth > 0 || ips.power_depth > 0, ips.power_depth > 0);
					surface_terms.push_back(draw_structure(m[i], po, caf, ips_n, &hetmp, scaledown, color));
					if(CALCULATOR->aborted()) {
						for(size_t i = 0; i < surface_terms.size(); i++) {
							if(surface_terms[i]) cairo_surface_destroy(surface_terms[i]);
						}
						return NULL;
					}
					wtmp = cairo_image_surface_get_width(surface_terms[i]) / scalefactor;
					htmp = cairo_image_surface_get_height(surface_terms[i]) / scalefactor;
					hpt.push_back(htmp);
					cpt.push_back(hetmp);
					wpt.push_back(wtmp);
					w += wtmp;
					if(htmp - hetmp > uh) {
						uh = htmp - hetmp;
					}
					if(hetmp > dh) {
						dh = hetmp;
					}				
				}
				
				PangoLayout *layout_sign = gtk_widget_create_pango_layout(resultview, NULL);
				string str;
				TTBP(str);
				if(m.type() == STRUCT_COMPARISON) {
					switch(m.comparisonType()) {
						case COMPARISON_EQUALS: {
							if((ips.depth == 0 || (po.interval_display != INTERVAL_DISPLAY_INTERVAL && m.containsInterval())) && po.use_unicode_signs && ((po.is_approximate && *po.is_approximate) || m.isApproximate()) && (!po.can_display_unicode_string_function || (*po.can_display_unicode_string_function) (SIGN_ALMOST_EQUAL, po.can_display_unicode_string_arg))) {
								str += SIGN_ALMOST_EQUAL;
							} else {
								str += "=";
							}
							break;
						}
						case COMPARISON_NOT_EQUALS: {
							if(po.use_unicode_signs && (!po.can_display_unicode_string_function || (*po.can_display_unicode_string_function) (SIGN_NOT_EQUAL, po.can_display_unicode_string_arg))) {
								str += SIGN_NOT_EQUAL;
							} else {
								str += "!=";
							}
							break;
						}
						case COMPARISON_GREATER: {
							str += "&gt;";
							break;
						}
						case COMPARISON_LESS: {
							str += "&lt;";
							break;
						}
						case COMPARISON_EQUALS_GREATER: {
							if(po.use_unicode_signs && (!po.can_display_unicode_string_function || (*po.can_display_unicode_string_function) (SIGN_GREATER_OR_EQUAL, po.can_display_unicode_string_arg))) {
								str += SIGN_GREATER_OR_EQUAL;
							} else {
								str += "&gt;=";
							}
							break;
						}
						case COMPARISON_EQUALS_LESS: {
							if(po.use_unicode_signs && (!po.can_display_unicode_string_function || (*po.can_display_unicode_string_function) (SIGN_LESS_OR_EQUAL, po.can_display_unicode_string_arg))) {
								str += SIGN_LESS_OR_EQUAL;
							} else {
								str += "&lt;=";
							}
							break;
						}
					}
				} else if(m.type() == STRUCT_LOGICAL_AND) {
					if(po.spell_out_logical_operators) str += _("and");
					else str += "&amp;&amp;";
				} else if(m.type() == STRUCT_LOGICAL_OR) {
					if(po.spell_out_logical_operators) str += _("or");
					else str += "||";
				} else if(m.type() == STRUCT_LOGICAL_XOR) {
					str += "xor";
				} else if(m.type() == STRUCT_BITWISE_AND) {
					str += "&amp;";
				} else if(m.type() == STRUCT_BITWISE_OR) {
					str += "|";
				} else if(m.type() == STRUCT_BITWISE_XOR) {
					str += "xor";
				}
				
				TTE(str);
				pango_layout_set_markup(layout_sign, str.c_str(), -1);
				pango_layout_get_pixel_size(layout_sign, &sign_w, &sign_h);
				if(sign_h / 2 > dh) {
					dh = sign_h / 2;
				}
				if(sign_h / 2 + sign_h % 2 > uh) {
					uh = sign_h / 2 + sign_h % 2;
				}
				w += sign_w * (m.size() - 1);
				
				w += space_w * (surface_terms.size() - 1) * 2;
				
				central_point = dh;
				h = dh + uh;
				surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
				cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
				cr = cairo_create(surface);
				w = 0;
				for(size_t i = 0; i < surface_terms.size(); i++) {
					if(!CALCULATOR->aborted()) {
						gdk_cairo_set_source_rgba(cr, color);
						if(i > 0) {
							w += space_w;
							cairo_move_to(cr, w, uh - sign_h / 2 - sign_h % 2);
							pango_cairo_show_layout(cr, layout_sign);
							w += sign_w;	
							w += space_w;			
						}
						cairo_set_source_surface(cr, surface_terms[i], w, uh - (hpt[i] - cpt[i]));
						cairo_paint(cr);
						w += wpt[i];
					}
					cairo_surface_destroy(surface_terms[i]);
				}
				g_object_unref(layout_sign);
				break;
			}
			case STRUCT_LOGICAL_NOT: {}
			case STRUCT_BITWISE_NOT: {

				ips_n.depth++;

				gint not_w, not_h, uh, dh, h, w, ctmp, htmp, wtmp, hpa, cpa;
				//gint wpa;
				
				PangoLayout *layout_not = gtk_widget_create_pango_layout(resultview, NULL);
				
				if(m.type() == STRUCT_LOGICAL_NOT) {
					PANGO_TTP(layout_not, "!");
				} else {
					if(po.use_unicode_signs && (!po.can_display_unicode_string_function || (*po.can_display_unicode_string_function) ("¬", po.can_display_unicode_string_arg))) {
						PANGO_TTP(layout_not, "¬");
					} else {
						PANGO_TTP(layout_not, "~");
					}
				}
				pango_layout_get_pixel_size(layout_not, &not_w, &not_h);

				w = not_w + 1;
				uh = not_h / 2 + not_h % 2;
				dh = not_h / 2;
				
				ips_n.wrap = m[0].needsParenthesis(po, ips_n, m, 1, ips.division_depth > 0 || ips.power_depth > 0, ips.power_depth > 0);
				cairo_surface_t *surface_arg = draw_structure(m[0], po, caf, ips_n, &ctmp, scaledown, color);
				if(!surface_arg) {
					g_object_unref(layout_not);
					return NULL;
				}
				wtmp = cairo_image_surface_get_width(surface_arg) / scalefactor;
				htmp = cairo_image_surface_get_height(surface_arg) / scalefactor;
				hpa = htmp;
				cpa = ctmp;
				//wpa = wtmp;
				w += wtmp;
				if(ctmp > dh) {
					dh = ctmp;
				}
				if(htmp - ctmp > uh) {
					uh = htmp - ctmp;
				}				
				
				h = uh + dh;
				central_point = dh;

				surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
				cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
				cr = cairo_create(surface);
				
				w = 0;
				gdk_cairo_set_source_rgba(cr, color);
				cairo_move_to(cr, w, uh - not_h / 2 - not_h % 2);
				pango_cairo_show_layout(cr, layout_not);
				w += not_w + 1;
				cairo_set_source_surface(cr, surface_arg, w, uh - (hpa - cpa));
				cairo_paint(cr);
				cairo_surface_destroy(surface_arg);
				
				g_object_unref(layout_not);
				break;
			}
			case STRUCT_VECTOR: {

				ips_n.depth++;
				
				if(m.isMatrix()) {
					if(m[0].size() == 0) {
						PangoLayout *layout = gtk_widget_create_pango_layout(resultview, NULL);
						string str;
						TTBP(str)
						str += "[ ]";
						TTE(str)
						pango_layout_set_markup(layout, str.c_str(), -1);
						PangoRectangle rect;
						pango_layout_get_pixel_size(layout, &w, &h);
						pango_layout_get_pixel_extents(layout, &rect, NULL);
						w = rect.width + rect.x;
						w += 1;
						central_point = h / 2;
						surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
						cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
						cr = cairo_create(surface);
						gdk_cairo_set_source_rgba(cr, color);
						cairo_move_to(cr, 1, 0);
						pango_cairo_show_layout(cr, layout);
						g_object_unref(layout);
						break;
					}
					gint wtmp, htmp, ctmp = 0, w = 0, h = 0;
					CALCULATE_SPACE_W
					vector<gint> col_w;
					vector<gint> row_h;
					vector<gint> row_uh;
					vector<gint> row_dh;									
					vector<vector<gint> > element_w;
					vector<vector<gint> > element_h;
					vector<vector<gint> > element_c;			
					vector<vector<cairo_surface_t*> > surface_elements;
					element_w.resize(m.size());
					element_h.resize(m.size());
					element_c.resize(m.size());						
					surface_elements.resize(m.size());
					PangoLayout *layout_comma = gtk_widget_create_pango_layout(resultview, NULL);
					string str;
					gint comma_w = 0, comma_h = 0;
					TTP(str, po.comma())
					pango_layout_set_markup(layout_comma, str.c_str(), -1);		
					pango_layout_get_pixel_size(layout_comma, &comma_w, &comma_h);
					for(size_t index_r = 0; index_r < m.size(); index_r++) {
						for(size_t index_c = 0; index_c < m[index_r].size(); index_c++) {
							ctmp = 0;
							ips_n.wrap = m[index_r][index_c].needsParenthesis(po, ips_n, m, index_r + 1, ips.division_depth > 0 || ips.power_depth > 0, ips.power_depth > 0);
							surface_elements[index_r].push_back(draw_structure(m[index_r][index_c], po, caf, ips_n, &ctmp, scaledown, color));
							if(CALCULATOR->aborted()) {
								break;
							}
							wtmp = cairo_image_surface_get_width(surface_elements[index_r][index_c]) / scalefactor;
							htmp = cairo_image_surface_get_height(surface_elements[index_r][index_c]) / scalefactor;
							element_w[index_r].push_back(wtmp);
							element_h[index_r].push_back(htmp);
							element_c[index_r].push_back(ctmp);					
							if(index_r == 0) {
								col_w.push_back(wtmp);
							} else if(wtmp > col_w[index_c]) {
								col_w[index_c] = wtmp;
							}
							if(index_c == 0) {
								row_uh.push_back(htmp - ctmp);
								row_dh.push_back(ctmp);
							} else {
								if(ctmp > row_dh[index_r]) {
									row_dh[index_r] = ctmp;
								}
								if(htmp - ctmp > row_uh[index_r]) {
									row_uh[index_r] = htmp - ctmp;
								}						
							}
						}
						if(CALCULATOR->aborted()) {
							break;
						}
						row_h.push_back(row_uh[index_r] + row_dh[index_r]);
						h += row_h[index_r];
						if(index_r != 0) {
							h += 4;
						}
					}	
					h += 4;
					for(size_t i = 0; i < col_w.size(); i++) {
						w += col_w[i];
						if(i != 0) {
							w += space_w * 2;
						}
					}
		
					gint wlr, wll;
					wll = 10;
					wlr = 10;
				
					w += wlr + 1;
					w += wll + 3;
					central_point = h / 2;
					surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
					cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
					cr = cairo_create(surface);
					gdk_cairo_set_source_rgba(cr, color);
					w = 1;
					cairo_move_to(cr, w, 1);
					cairo_line_to(cr, w, h - 1);
					cairo_move_to(cr, w, 1);
					cairo_line_to(cr, w + 7, 1);
					cairo_move_to(cr, w, h - 1);
					cairo_line_to(cr, w + 7, h - 1);
					cairo_set_line_width(cr, 2);
					cairo_stroke(cr);
					h = 2;
					for(size_t index_r = 0; index_r < surface_elements.size(); index_r++) {
						if(!CALCULATOR->aborted()) {
							gdk_cairo_set_source_rgba(cr, color);
							w = wll + 1;
						}
						for(size_t index_c = 0; index_c < surface_elements[index_r].size(); index_c++) {
							if(!CALCULATOR->aborted()) {
								cairo_set_source_surface(cr, surface_elements[index_r][index_c], w + (col_w[index_c] - element_w[index_r][index_c]), h + row_uh[index_r] - (element_h[index_r][index_c] - element_c[index_r][index_c]));
								cairo_paint(cr);
								w += col_w[index_c];
								if(index_c != m[index_r].size() - 1) {
									w += space_w * 2;
								}
							}
							if(surface_elements[index_r][index_c]) {
								cairo_surface_destroy(surface_elements[index_r][index_c]);
							}
						}
						if(!CALCULATOR->aborted()) {
							h += row_h[index_r];
							h += 4;
						}
					}
					h -= 4;
					h += 2;
					w += wll - 7;
					gdk_cairo_set_source_rgba(cr, color);
					cairo_move_to(cr, w + 7, 1);
					cairo_line_to(cr, w + 7, h - 1);
					cairo_move_to(cr, w, 1);
					cairo_line_to(cr, w + 7, 1);
					cairo_move_to(cr, w, h - 1);
					cairo_line_to(cr, w + 7, h - 1);
					cairo_set_line_width(cr, 2);
					cairo_stroke(cr);
					g_object_unref(layout_comma);
					break;
				}
				
				gint comma_w, comma_h, uh = 0, dh = 0, h = 0, w = 0, ctmp, htmp, wtmp, arc_w, arc_h;
				vector<cairo_surface_t*> surface_args;
				vector<gint> hpa;
				vector<gint> cpa;			
				vector<gint> wpa;
				
				CALCULATE_SPACE_W
				PangoLayout *layout_comma = gtk_widget_create_pango_layout(resultview, NULL);
				string str, func_str;
				TTP(str, CALCULATOR->getComma())
				pango_layout_set_markup(layout_comma, str.c_str(), -1);		
				pango_layout_get_pixel_size(layout_comma, &comma_w, &comma_h);

				if(m.size() == 0) {
					PangoLayout *layout_one = gtk_widget_create_pango_layout(resultview, NULL);
					TTP(str, "1")
					pango_layout_set_markup(layout_one, str.c_str(), -1);
					pango_layout_get_pixel_size(layout_one, &w, &h);
					uh = h / 2 + h % 2;
					dh = h / 2;
					w = 2;
					g_object_unref(layout_one);
				}
				for(size_t index = 0; index < m.size(); index++) {
					ips_n.wrap = m[index].needsParenthesis(po, ips_n, m, index + 1, ips.division_depth > 0 || ips.power_depth > 0, ips.power_depth > 0);
					surface_args.push_back(draw_structure(m[index], po, caf, ips_n, &ctmp, scaledown, color));
					if(CALCULATOR->aborted()) {
						for(size_t i = 0; i < surface_args.size(); i++) {
							if(surface_args[i]) cairo_surface_destroy(surface_args[i]);
						}
						g_object_unref(layout_comma);
						return NULL;
					}
					wtmp = cairo_image_surface_get_width(surface_args[index]) / scalefactor;
					htmp = cairo_image_surface_get_height(surface_args[index]) / scalefactor;
					hpa.push_back(htmp);
					cpa.push_back(ctmp);				
					wpa.push_back(wtmp);
					if(index > 0) {
						w += comma_w;
						w += space_w;
					}				
					w += wtmp;
					if(ctmp > dh) {
						dh = ctmp;
					}
					if(htmp - ctmp > uh) {
						uh = htmp - ctmp;
					}				
				}
			
				if(dh > uh) uh = dh;
				h = uh + dh;
				central_point = dh;
				arc_h = dh * 2;
				arc_w = (int) ::sqrt((double) arc_h * 3);
				w += arc_w * 2;
				w += 1;

				surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
				cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
				cr = cairo_create(surface);

				w = 0;
				cairo_set_source_surface(cr, get_left_parenthesis(arc_w, arc_h, scaledown, color), w, uh - arc_h / 2 - arc_h % 2);
				cairo_paint(cr);
				w += arc_w;
				if(m.size() == 0) w += 2;
				for(size_t index = 0; index < surface_args.size(); index++) {
					if(!CALCULATOR->aborted()) {
						gdk_cairo_set_source_rgba(cr, color);
						if(index > 0) {
							cairo_move_to(cr, w, uh - comma_h / 2 - comma_h % 2);
							pango_cairo_show_layout(cr, layout_comma);
							w += comma_w;
							w += space_w;
						}
						cairo_set_source_surface(cr, surface_args[index], w, uh - (hpa[index] - cpa[index]));
						cairo_paint(cr);
						w += wpa[index];
					}
					cairo_surface_destroy(surface_args[index]);
				}
				cairo_set_source_surface(cr, get_right_parenthesis(arc_w, arc_h, scaledown, color), w, uh - arc_h / 2 - arc_h % 2);
				cairo_paint(cr);
				
				g_object_unref(layout_comma);

				break;
			}
			case STRUCT_UNIT: {

				string str, str2;
				TTBP(str);
				
				const ExpressionName *ename = &m.unit()->preferredDisplayName(po.abbreviate_names, po.use_unicode_signs, m.isPlural(), po.use_reference_names, po.can_display_unicode_string_function, po.can_display_unicode_string_arg);

				if(m.prefix()) {
					str += m.prefix()->name(po.abbreviate_names && ename->abbreviation && (ename->suffix || ename->name.find("_") == string::npos), po.use_unicode_signs, po.can_display_unicode_string_function, po.can_display_unicode_string_arg);
				}
				if(ename->suffix && ename->name.length() > 1) {
					size_t i = ename->name.rfind('_');
					bool b = i == string::npos || i == ename->name.length() - 1 || i == 0;
					size_t i2 = 1;
					if(b) {
						if(is_in(NUMBERS, ename->name[ename->name.length() - 1])) {
							while(ename->name.length() > i2 + 1 && is_in(NUMBERS, ename->name[ename->name.length() - 1 - i2])) {
								i2++;
							}
						}
						str += ename->name.substr(0, ename->name.length() - i2);
					} else {
						str += ename->name.substr(0, i);
					}
					if(b || i + 5 != ename->name.length() || ename->name.substr(ename->name.length() - 4, 4) != "unit") {
						TTBP_SMALL(str);
						str += "<sub>";
						if(b) str += ename->name.substr(ename->name.length() - i2, i2);
						else if(i + 5 < ename->name.length() && ename->name.substr(ename->name.length() - 4, 4) == "unit") {str += ename->name.substr(i + 1, ename->name.length() - (i + 1) - 4);}
						else str += ename->name.substr(i + 1, ename->name.length() - (i + 1));
						str += "</sub>";
						TTE(str);
					}
				} else {
					str += ename->name;
				}
				gsub("_", " ", str);

				TTE(str);
				PangoLayout *layout = gtk_widget_create_pango_layout(resultview, NULL);
				pango_layout_set_markup(layout, str.c_str(), -1);
				pango_layout_get_pixel_size(layout, &w, &h);
				central_point = h / 2;
				surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
				cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
				cr = cairo_create(surface);
				gdk_cairo_set_source_rgba(cr, color);
				cairo_move_to(cr, 0, 0);
				pango_cairo_show_layout(cr, layout);
				g_object_unref(layout);
				break;
			}
			case STRUCT_VARIABLE: {

				PangoLayout *layout = gtk_widget_create_pango_layout(resultview, NULL);
				string str;
				
				if(m.variable() != CALCULATOR->v_i) {
					str = "<i>";
				}
				TTBP(str);
				
				const ExpressionName *ename = &m.variable()->preferredDisplayName(po.abbreviate_names, po.use_unicode_signs, false, po.use_reference_names, po.can_display_unicode_string_function, po.can_display_unicode_string_arg);
				if(ename->suffix && ename->name.length() > 1) {
					size_t i = ename->name.rfind('_');
					bool b = i == string::npos || i == ename->name.length() - 1 || i == 0;
					size_t i2 = 1;
					if(b) {
						if(is_in(NUMBERS, ename->name[ename->name.length() - 1])) {
							while(ename->name.length() > i2 + 1 && is_in(NUMBERS, ename->name[ename->name.length() - 1 - i2])) {
								i2++;
							}
						}
						str += ename->name.substr(0, ename->name.length() - i2);
					} else {
						str += ename->name.substr(0, i);
					}
					if(!b || i + 9 != ename->name.length() || ename->name.substr(ename->name.length() - 8, 8) != "constant") {
						TTBP_SMALL(str);
						str += "<sub>";
						if(b) str += ename->name.substr(ename->name.length() - i2, i2);
						else if(i + 9 < ename->name.length() && ename->name.substr(ename->name.length() - 8, 8) == "constant") str += ename->name.substr(i + 1, ename->name.length() - (i + 1) - 8);
						else str += ename->name.substr(i + 1, ename->name.length() - (i + 1));
						str += "</sub>";
						TTE(str);
					}
				} else {
					str += ename->name;
				}
				gsub("_", " ", str);
				
				TTE(str);
				if(m.variable() != CALCULATOR->v_i) {
					str += "</i>";
				} 
				pango_layout_set_markup(layout, str.c_str(), -1);
				PangoRectangle rect;
				pango_layout_get_pixel_size(layout, &w, &h);
				pango_layout_get_pixel_extents(layout, &rect, NULL);
				w = rect.width + rect.x;
				w += 1;
				if(m.variable() == CALCULATOR->v_i) w += 1;
				central_point = h / 2;
				surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
				cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
				cr = cairo_create(surface);
				gdk_cairo_set_source_rgba(cr, color);
				cairo_move_to(cr, 1, 0);
				pango_cairo_show_layout(cr, layout);
				g_object_unref(layout);
				break;
			}
			case STRUCT_FUNCTION: {
			
				if(m.function() == CALCULATOR->f_uncertainty && m.size() == 3 && m[2].isZero()) {
					ips_n.depth++;
					gint unc_uh, unc_w, unc_dh, mid_w, mid_dh, mid_uh, dh = 0, uh = 0, w = 0, h = 0;
					cairo_surface_t *mid_surface = NULL, *unc_surface = NULL;
					ips_n.wrap = !m[0].isNumber();
					PrintOptions po2 = po;
					po2.show_ending_zeroes = false;
					po2.number_fraction_format = FRACTION_DECIMAL;
					mid_surface = draw_structure(m[0], po2, caf, ips_n, &mid_dh, scaledown, color);
					if(!mid_surface) {
						return NULL;
					}
					mid_w = cairo_image_surface_get_width(mid_surface) / scalefactor;
					h = cairo_image_surface_get_height(mid_surface) / scalefactor;
					mid_uh = h - mid_dh;
					ips_n.wrap = !m[1].isNumber();
					unc_surface = draw_structure(m[1], po2, caf, ips_n, &unc_dh, scaledown, color);
					unc_w = cairo_image_surface_get_width(unc_surface) / scalefactor;
					h = cairo_image_surface_get_height(unc_surface) / scalefactor;
					unc_uh = h - unc_dh;
					h = 0;
					gint pm_w, pm_h;
					PangoLayout *layout_pm = gtk_widget_create_pango_layout(resultview, NULL);
					PANGO_TTP(layout_pm, SIGN_PLUSMINUS);
					pango_layout_get_pixel_size(layout_pm, &pm_w, &pm_h);
					w = mid_w + unc_w + pm_w;
					dh = mid_dh; uh = mid_uh;
					if(unc_dh > dh) h = unc_dh;
					if(unc_uh > uh) uh = unc_uh;
					if(pm_h / 2 > dh) {
						dh = pm_h / 2;
					}
					if(pm_h / 2 + pm_h % 2 > uh) {
						uh = pm_h / 2 + pm_h % 2;
					}
					h = uh + dh;
					central_point = dh;
					surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
					cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
					cr = cairo_create(surface);
					gdk_cairo_set_source_rgba(cr, color);
					w = 0;
					cairo_set_source_surface(cr, mid_surface, w, uh - mid_uh);
					cairo_paint(cr);
					w += mid_w;
					gdk_cairo_set_source_rgba(cr, color);
					cairo_move_to(cr, w, uh - pm_h / 2 - pm_h % 2);
					pango_cairo_show_layout(cr, layout_pm);
					w += pm_w;
					cairo_set_source_surface(cr, unc_surface, w, uh - unc_uh);
					cairo_paint(cr);
					g_object_unref(layout_pm);
					cairo_surface_destroy(mid_surface);
					cairo_surface_destroy(unc_surface);
					break;
				} else if(SHOW_WITH_ROOT_SIGN(m)) {

					ips_n.depth++;
					gint arg_w, arg_h, root_w, root_h, sign_w, sign_h, h, w, ctmp;
					
					int i_root = 2;
					if(m.function() == CALCULATOR->f_root) i_root = m[1].number().intValue();
					else if(m.function() == CALCULATOR->f_cbrt) i_root = 3;
					string root_str;
					TT_XSMALL(root_str, i2s(i_root));
					PangoLayout *layout_root = gtk_widget_create_pango_layout(resultview, NULL);
					pango_layout_set_markup(layout_root, root_str.c_str(), -1);		
					pango_layout_get_pixel_size(layout_root, &root_w, &root_h);

					ips_n.wrap = false;
					cairo_surface_t *surface_arg = draw_structure(m[0], po, caf, ips_n, &ctmp, scaledown, color);
					if(!surface_arg) return NULL;

					arg_w = cairo_image_surface_get_width(surface_arg) / scalefactor;
					arg_h = cairo_image_surface_get_height(surface_arg) / scalefactor;
					
					double divider = 1.0;
					if(ips.power_depth >= 1) divider = 1.5;
					
					gint extra_space = 5;
					if(scaledown == 1) extra_space = 3;
					else if(scaledown > 1) extra_space = 1;
					
					central_point = ctmp + extra_space / divider;
					
					root_w = root_w / divider;
					root_h = root_h / divider;
					sign_w = root_w * 2.6;
					
					if(i_root == 2) {
						sign_h = arg_h + extra_space / divider;
					} else {
						sign_h = root_h * 2.0;
						if(sign_h < arg_h + extra_space / divider) sign_h = arg_h + extra_space / divider;
					}
					
					h = sign_h + extra_space * 2.0 / divider;
					w = arg_w + sign_w * 1.25;
					
					surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
					cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
					cr = cairo_create(surface);
					gdk_cairo_set_source_rgba(cr, color);

					cairo_move_to(cr, 0, h / 2.0 + h / 15.0);
					cairo_line_to(cr, sign_w / 6.0, h / 2.0);
					cairo_line_to(cr, sign_w / 2.2, h - extra_space / divider);
					cairo_line_to(cr, sign_w,  extra_space / divider);
					cairo_line_to(cr, w,  extra_space / divider);
					cairo_set_line_width(cr, 2 / divider);
					cairo_stroke(cr);
					
					if(i_root != 2) {
						cairo_move_to(cr, (sign_w - root_w) / 3.0, ((h / 2.0) - root_h) / 2.0);
						cairo_surface_set_device_scale(surface, scalefactor / divider, scalefactor / divider);
						pango_cairo_show_layout(cr, layout_root);
						cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
					}
					
					gdk_cairo_set_source_rgba(cr, color);
					cairo_move_to(cr, 0, 0);
					cairo_set_source_surface(cr, surface_arg, sign_w + 1, h - arg_h - extra_space / divider);
					cairo_paint(cr);
					
					cairo_surface_destroy(surface_arg);
					g_object_unref(layout_root);
					
					break;
					
				} else if(m.function() == CALCULATOR->f_abs && m.size() == 1) {
				
					ips_n.depth++;
					gint arg_w, arg_h, h, w, ctmp;
					
					ips_n.wrap = false;
					cairo_surface_t *surface_arg = draw_structure(m[0], po, caf, ips_n, &ctmp, scaledown, color);
					if(!surface_arg) return NULL;

					arg_w = cairo_image_surface_get_width(surface_arg) / scalefactor;
					arg_h = cairo_image_surface_get_height(surface_arg) / scalefactor;
					
					double divider = 1.0;
					if(ips.power_depth >= 1) divider = 1.5;
					
					gint extra_space = 5;
					if(scaledown == 1) extra_space = 3;
					else if(scaledown > 1) extra_space = 1;
					
					central_point = ctmp + extra_space / divider;
					h = arg_h + extra_space * 2 / divider;
					w = arg_w + extra_space * 2 + extra_space * 2 / divider;
					
					surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
					cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
					cr = cairo_create(surface);
					gdk_cairo_set_source_rgba(cr, color);

					cairo_move_to(cr, (extra_space / divider), extra_space / divider);
					cairo_line_to(cr, (extra_space / divider), h - extra_space / divider);
					cairo_move_to(cr, w - (extra_space / divider), extra_space / divider);
					cairo_line_to(cr, w - (extra_space / divider), h - extra_space / divider);
					cairo_set_line_width(cr, 2 / divider);
					cairo_stroke(cr);
					
					gdk_cairo_set_source_rgba(cr, color);
					cairo_move_to(cr, 0, 0);
					cairo_set_source_surface(cr, surface_arg, (w - arg_w) / 2.0, (h - arg_h) / 2.0);
					cairo_paint(cr);
					
					cairo_surface_destroy(surface_arg);
					
					break;
				} else if(m.function() == CALCULATOR->f_diff && (m.size() == 3 || (m.size() == 4 && m[3].isUndefined())) && (m[1].isVariable() || m[1].isSymbolic()) && m[2].isInteger()) {
					
					MathStructure mdx("d");
					if(!m[2].isOne()) mdx ^= m[2];
					string s = "d";
					if(m[1].isSymbolic()) s += m[1].symbol();
					else s += m[1].variable()->preferredDisplayName(po.abbreviate_names, po.use_unicode_signs, false, po.use_reference_names, po.can_display_unicode_string_function, po.can_display_unicode_string_arg).name;
					mdx.transform(STRUCT_DIVISION, s);
					if(!m[2].isOne()) mdx[1] ^= m[2];
					
					ips_n.depth++;
				
					gint hpt1, hpt2;
					gint wpt1, wpt2;
					gint cpt1, cpt2;
					gint w = 0, h = 0, dh = 0, uh = 0;
				
					CALCULATE_SPACE_W

					ips_n.wrap = false;
					cairo_surface_t *surface_term1 = draw_structure(mdx, po, caf, ips_n, &cpt1, scaledown, color);
					wpt1 = cairo_image_surface_get_width(surface_term1) / scalefactor;
					hpt1 = cairo_image_surface_get_height(surface_term1) / scalefactor;
					ips_n.wrap = true;
					cairo_surface_t *surface_term2 = draw_structure(m[0], po, caf, ips_n, &cpt2, scaledown, color);
					wpt2 = cairo_image_surface_get_width(surface_term2) / scalefactor;
					hpt2 = cairo_image_surface_get_height(surface_term2) / scalefactor;
					w = wpt1 + wpt2 + space_w;
					if(hpt1 - cpt1 > hpt2 - cpt2) uh = hpt1 - cpt1;
					else uh = hpt2 - cpt2;
					if(cpt1 > cpt2) dh = cpt1;
					else dh = cpt2;
					central_point = dh;
					h = dh + uh;
					surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
					cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
					cr = cairo_create(surface);
					gdk_cairo_set_source_rgba(cr, color);
					cairo_set_source_surface(cr, surface_term1, 0, uh - (hpt1 - cpt1));
					cairo_paint(cr);
					gdk_cairo_set_source_rgba(cr, color);
					cairo_set_source_surface(cr, surface_term2, wpt1 + space_w, uh - (hpt2 - cpt2));
					cairo_paint(cr);
					cairo_surface_destroy(surface_term1);
					cairo_surface_destroy(surface_term2);

					break;
				}

				ips_n.depth++;
				
				gint comma_w, comma_h, function_w, function_h, uh, dh, h, w, ctmp, htmp, wtmp, arc_w, arc_h;
				vector<cairo_surface_t*> surface_args;
				vector<gint> hpa;
				vector<gint> cpa;			
				vector<gint> wpa;
				
				CALCULATE_SPACE_W
				PangoLayout *layout_comma = gtk_widget_create_pango_layout(resultview, NULL);
				string str;
				TTP(str, po.comma())
				pango_layout_set_markup(layout_comma, str.c_str(), -1);		
				pango_layout_get_pixel_size(layout_comma, &comma_w, &comma_h);
				PangoLayout *layout_function = gtk_widget_create_pango_layout(resultview, NULL);
			
				str = "";
				TTBP(str);
				
				size_t argcount = m.size();
				
				if(m.function() == CALCULATOR->f_signum && argcount > 1) argcount = 1;
				
				if(m.function()->maxargs() > 0 && m.function()->minargs() < m.function()->maxargs() && m.size() > (size_t) m.function()->minargs()) {
					while(true) {
						string defstr = m.function()->getDefaultValue(argcount);
						Argument *arg = m.function()->getArgumentDefinition(argcount);
						remove_blank_ends(defstr);
						if(defstr.empty()) break;
						if(m[argcount - 1].isUndefined() && defstr == "undefined") {
							argcount--;
						} else if(m[argcount - 1].isVariable() && (!arg || arg->type() != ARGUMENT_TYPE_TEXT) && defstr == m[argcount - 1].variable()->referenceName()) {
							argcount--;
						} else if(m[argcount - 1].isInteger() && (!arg || arg->type() != ARGUMENT_TYPE_TEXT) && defstr.find_first_not_of(NUMBERS) == string::npos && m[argcount - 1].number() == s2i(defstr)) {
							argcount--;
						} else if(m[argcount - 1].isSymbolic() && arg && arg->type() == ARGUMENT_TYPE_TEXT && m[argcount - 1] == defstr) {
							argcount--;
						} else {
							break;
						}
						if(argcount == 0 || argcount == (size_t) m.function()->minargs()) break;
					}
				}
							
				const ExpressionName *ename = &m.function()->preferredDisplayName(po.abbreviate_names, po.use_unicode_signs, false, po.use_reference_names, po.can_display_unicode_string_function, po.can_display_unicode_string_arg);
				if(ename->suffix && ename->name.length() > 1) {
					
					size_t i = ename->name.rfind('_');
					bool b = i == string::npos || i == ename->name.length() - 1 || i == 0;
					size_t i2 = 1;
					if(b) {
						if(is_in(NUMBERS, ename->name[ename->name.length() - 1])) {
							while(ename->name.length() > i2 + 1 && is_in(NUMBERS, ename->name[ename->name.length() - 1 - i2])) {
								i2++;
							}
						}
						str += ename->name.substr(0, ename->name.length() - i2);
					} else {
						str += ename->name.substr(0, i);
					}
					TTBP_SMALL(str);
					str += "<sub>";
					if(b) str += ename->name.substr(ename->name.length() - i2, i2);
					else str += ename->name.substr(i + 1, ename->name.length() - (i + 1));
					str += "</sub>";
					TTE(str);
				} else {
					str += ename->name;
					if((m.function() == CALCULATOR->f_lambert_w || m.function() == CALCULATOR->f_logn) && m.size() == 2 && ((m[1].size() == 0 && (!m[1].isNumber() || (m[1].number().isInteger() && m[1].number() < 100 && m[1].number() > -100))) || (m[1].isNegate() && m[1][0].size() == 0 && (!m[1][0].isNumber() || (m[1][0].number().isInteger() && m[1][0].number() < 100 && m[1][0].number() > -100))))) {
						argcount = 1;
						TTBP_SMALL(str);
						str += "<sub>";
						str += m[1].print(po);
						str += "</sub>";
						TTE(str);
					}
				}
				gsub("_", " ", str);
				
				TTE(str);
				
				pango_layout_set_markup(layout_function, str.c_str(), -1);			
				pango_layout_get_pixel_size(layout_function, &function_w, &function_h);
				w = function_w + 1;
				uh = function_h / 2 + function_h % 2;
				dh = function_h / 2;

				for(size_t index = 0; index < argcount; index++) {
							
					ips_n.wrap = m[index].needsParenthesis(po, ips_n, m, index + 1, ips.division_depth > 0 || ips.power_depth > 0, ips.power_depth > 0);
					if(m.function() == CALCULATOR->f_interval) {
						PrintOptions po2 = po;
						po2.show_ending_zeroes = false;
						if(m[index].isNumber()) {
							if(index == 0) po2.interval_display = INTERVAL_DISPLAY_LOWER;
							else if(index == 1) po2.interval_display = INTERVAL_DISPLAY_UPPER;
						}
						surface_args.push_back(draw_structure(m[index], po2, caf, ips_n, &ctmp, scaledown, color));
					} else {
						surface_args.push_back(draw_structure(m[index], po, caf, ips_n, &ctmp, scaledown, color));
					}
					if(CALCULATOR->aborted()) {
						for(size_t i = 0; i < surface_args.size(); i++) {
							if(surface_args[i]) cairo_surface_destroy(surface_args[i]);
						}
						g_object_unref(layout_function);
						g_object_unref(layout_comma);
						return NULL;
					}
					wtmp = cairo_image_surface_get_width(surface_args[index]) / scalefactor;
					htmp = cairo_image_surface_get_height(surface_args[index]) / scalefactor;
					hpa.push_back(htmp);
					cpa.push_back(ctmp);				
					wpa.push_back(wtmp);
					if(index > 0) {
						w += comma_w;
						w += space_w;
					}				
					w += wtmp;
					if(ctmp > dh) {
						dh = ctmp;
					}
					if(htmp - ctmp > uh) {
						uh = htmp - ctmp;
					}				
				}
				
				if(dh > uh) uh = dh;
				h = uh + dh;
				central_point = dh;
				arc_h = dh * 2;
				arc_w = (int) ::sqrt((double) arc_h * 3);
				w += arc_w * 2;
				w += 1;

				surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
				cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
				cr = cairo_create(surface);
				
				w = 0;
				gdk_cairo_set_source_rgba(cr, color);
				cairo_move_to(cr, w, uh - function_h / 2 - function_h % 2);
				pango_cairo_show_layout(cr, layout_function);
				w += function_w;
				cairo_set_source_surface(cr, get_left_parenthesis(arc_w, arc_h, scaledown, color), w, uh - arc_h / 2 - arc_h % 2);
				cairo_paint(cr);
				w += arc_w;
				for(size_t index = 0; index < surface_args.size(); index++) {
					if(!CALCULATOR->aborted()) {
						gdk_cairo_set_source_rgba(cr, color);
						if(index > 0) {
							cairo_move_to(cr, w, uh - comma_h / 2 - comma_h % 2);
							pango_cairo_show_layout(cr, layout_comma);
							w += comma_w;
							w += space_w;
						}
						cairo_set_source_surface(cr, surface_args[index], w, uh - (hpa[index] - cpa[index]));
						cairo_paint(cr);
						w += wpa[index];
					}
					cairo_surface_destroy(surface_args[index]);
				}
				cairo_set_source_surface(cr, get_right_parenthesis(arc_w, arc_h, scaledown, color), w, uh - arc_h / 2 - arc_h % 2);
				cairo_paint(cr);
							
				g_object_unref(layout_comma);
				g_object_unref(layout_function);

				break;
			}
			case STRUCT_UNDEFINED: {
				PangoLayout *layout = gtk_widget_create_pango_layout(resultview, NULL);
				string str;
				TTP(str, _("undefined"));
				pango_layout_set_markup(layout, str.c_str(), -1);
				PangoRectangle rect;
				pango_layout_get_pixel_size(layout, &w, &h);
				pango_layout_get_pixel_extents(layout, &rect, NULL);
				w = rect.width + rect.x;
				w += 1;
				central_point = h / 2;
				surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
				cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
				cr = cairo_create(surface);
				gdk_cairo_set_source_rgba(cr, color);
				cairo_move_to(cr, 1, 0);
				pango_cairo_show_layout(cr, layout);
				g_object_unref(layout);
				break;
			}
			default: {}
		}
	}
	if(ips.wrap && surface) {
		gint w, h, base_h, base_w;
		base_w = cairo_image_surface_get_width(surface) / scalefactor;
		base_h = cairo_image_surface_get_height(surface) / scalefactor;
		h = base_h;
		w = base_w;
		gint arc_base_h = central_point * 2;
		if(h < arc_base_h) h = arc_base_h;
		gint arc_base_w = (int) ::sqrt((double) arc_base_h * 3);
		//base_h += 4;
		//central_point += 2;
		w += arc_base_w * 2;
		cairo_surface_t *surface_old = surface;
		cairo_destroy(cr);
		surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
		cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
		cr = cairo_create(surface);
		gdk_cairo_set_source_rgba(cr, color);
		w = 0;
		cairo_set_source_surface(cr, get_left_parenthesis(arc_base_w, arc_base_h, scaledown, color), w, h - arc_base_h);
		cairo_paint(cr);
		w += arc_base_w;
		cairo_set_source_surface(cr, surface_old, w, (h - base_h) / 2);
		cairo_paint(cr);
		cairo_surface_destroy(surface_old);
		w += base_w;
		cairo_set_source_surface(cr, get_right_parenthesis(arc_base_w, arc_base_h, scaledown, color), w, h - arc_base_h);
		cairo_paint(cr);
	}
	if(ips.depth == 0 && !(m.isComparison() && (!((po.is_approximate && *po.is_approximate) || m.isApproximate()) || (m.comparisonType() == COMPARISON_EQUALS && po.use_unicode_signs && (!po.can_display_unicode_string_function || (*po.can_display_unicode_string_function) (SIGN_ALMOST_EQUAL, po.can_display_unicode_string_arg))))) && surface) {
		gint w, h, wle, hle, w_new, h_new;
		w = cairo_image_surface_get_width(surface) / scalefactor;
		h = cairo_image_surface_get_height(surface) / scalefactor;
		cairo_surface_t *surface_old = surface;
		PangoLayout *layout_equals = gtk_widget_create_pango_layout(resultview, NULL);
		if((po.is_approximate && *po.is_approximate) || m.isApproximate()) {
			if(po.use_unicode_signs && (!po.can_display_unicode_string_function || (*po.can_display_unicode_string_function) (SIGN_ALMOST_EQUAL, po.can_display_unicode_string_arg))) {
				PANGO_TT(layout_equals, SIGN_ALMOST_EQUAL);
			} else {
				
				string str;
				TT(str, _("approx."));
				pango_layout_set_markup(layout_equals, str.c_str(), -1);
			}
		} else {
			PANGO_TT(layout_equals, "=");
		}
		CALCULATE_SPACE_W
		pango_layout_get_pixel_size(layout_equals, &wle, &hle);
		w_new = w + wle + 1 + space_w;
		h_new = h;
		surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w_new * scalefactor, h_new * scalefactor);
		cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
		cr = cairo_create(surface);
		gdk_cairo_set_source_rgba(cr, color);
		cairo_move_to(cr, 1, h - central_point - hle / 2 - hle % 2);
		pango_cairo_show_layout(cr, layout_equals);
		cairo_set_source_surface(cr, surface_old, wle + 1 + space_w, 0);
		cairo_paint(cr);
		cairo_surface_destroy(surface_old);
		g_object_unref(layout_equals);
	}
	if(!surface) {
		surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1 * scalefactor, 1 * scalefactor);
		cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
		cr = cairo_create(surface);
	}
	if(cr) cairo_destroy(cr);
	if(point_central) *point_central = central_point;
	return surface;
}

void clearresult() {
	showing_first_time_message = false;
	if(displayed_mstruct) {
		displayed_mstruct->unref();
		displayed_mstruct = NULL;
		if(!surface_result) gtk_widget_queue_draw(resultview);
	}
	result_autocalculated = false;
	date_map.clear();
	number_map.clear();
	number_base_map.clear();
	number_exp_map.clear();
	number_exp_minus_map.clear();
	number_approx_map.clear();
	if(gtk_revealer_get_child_revealed(GTK_REVEALER(gtk_builder_get_object(main_builder, "message_revealer")))) {
		gtk_info_bar_response(GTK_INFO_BAR(gtk_builder_get_object(main_builder, "message_bar")), GTK_RESPONSE_CLOSE);
	}
	update_expression_icons();
	if(surface_result) {
		cairo_surface_destroy(surface_result);
		surface_result = NULL;
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "menu_item_save_image")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_save_image")), FALSE);
		gtk_widget_queue_draw(resultview);
	}
	result_bin = ""; result_oct = ""; result_dec = ""; result_hex = "";
	gtk_label_set_text(GTK_LABEL(result_bases), "");
	gtk_widget_set_tooltip_markup(result_bases, "");
	gtk_widget_set_tooltip_text(resultview, "");
}

void on_abort_display(GtkDialog*, gint, gpointer) {
	CALCULATOR->abort();
}

void replace_interval_with_function(MathStructure &m) {
	if(m.isNumber() && m.number().isInterval()) {
		m.transform(STRUCT_FUNCTION);
		m.setFunction(CALCULATOR->f_interval);
		m.addChild(m[0]);
	} else {
		for(size_t i = 0; i < m.size(); i++) replace_interval_with_function(m[i]);
	}
}

void ViewThread::run() {

	while(true) {
		int scale_tmp = 0;
		if(!read(&scale_tmp)) break;
		void *x = NULL;
		if(!read(&x) || !x) break;
		MathStructure m(*((MathStructure*) x));
		bool b_stack = false;
		if(!read(&b_stack)) break;
		if(!read(&x)) break;
		MathStructure *mm = (MathStructure*) x;
		if(!read(&x)) break;
		CALCULATOR->startControl();
		printops.can_display_unicode_string_arg = (void*) historyview;
		bool b_puup = printops.use_unit_prefixes;
		if(x) {
			PrintOptions po;
			if(!read(&po.is_approximate)) break;
			void *x_to = NULL;
			if(!read(&x_to)) break;
			po.show_ending_zeroes = evalops.parse_options.read_precision != DONT_READ_PRECISION && CALCULATOR->usesIntervalArithmetic() && evalops.parse_options.base > BASE_CUSTOM;
			po.lower_case_e = printops.lower_case_e;
			po.lower_case_numbers = printops.lower_case_numbers;
			po.base_display = printops.base_display;
			po.twos_complement = printops.twos_complement;
			po.hexadecimal_twos_complement = printops.hexadecimal_twos_complement;
			po.base = evalops.parse_options.base;
			po.preserve_format = (x_to != NULL);
			Number nr_base;
			if(po.base == BASE_CUSTOM && (CALCULATOR->usesIntervalArithmetic() || CALCULATOR->customInputBase().isRational()) && (CALCULATOR->customInputBase().isInteger() || !CALCULATOR->customInputBase().isNegative()) && (CALCULATOR->customInputBase() > 1 || CALCULATOR->customInputBase() < -1)) {
				nr_base = CALCULATOR->customOutputBase();
				CALCULATOR->setCustomOutputBase(CALCULATOR->customInputBase());
			} else if(po.base == BASE_CUSTOM || (po.base < BASE_CUSTOM && !CALCULATOR->usesIntervalArithmetic() && po.base != BASE_UNICODE && po.base != BASE_BIJECTIVE_26)) {
				po.base = 10;
				po.min_exp = 6;
				po.use_max_decimals = true;
				po.max_decimals = 5;
				po.preserve_format = false;
			}
			po.abbreviate_names = false;
			po.use_unicode_signs = printops.use_unicode_signs;
			po.digit_grouping = printops.digit_grouping;
			po.multiplication_sign = printops.multiplication_sign;
			po.division_sign = printops.division_sign;
			po.short_multiplication = false;
			po.excessive_parenthesis = true;
			po.improve_division_multipliers = false;
			po.can_display_unicode_string_function = &can_display_unicode_string_function;
			po.can_display_unicode_string_arg = (void*) statuslabel_l;
			po.spell_out_logical_operators = printops.spell_out_logical_operators;
			po.restrict_to_parent_precision = false;
			po.interval_display = INTERVAL_DISPLAY_PLUSMINUS;
			MathStructure mp(*((MathStructure*) x));
			mp.format(po);
			parsed_text = mp.print(po);
			if(x_to && !((MathStructure*) x_to)->isUndefined()) {
				mp.set(*((MathStructure*) x_to));
				parsed_text += CALCULATOR->localToString();
				mp.format(po);
				parsed_text += mp.print(po); 
				printops.use_unit_prefixes = true;
			}
			if(po.base == BASE_CUSTOM) CALCULATOR->setCustomOutputBase(nr_base);
		}
		printops.allow_non_usable = false;

		if(mm && m.isMatrix()) {
			mm->set(m);
			MathStructure mm2(m);
			string mstr;
			int c = mm->columns(), r = mm->rows();
			for(int index_r = 0; index_r < r; index_r++) {
				for(int index_c = 0; index_c < c; index_c++) {
					mm->getElement(index_r + 1, index_c + 1)->setAborted();
				}
			}
			for(int index_r = 0; index_r < r; index_r++) {
				for(int index_c = 0; index_c < c; index_c++) {
					mm2.getElement(index_r + 1, index_c + 1)->format(printops);
					mstr = mm2.getElement(index_r + 1, index_c + 1)->print(printops);
					mm->getElement(index_r + 1, index_c + 1)->set(mstr);
				}
			}
		}

		m.removeDefaultAngleUnit(evalops);
		m.format(printops);
		gint64 time1 = g_get_monotonic_time();
		result_text = m.print(printops);
		if(complex_angle_form) replace_result_cis(result_text);
		result_text_approximate = *printops.is_approximate;
		
		if(!b_stack) {
			result_bin = ""; result_oct = "", result_dec = "", result_hex = "";
			if(max_bases.isZero()) {max_bases = 2; max_bases ^= 64; min_bases = -max_bases;}
			if(!CALCULATOR->aborted() && ((m.isNumber() && m.number() < max_bases && m.number() > min_bases) || (m.isNegate() && m[0].isNumber() && m[0].number() < max_bases && m[0].number() > min_bases))) {
				Number nr;
				if(m.isNumber()) {
					nr = m.number();
				} else {
					nr = m[0].number();
					nr.negate();
				}
				nr.round(printops.round_halfway_to_even);
				PrintOptions po = printops;
				po.show_ending_zeroes = false;
				po.min_exp = 0;
				if(printops.base != 2) {
					po.base = 2;
					result_bin = nr.print(po);
				}
				if(printops.base != 8) {
					po.base = 8;
					result_oct = nr.print(po);
					size_t i = result_oct.find_first_of(NUMBERS);
					if(i != string::npos && result_oct.length() > i + 1 && result_oct[i] == '0' && is_in(NUMBERS, result_oct[i + 1])) result_oct.erase(i, 1);
				}
				if(printops.base != 10) {
					po.base = 10;
					result_dec = nr.print(po);
				}
				if(printops.base != 16) {
					po.base = 16;
					result_hex = nr.print(po);
					gsub("0x", "", result_hex);
				}
			}
		}

		if(!b_stack && g_get_monotonic_time() - time1 < 200000) {
			PrintOptions printops_long = printops;
			printops_long.abbreviate_names = false; 
			printops_long.short_multiplication = false;
			printops_long.excessive_parenthesis = true;
			printops_long.is_approximate = NULL;
			result_text_long = m.print(printops_long);
			if(complex_angle_form) replace_result_cis(result_text_long);
		} else if(!b_stack) {
			result_text_long = "";
		}
		printops.can_display_unicode_string_arg = NULL;
		
		result_too_long = false;
		if(!b_stack && result_text.length() > 900) {
			PangoLayout *layout = gtk_widget_create_pango_layout(resultview, NULL);
			result_too_long = true;
			pango_layout_set_markup(layout, _("result is too long\nsee history"), -1);
			gint w = 0, h = 0;
			pango_layout_get_pixel_size(layout, &w, &h);
			gint scalefactor = gtk_widget_get_scale_factor(expressiontext);
			tmp_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
			cairo_surface_set_device_scale(tmp_surface, scalefactor, scalefactor);
			cairo_t *cr = cairo_create(tmp_surface);
			GdkRGBA rgba;
			gtk_style_context_get_color(gtk_widget_get_style_context(resultview), gtk_widget_get_state_flags(resultview), &rgba);
			gdk_cairo_set_source_rgba(cr, &rgba);
			pango_cairo_show_layout(cr, layout);
			cairo_destroy(cr);
			g_object_unref(layout);
			*printops.is_approximate = false;
			if(displayed_mstruct) {
				displayed_mstruct->unref();
				displayed_mstruct = NULL;
			}
		} else if(!b_stack && m.isAborted()) {
			PangoLayout *layout = gtk_widget_create_pango_layout(resultview, NULL);
			pango_layout_set_markup(layout, _("calculation was aborted"), -1);
			gint w = 0, h = 0;
			pango_layout_get_pixel_size(layout, &w, &h);
			gint scalefactor = gtk_widget_get_scale_factor(expressiontext);
			tmp_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
			cairo_t *cr = cairo_create(tmp_surface);
			GdkRGBA rgba;
			gtk_style_context_get_color(gtk_widget_get_style_context(resultview), gtk_widget_get_state_flags(resultview), &rgba);
			gdk_cairo_set_source_rgba(cr, &rgba);
			pango_cairo_show_layout(cr, layout);
			cairo_destroy(cr);
			g_object_unref(layout);
			*printops.is_approximate = false;
			if(displayed_mstruct) displayed_mstruct->unref();
			displayed_mstruct = new MathStructure(m);
			displayed_printops = printops;
			displayed_caf = complex_angle_form;
		} else if(!b_stack) {
			if(!CALCULATOR->aborted()) {
				printops.allow_non_usable = true;
				printops.can_display_unicode_string_arg = (void*) resultview;

				MathStructure *displayed_mstruct_pre = new MathStructure(m);
				if(printops.interval_display == INTERVAL_DISPLAY_INTERVAL) replace_interval_with_function(*displayed_mstruct_pre);
				tmp_surface = draw_structure(*displayed_mstruct_pre, printops, complex_angle_form, top_ips, NULL, scale_tmp);
				if(displayed_mstruct) displayed_mstruct->unref();
				displayed_mstruct = displayed_mstruct_pre;
				if(tmp_surface && CALCULATOR->aborted()) {
					cairo_surface_destroy(tmp_surface);
					tmp_surface = NULL;
				}
			
				printops.can_display_unicode_string_arg = NULL;
				printops.allow_non_usable = false;
			}
			if(!tmp_surface && displayed_mstruct) {
				displayed_mstruct->unref();
				displayed_mstruct = NULL;
			} else {
				displayed_printops = printops;
				displayed_caf = complex_angle_form;
			}
		}
		result_autocalculated = false;
		printops.use_unit_prefixes = b_puup;
		b_busy = false;
		CALCULATOR->stopControl();
	}
}

gboolean on_event(GtkWidget*, GdkEvent *e, gpointer) {
	if(e->type == GDK_EXPOSE || e->type == GDK_PROPERTY_NOTIFY || e->type == GDK_CONFIGURE || e->type == GDK_FOCUS_CHANGE || e->type == GDK_VISIBILITY_NOTIFY) {
		return FALSE;
	}
	return TRUE;
}

void reload_history(gint from_index) {
	if(from_index < 0) gtk_list_store_clear(historystore);
	string history_str;
	GtkTreeIter history_iter;
	size_t i = inhistory.size();
	gint pos = 0;
	while(i > 0 && (from_index < 0 || (i >= (size_t) from_index))) {
		i--;
		switch(inhistory_type[i]) {
			case QALCULATE_HISTORY_RESULT_APPROXIMATE: {}
			case QALCULATE_HISTORY_RESULT: {
				history_str = "";
				size_t trans_l = 0;
				if(i + 1 < inhistory.size()  && inhistory_type[i + 1] == QALCULATE_HISTORY_TRANSFORMATION) {
					history_str = inhistory[i + 1];
					history_str += ":  ";
					trans_l = history_str.length();
				}
				if(inhistory_type[i] == QALCULATE_HISTORY_RESULT_APPROXIMATE) {
					if(printops.use_unicode_signs && can_display_unicode_string_function(SIGN_ALMOST_EQUAL, (void*) historyview)) {
						history_str += SIGN_ALMOST_EQUAL;
					} else {
						history_str += "= ";
						history_str += _("approx.");
					}
				} else {
					history_str += "=";
				}
				history_str += " ";
				size_t history_expr_i = history_str.length();
				history_str += inhistory[i];
				add_line_breaks(history_str, 2, history_expr_i);
				fix_history_string2(history_str);
				improve_result_text(history_str);
				if(trans_l > 0) {
					trans_l = history_str.find(":  ");
					if(trans_l != string::npos) {
						trans_l += 3;
						history_str.insert(trans_l, "</span>");
						history_str.insert(0, "<span font-style=\"italic\">");
					}
				}
				gtk_list_store_insert_with_values(historystore, &history_iter, from_index < 0 ? -1 : pos, 0, history_str.c_str(), 1, i, 3, inhistory_value[i], 4, 0, 5, history_scroll_width, 6, 1.0, 7, PANGO_ALIGN_RIGHT, -1);
				pos++;
				break;
			}
			case QALCULATE_HISTORY_PARSE_APPROXIMATE: {}
			case QALCULATE_HISTORY_PARSE: {
				if(i + 1 < inhistory.size() && (inhistory_type[i + 1] == QALCULATE_HISTORY_EXPRESSION || inhistory_type[i + 1] == QALCULATE_HISTORY_RPN_OPERATION || inhistory_type[i + 1] == QALCULATE_HISTORY_REGISTER_MOVED)) {
					if(i + 2 >= inhistory.size() || inhistory_type[i + 2] != QALCULATE_HISTORY_BOOKMARK) {
						if(i < inhistory.size() - 2) {gtk_list_store_insert_with_values(historystore, &history_iter, from_index < 0 ? -1 : pos, 1, -1, 5, 6, 6, 0.0, 7, PANGO_ALIGN_LEFT, -1); pos++;}
					}
					string expr_str;
					if(inhistory_type[i + 1] == QALCULATE_HISTORY_RPN_OPERATION) expr_str = ("RPN Operation");
					else if(inhistory_type[i + 1] == QALCULATE_HISTORY_REGISTER_MOVED) expr_str = ("RPN Register Moved");
					else expr_str = inhistory[i + 1];
					history_str = fix_history_string(expr_str);
					history_str += "<span font-style=\"italic\" foreground=\"";
					history_str += history_parse_color;
					history_str += "\">  ";
					string str2;
					if(inhistory_type[i] == QALCULATE_HISTORY_PARSE) {
						str2 = "=";
					} else {
						if(printops.use_unicode_signs && can_display_unicode_string_function(SIGN_ALMOST_EQUAL, (void*) historyview)) {
							str2 = SIGN_ALMOST_EQUAL;
						} else {
							str2 = _("approx.");
						}
					}
					history_str += str2;
					history_str += " ";
					history_str += fix_history_string(inhistory[i]);
					history_str += "</span>";
					PangoLayout *layout = gtk_widget_create_pango_layout(historyview, "");
					pango_layout_set_markup(layout, history_str.c_str(), -1);
					gint w = 0;
					pango_layout_get_pixel_size(layout, &w, NULL);
					if(w > history_width_e) {
						history_str = inhistory[i + 1];
						add_line_breaks(history_str, 1, 0);
						fix_history_string2(history_str);
						str2 += " ";
						size_t history_expr_i = str2.length();
						str2 += inhistory[i];
						add_line_breaks(str2, 3, history_expr_i);
						fix_history_string2(str2);
						history_str += '\n';
						history_str += "<span font-style=\"italic\" foreground=\"";
						history_str += history_parse_color;
						history_str += "\">";
						history_str += str2;
						history_str += "</span>";
					}
					if(inhistory_protected[i + 1] || (i + 2 < inhistory.size() && inhistory_type[i + 2] == QALCULATE_HISTORY_BOOKMARK)) {
						if(can_display_unicode_string_function_exact("🔒", historyview)) history_str += "<span size=\"small\"><sup> 🔒</sup></span>";
						else history_str += "<span size=\"x-small\"><sup> P</sup></span>";
					}
					gtk_list_store_insert_with_values(historystore, &history_iter, from_index < 0 ? -1 : pos, 0, history_str.c_str(), 1, i, 2, inhistory_value[i] > 0 ? i2s(inhistory_value[i]).c_str() : "   ", 3, inhistory_value[i], 4, EXPRESSION_YPAD, 5, 6, 6, 0.0, 7, PANGO_ALIGN_LEFT, -1);
					pos++;
					g_object_unref(layout);
				}
				break;
			}
			case QALCULATE_HISTORY_ERROR: {}
			case QALCULATE_HISTORY_WARNING: {
				string str = "- ";
				str += inhistory[i];
				add_line_breaks(str, false, 2);
				fix_history_string2(str);
				history_str = "<span foreground=\"";
				if(inhistory_type[i] == QALCULATE_HISTORY_WARNING) history_str += history_warning_color;
				else history_str += history_error_color;
				history_str += "\">";
				history_str += str;
				history_str += "</span>";
				gtk_list_store_insert_with_values(historystore, &history_iter, from_index < 0 ? -1 : pos, 0, history_str.c_str(), 1, i, 3, inhistory_value[i], 4, 0, 5, 6, 6, 0.0, 7, PANGO_ALIGN_LEFT, -1);
				pos++;
				break;
			}
			case QALCULATE_HISTORY_BOOKMARK: {
				if(i > 0 && (inhistory_type[i - 1] == QALCULATE_HISTORY_EXPRESSION || inhistory_type[i - 1] == QALCULATE_HISTORY_RPN_OPERATION || inhistory_type[i - 1] == QALCULATE_HISTORY_REGISTER_MOVED)) {
					if(i < inhistory.size() - 1) {gtk_list_store_insert_with_values(historystore, &history_iter, from_index < 0 ? -1 : pos, 1, -1, 5, 6, 6, 0.0, 7, PANGO_ALIGN_LEFT, -1); pos++;}
				}
				string str = inhistory[i];
				add_line_breaks(str, false);
				fix_history_string2(str);
				history_str = "<span foreground=\"";
				history_str += history_bookmark_color;
				history_str += "\">";
				history_str += str;
				history_str += ":";
				history_str += "</span>";
				gtk_list_store_insert_with_values(historystore, &history_iter, from_index < 0 ? -1 : pos, 0, history_str.c_str(), 1, i, 3, inhistory_value[i], 4, 0, 5, 6, 6, 0.0, 7, PANGO_ALIGN_LEFT, -1);
				pos++;
				break;
			}
			default: {}
		}
	}
	if(inhistory.size() != 0) {gtk_list_store_insert_with_values(historystore, &history_iter, from_index < 0 ? -1 : pos, 1, -1, 2, "   ", 5, 6, 6, 0.0, 7, PANGO_ALIGN_LEFT, -1); pos++;}
}

void add_line_breaks(string &str, int expr, size_t first_i) {
	PangoLayout *layout = gtk_widget_create_pango_layout(historyview, "");
	PangoFontDescription *font_desc = NULL;
	if(expr == 3) {
		gtk_style_context_get(gtk_widget_get_style_context(historyview), GTK_STATE_FLAG_NORMAL, GTK_STYLE_PROPERTY_FONT, &font_desc, NULL);
		pango_font_description_set_style(font_desc, PANGO_STYLE_ITALIC);
		pango_layout_set_font_description(layout, font_desc);
	}
	int r = 1;
	size_t i_row = 0;
	size_t indent = 0;
	size_t lb_point = string::npos;
	size_t c = 0;
	int b_or = 0;
	int history_width = (expr == 2 ? history_width_a : history_width_e);
	if(expr > 1 && str.find("||") != string::npos) b_or = 2;
	else if(expr > 1 && str.find(_("or")) != string::npos) b_or = 1;
	for(size_t i = first_i; i < str.length(); i++) {
		if(r != 1 && i - i_row <= indent) {
			if(str[i] == ' ') {
				str.erase(i, 1);
				if(i >= str.length()) i = str.length() - 1;
			} else if(str[i] <= 0 && (unsigned char) str[i] >= 0xC0) {
				size_t l = 1;
				while(i + l < str.length() && str[i + l] <= 0 && (unsigned char) str[i + l] < 0xC0) l++;
				if(str.substr(i, l) == " ") {
					str.erase(i, l);
					if(i >= str.length()) i = str.length() - 1;
				}
			}
		}
		if(str[i] > 0 || (unsigned char) str[i] >= 0xC0 || i == str.length() - 1) {
			if(str[i] == '\n') {
				r++;
				i_row = i + 1;
				lb_point = string::npos;
			} else {
				if(i - i_row > indent) {
					if(is_in(" \t", str[i]) && i + 1 < str.length() && (is_not_in("0123456789", str[i + 1]) || is_not_in("0123456789", str[i - 1]))) {
						if(b_or == 1 && str.length() > i + strlen("or") + 2 && str.substr(i + 1, strlen(_("or"))) == _("or") && str[i + strlen(_("or")) + 1] == ' ') {
							i = i + strlen(_("or")) + 1;
							str[i] = '\n';
							i_row = i + 1;
							lb_point = string::npos;
							c = 0;
						} else if(b_or == 2 && str.length() > i + 2 + 2 && str.substr(i + 1, 2) == "||" && str[i + 2 + 1] == ' ') {
							i = i + 2 + 1;
							str[i] = '\n';
							i_row = i + 1;
							lb_point = string::npos;
							c = 0;
						} else if(c > 10) {
							string teststr = str.substr(i_row, i - i_row);
							pango_layout_set_text(layout, teststr.c_str(), -1);
							gint w = 0;
							pango_layout_get_pixel_size(layout, &w, NULL);
							if(w > history_width) {
								bool cbreak = lb_point == string::npos;
								if(!cbreak && expr) {
									teststr = str.substr(i_row, lb_point - i_row);
									pango_layout_set_text(layout, teststr.c_str(), -1);
									pango_layout_get_pixel_size(layout, &w, NULL);
									cbreak = (w > history_width || w < history_width / 3);
									if(w <= history_width) teststr = str.substr(i_row, i - i_row);
								}
								if(cbreak) {
									while(true) {
										while(teststr[teststr.length() - 1] <= 0 && (unsigned char) teststr[teststr.length() - 1] < 0xC0) {
											i--;
											teststr.erase(teststr.length() - 1, 1);
											if(i == i_row) return;
										}
										i--;
										teststr.erase(teststr.length() - 1, 1);
										if(i == i_row) return;
										pango_layout_set_text(layout, teststr.c_str(), -1);
										pango_layout_get_pixel_size(layout, &w, NULL);
										if(w <= history_width) {
											i++;
											if(str[i - 1] == ' ') {
												i--;
											} else if(str[i - 1] < 0) {
												if(teststr.find(" ", teststr.length() - 3) == teststr.length() - 3) i -= 3;
											} else if(i > 3 && str[i] <= '9' && str[i] >= '0' && str[i - 1] <= '9' && str[i - 1] >= '0') {
												if(str[i - 2] == ' ' && str[i - 3] <= '9' && str[i - 3] >= '0') i -= 2;
												else if(str[i - 3] == ' ' && str[i - 4] <= '9' && str[i - 4] >= '0') i -= 3;
												else if((str[i - 2] == '.' || str[i - 2] == ',') && str[i - 3] <= '9' && str[i - 3] >= '0') i--;
												else if((str[i - 3] == '.' || str[i - 3] == ',') && str[i - 4] <= '9' && str[i - 4] >= '0') i -= 2;
												else if(teststr.length() > 6) {
													size_t i2 = teststr.find(" ", teststr.length() - 6);
													if(i2 != string::npos && i2 > 0 && teststr[i2 - 1] <= '9' && teststr[i2 - 1] >= '0') {
														i = i2 + i_row;
													}
												}
											} else if(i > 4 && (str[i] == '.' || str[i] == ',') && str[i - 1] <= '9' && str[i - 1] >= '0' && str[i - 4] == str[i] && str[i - 5] <= '9' && str[i - 5] >= '0') {
												i -= 3;
											}
											str.insert(i, "\n");
											i_row = i + 1;
											r++;
											lb_point = string::npos;
											break;
										}
									}
								} else {
									str[lb_point] = '\n';
									i = lb_point;
									i_row = i + 1;
									r++;
									lb_point = string::npos;
								}
								c = 0;
							} else {
								lb_point = i;
								c++;
							}
						}
					} else if(i + 1 == str.length() || (c >= 50 && c % 50 == 0)) {
						string teststr;
						if(str[i] <= 0) {
							while(i + 1 < str.length() && str[i + 1] <= 0 && (unsigned char) str[i + 1] < 0xC0) i++;
						}
						if(i + 1 == str.length()) teststr = str.substr(i_row);
						else teststr = str.substr(i_row, i - i_row + 1);
						pango_layout_set_text(layout, teststr.c_str(), -1);
						gint w = 0;
						pango_layout_get_pixel_size(layout, &w, NULL);
						if(w > history_width) {
							bool cbreak = lb_point == string::npos;
							if(!cbreak && expr) {
								teststr = str.substr(i_row, lb_point - i_row);
								pango_layout_set_text(layout, teststr.c_str(), -1);
								pango_layout_get_pixel_size(layout, &w, NULL);
								cbreak = (w > history_width || w < history_width / 3);
								if(w <= history_width) {
									if(i + 1 == str.length()) teststr = str.substr(i_row);
									else teststr = str.substr(i_row, i - i_row + 1);
								}
							}
							if(cbreak) {
								while(true) {
									while(teststr[teststr.length() - 1] <= 0 && (unsigned char) teststr[teststr.length() - 1] < 0xC0) {
										i--;
										teststr.erase(teststr.length() - 1, 1);
										if(i == i_row) return;
									}
									i--;
									teststr.erase(teststr.length() - 1, 1);
									if(i == i_row) return;
									pango_layout_set_text(layout, teststr.c_str(), -1);
									pango_layout_get_pixel_size(layout, &w, NULL);
									if(w <= history_width) {
										i++;
										if(str[i - 1] == ' ') {
											i--;
										} else if(str[i - 1] < 0) {
											if(teststr.find(" ", teststr.length() - 3) == teststr.length() - 3) i -= 3;
										} else if(i > 3 && str[i] <= '9' && str[i] >= '0' && str[i - 1] <= '9' && str[i - 1] >= '0') {
											if(str[i - 2] == ' ' && str[i - 3] <= '9' && str[i - 3] >= '0') i -= 2;
											else if(str[i - 3] == ' ' && str[i - 4] <= '9' && str[i - 4] >= '0') i -= 3;
											else if((str[i - 2] == '.' || str[i - 2] == ',') && str[i - 3] <= '9' && str[i - 3] >= '0') i--;
											else if((str[i - 3] == '.' || str[i - 3] == ',') && str[i - 4] <= '9' && str[i - 4] >= '0') i -= 2;
											else if(teststr.length() > 6) {
												size_t i2 = teststr.find(" ", teststr.length() - 6);
												if(i2 != string::npos && i2 > 0 && teststr[i2 - 1] <= '9' && teststr[i2 - 1] >= '0') {
													i = i2 + i_row;
												}
											}
										} else if(i > 4 && (str[i] == '.' || str[i] == ',') && str[i - 1] <= '9' && str[i - 1] >= '0' && str[i - 4] == str[i] && str[i - 5] <= '9' && str[i - 5] >= '0') {
											i -= 3;
										}
										str.insert(i, "\n");
										i_row = i + 1;
										r++;
										lb_point = string::npos;
										break;
									}
								}
							} else {
								str[lb_point] = '\n';
								i = lb_point;
								i_row = i + 1;
								r++;
								lb_point = string::npos;
							}
							c = 0;
						} else {
							c++;
						}
					} else {
						c++;
					}
				}
			}
		}
	}
	g_object_unref(layout);
	if(font_desc) pango_font_description_free(font_desc);
}

void update_result_bases() {
	if(!result_hex.empty() || !result_dec.empty() || !result_oct.empty() || !result_bin.empty()) {
		string str1, str2;
		bool b_almost_equal = false;
		if(mstruct->isInteger() || (mstruct->isNegate() && mstruct->getChild(1)->isInteger())) {
			str1 = "=";
		} else if(printops.use_unicode_signs && can_display_unicode_string_function(SIGN_ALMOST_EQUAL, (void*) historyview)) {
			str1 = SIGN_ALMOST_EQUAL;
			b_almost_equal = true;
		} else {
			str1 = "= ";
			str1 += _("approx.");
		}
		str1 += " ";
		if(b_almost_equal) str2 = SIGN_ALMOST_EQUAL " ";
		else str2 = "= ";
		PangoFontDescription *font_desc;
		gtk_style_context_get(gtk_widget_get_style_context(result_bases), GTK_STATE_FLAG_NORMAL, GTK_STYLE_PROPERTY_FONT, &font_desc, NULL);
#define SUB_STRING2(X) string("<span size=\"x-small\" rise=\"" + i2s((int) (-pango_font_description_get_size(font_desc) / 2.5)) + "\">") + string(X) + "</span>"
		if(printops.base != 16) {
			str1 += result_hex;
			if(printops.hexadecimal_twos_complement && (mstruct->isNegate() || mstruct->number().isNegative())) str1 += SUB_STRING2("16-");
			else str1 += SUB_STRING2("16");
		}
		if(printops.base != 10) {
			if(printops.base != 16) {
				if(b_almost_equal) str1 += " " SIGN_ALMOST_EQUAL " ";
				else str1 += " = ";
			}
			str1 += result_dec;
			str1 += SUB_STRING2("10");
		}
		if(printops.base != 8) {
			if(b_almost_equal) str1 += " " SIGN_ALMOST_EQUAL " ";
			else str1 += " = ";
			str1 += result_oct;
			str1 += SUB_STRING2("8");
		}
		if(printops.base != 2) {
			if(b_almost_equal) str1 += " " SIGN_ALMOST_EQUAL " ";
			else str1 += " = ";
			str1 += result_bin;
			if(printops.twos_complement && (mstruct->isNegate() || mstruct->number().isNegative())) str1 += SUB_STRING2("2-");
			else str1 += SUB_STRING2("2");
		}
		if(two_result_bases_rows != 0) {
			PangoLayout *layout = gtk_widget_create_pango_layout(result_bases, "");
			pango_layout_set_markup(layout, str1.c_str(), -1);
			gint w = 0;
			pango_layout_get_pixel_size(layout, &w, NULL);
			g_object_unref(layout);
			if(w + 12 > gtk_widget_get_allocated_width(GTK_WIDGET(gtk_builder_get_object(main_builder, "stack_keypad_top")))) {
				size_t i;
				if(b_almost_equal) i = str1.rfind(" " SIGN_ALMOST_EQUAL " ");
				else i = str1.rfind(" = ");
				str1[i] = '\n';
#if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 16
				gtk_label_set_yalign(GTK_LABEL(result_bases), 0.0);
#else
				gtk_misc_set_alignment(GTK_MISC(result_bases), 1.0, 0.0);
#endif
				if(two_result_bases_rows < 0) {
					layout = gtk_widget_create_pango_layout(result_bases, "");
					pango_layout_set_markup(layout, str1.c_str(), -1);
					gint h = 0;
					pango_layout_get_pixel_size(layout, NULL, &h);
					if(h + 3 > gtk_widget_get_allocated_height(GTK_WIDGET(gtk_builder_get_object(main_builder, "stack_keypad_top")))) {
						two_result_bases_rows = 0;
						str1[i] = ' ';
#if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 16
						gtk_label_set_yalign(GTK_LABEL(result_bases), 0.5);
#else
						gtk_misc_set_alignment(GTK_MISC(result_bases), 1.0, 0.5);
#endif
					} else {
						two_result_bases_rows = 1;
					}
					g_object_unref(layout);
				}
			} else {
#if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 16
				gtk_label_set_yalign(GTK_LABEL(result_bases), 0.5);
#else
				gtk_misc_set_alignment(GTK_MISC(result_bases), 1.0, 0.5);
#endif
			}
		}

		pango_font_description_free(font_desc);
		gtk_label_set_markup(GTK_LABEL(result_bases), str1.c_str());
		if(b_almost_equal) gsub(" " SIGN_ALMOST_EQUAL " ", "\n" SIGN_ALMOST_EQUAL " ", str1);
		else gsub(" = ", "\n= ", str1);
		gtk_widget_set_tooltip_markup(result_bases, str1.c_str());
	} else {
		gtk_label_set_text(GTK_LABEL(result_bases), "");
		gtk_widget_set_tooltip_markup(result_bases, "");
	}
}

/*
	set result in result widget and add to history widget
*/
void setResult(Prefix *prefix, bool update_history, bool update_parse, bool force, string transformation, size_t stack_index, bool register_moved) {

	if(block_result_update || exit_in_progress) return;
	
	if(expression_has_changed && (!rpn_mode || CALCULATOR->RPNStackSize() == 0)) {
		if(!force) return;
		execute_expression();
		if(!prefix) return;
	}
	
	if(rpn_mode && CALCULATOR->RPNStackSize() == 0) return;
	
	if(nr_of_new_expressions == 0 && !register_moved && !update_parse && update_history) {
		update_history = false;
	}	
	
	if(b_busy || b_busy_result || b_busy_expression || b_busy_command) return;

	if(!rpn_mode) stack_index = 0;

	if(stack_index != 0) {
		update_history = true;
		update_parse = false;
	}
	if(register_moved) {
		update_history = true;
		update_parse = false;
	}

	do_timeout = false;
	b_busy = true;
	b_busy_result = true;
	display_aborted = false;
	
	if(!view_thread->running && !view_thread->start()) {
		b_busy = false; 
		b_busy_result = false;
		do_timeout = true;
		return;
	}

	GtkTreeIter history_iter;
	
	bool b_rpn_operation = false;

	int inhistory_index = 0;
	if(update_history) {
		if(update_parse || register_moved || current_inhistory_index < 0) {
			if(register_moved) {
				result_text = _("RPN Register Moved");
				inhistory_type.push_back(QALCULATE_HISTORY_REGISTER_MOVED);
				inhistory_protected.push_back(false);
				inhistory.push_back("");
				inhistory_value.push_back(nr_of_new_expressions);
			} else {
				remove_blank_ends(result_text);
				gsub("\n", " ", result_text);
				if(result_text == _("RPN Operation")) {
					b_rpn_operation = true;
					inhistory_type.push_back(QALCULATE_HISTORY_RPN_OPERATION);
					inhistory_protected.push_back(false);
					inhistory.push_back("");
					inhistory_value.push_back(nr_of_new_expressions);
				} else {
					inhistory_type.push_back(QALCULATE_HISTORY_EXPRESSION);
					inhistory_protected.push_back(false);
					inhistory.push_back(result_text);
					inhistory_value.push_back(nr_of_new_expressions);
					if(adaptive_interval_display) {
						string expression_str = get_expression_text();
						if((parsed_mstruct && parsed_mstruct->containsFunction(CALCULATOR->f_uncertainty)) || expression_str.find("+/-") != string::npos || expression_str.find("+/" SIGN_MINUS) != string::npos || expression_str.find("±") != string::npos) printops.interval_display = INTERVAL_DISPLAY_PLUSMINUS;
						else if(parsed_mstruct && parsed_mstruct->containsFunction(CALCULATOR->f_interval)) printops.interval_display = INTERVAL_DISPLAY_INTERVAL;
						else printops.interval_display = INTERVAL_DISPLAY_SIGNIFICANT_DIGITS;
					}
				}
			}
			nr_of_new_expressions++;
			gtk_list_store_insert_with_values(historystore, &history_iter, 0, 0, fix_history_string(result_text).c_str(), 1, inhistory.size() - 1, 2, i2s(nr_of_new_expressions).c_str(), 3, nr_of_new_expressions, 4, EXPRESSION_YPAD, 5, 6, 6, 0.0, 7, PANGO_ALIGN_LEFT, -1);
			gtk_list_store_insert_with_values(historystore, NULL, 1, 1, -1, 5, history_scroll_width, 6, 1.0, 7, PANGO_ALIGN_RIGHT, -1);
			history_index = 0;
			inhistory_index = inhistory.size() - 1;
			history_parsed.push_back(NULL);
			history_answer.push_back(NULL);
		} else if(current_inhistory_index >= 0) {
			inhistory_index = current_inhistory_index;
			if(!transformation.empty()) {
				string history_str = transformation;
				history_str += ":";
				add_line_breaks(history_str, 3, 0);
				fix_history_string2(history_str);
				improve_result_text(history_str);
				history_str.insert(0, "<span font-style=\"italic\">");
				history_str += "</span>";
				history_index++;
				gtk_list_store_insert_with_values(historystore, &history_iter, history_index, 0, history_str.c_str(), 1, inhistory_index, 3, nr_of_new_expressions, 4, 0, 5, history_scroll_width, 6, 1.0, 7, PANGO_ALIGN_RIGHT, -1);
				GtkTreeIter index_iter = history_iter;
				gint index_hi = -1;
				while(gtk_tree_model_iter_previous(GTK_TREE_MODEL(historystore), &index_iter)) {
					gtk_tree_model_get(GTK_TREE_MODEL(historystore), &index_iter, 1, &index_hi, -1);
					if(index_hi >= 0) {
						gtk_list_store_set(historystore, &index_iter, 1, index_hi + 1, -1);
					}
				}
				inhistory.insert(inhistory.begin() + inhistory_index, transformation);
				inhistory_type.insert(inhistory_type.begin() + inhistory_index, QALCULATE_HISTORY_TRANSFORMATION);
				inhistory_protected.insert(inhistory_protected.begin() + inhistory_index, false);
				inhistory_value.insert(inhistory_value.begin() + inhistory_index, nr_of_new_expressions);
			}
		} else {
			b_busy = false;
			b_busy_result = false;
			do_timeout = true;
			return;
		}
		result_text = "?";
	}
	
	if(update_parse) {
		parsed_text = "aborted";
	}

	if(stack_index == 0) {
		clearresult();
	}
	
	update_expression_icons(EXPRESSION_STOP);

	scale_n = 0;

	gint w = 0, h = 0;
	bool parsed_approx = false;
	bool title_set = FALSE;
	
	Number save_nbase(CALCULATOR->customOutputBase());
	int save_base = printops.base;
	bool save_pre = printops.use_unit_prefixes;
	bool save_cur = printops.use_prefixes_for_currencies;
	bool save_allu = printops.use_prefixes_for_all_units;
	bool save_all = printops.use_all_prefixes;
	bool save_den = printops.use_denominator_prefix;
	int save_bin = CALCULATOR->usesBinaryPrefixes();
	NumberFractionFormat save_format = printops.number_fraction_format;
	bool save_restrict_fraction_length = printops.restrict_fraction_length;
	bool do_to = false;
	
	if(stack_index == 0) {
		if(to_base != 0 || to_fraction || to_prefix != 0) {
			if(to_base != 0 && (to_base != printops.base || (to_base == BASE_CUSTOM && to_nbase != CALCULATOR->customOutputBase()))) {
				printops.base = to_base;
				if(to_base == BASE_CUSTOM) CALCULATOR->setCustomOutputBase(to_nbase);
				do_to = true;
			}
			if(to_fraction && (printops.restrict_fraction_length || (mstruct->isNumber() && printops.number_fraction_format != FRACTION_COMBINED) || (!mstruct->isNumber() && printops.number_fraction_format != FRACTION_FRACTIONAL))) {
				printops.restrict_fraction_length = false;
				if(mstruct->isNumber()) printops.number_fraction_format = FRACTION_COMBINED;
				else printops.number_fraction_format = FRACTION_FRACTIONAL;
				do_to = true;
			}
			if(to_prefix != 0 && !prefix) {
				bool new_pre = printops.use_unit_prefixes;
				bool new_cur = printops.use_prefixes_for_currencies;
				bool new_allu = printops.use_prefixes_for_all_units;
				bool new_all = printops.use_all_prefixes;
				bool new_den = printops.use_denominator_prefix;
				int new_bin = CALCULATOR->usesBinaryPrefixes();
				new_pre = true;
				if(to_prefix == 'b') {
					int i = has_information_unit(*mstruct);
					new_bin = (i > 0 ? 1 : 2);
					if(i == 1) {
						new_den = false;
					} else if(i > 1) {
						new_den = true;
					} else {
						new_cur = true;
						new_allu = true;
					}
				} else {
					new_cur = true;
					new_allu = true;
					if(to_prefix == 'a') new_all = true;
					else if(to_prefix == 'd') new_bin = 0;
				}
				if(printops.use_unit_prefixes != new_pre || printops.use_prefixes_for_currencies != new_cur || printops.use_prefixes_for_all_units != new_allu || printops.use_all_prefixes != new_all || printops.use_denominator_prefix != new_den || CALCULATOR->usesBinaryPrefixes() != new_bin) {
					printops.use_unit_prefixes = new_pre;
					printops.use_all_prefixes = new_all;
					printops.use_prefixes_for_currencies = new_cur;
					printops.use_prefixes_for_all_units = new_allu;
					printops.use_denominator_prefix = new_den;
					CALCULATOR->useBinaryPrefixes(new_bin);
					do_to = true;
				}
			}
		}
		if(surface_result) {
			cairo_surface_destroy(surface_result);
		}
		surface_result = NULL;
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "menu_item_save_image")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_save_image")), FALSE);
	}

	printops.prefix = prefix;
	tmp_surface = NULL;

	if(!view_thread->write(scale_n)) {b_busy = false; b_busy_result = false; do_timeout = true; return;}
	if(stack_index == 0) {
		if(!view_thread->write((void *) mstruct)) {b_busy = false; b_busy_result = false; do_timeout = true; return;}
	} else {
		MathStructure *mreg = CALCULATOR->getRPNRegister(stack_index + 1);
		if(!view_thread->write((void *) mreg)) {b_busy = false; b_busy_result = false; do_timeout = true; return;}
	}
	bool b_stack = stack_index != 0;
	if(!view_thread->write(b_stack)) {b_busy = false; b_busy_result = false; do_timeout = true; return;}
	if(b_stack) {
		if(!view_thread->write(NULL)) {b_busy = false; b_busy_result = false; do_timeout = true; return;}
	} else {
		matrix_mstruct->clear();
		if(!view_thread->write((void *) matrix_mstruct)) {b_busy = false; b_busy_result = false; do_timeout = true; return;}
	}
	if(update_parse) {
		if(!view_thread->write((void *) parsed_mstruct)) {b_busy = false; b_busy_result = false; do_timeout = true; return;}
		bool *parsed_approx_p = &parsed_approx;
		if(!view_thread->write((void *) parsed_approx_p)) {b_busy = false; b_busy_result = false; do_timeout = true; return;}
		if(!view_thread->write((void *) (b_rpn_operation ? NULL : parsed_tostruct))) {b_busy = false; b_busy_result = false; do_timeout = true; return;}
	} else {
		if(!view_thread->write(NULL)) {b_busy = false; b_busy_result = false; do_timeout = true; return;}
	}

	int i = 0;
	while(b_busy && view_thread->running && i < 50) {
		sleep_ms(10);
		i++;
	}
	i = 0;

	if(b_busy && view_thread->running) {
		g_application_mark_busy(g_application_get_default());
		gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(main_builder, "resultspinner")));
		gtk_spinner_start(GTK_SPINNER(gtk_builder_get_object(main_builder, "resultspinner")));
		gtk_window_set_title(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), _("Processing…"));
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "menubar")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "buttons")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "convert")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "historyview")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "historyactions")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "rpntab")), FALSE);
		title_set = TRUE;
	}
	while(b_busy && view_thread->running) {
		while(gtk_events_pending()) gtk_main_iteration();
		sleep_ms(100);
	}
	b_busy = true;
	b_busy_result = true;
	
	if(stack_index == 0) {
		display_aborted = !tmp_surface;
		if(display_aborted) {
			PangoLayout *layout = gtk_widget_create_pango_layout(resultview, NULL);
			pango_layout_set_markup(layout, _("result processing was aborted"), -1);
			pango_layout_get_pixel_size(layout, &w, &h);
			gint scalefactor = gtk_widget_get_scale_factor(expressiontext);
			tmp_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
			cairo_surface_set_device_scale(tmp_surface, scalefactor, scalefactor);
			cairo_t *cr = cairo_create(tmp_surface);
			GdkRGBA rgba;
			gtk_style_context_get_color(gtk_widget_get_style_context(resultview), gtk_widget_get_state_flags(resultview), &rgba);
			gdk_cairo_set_source_rgba(cr, &rgba);
			pango_cairo_show_layout(cr, layout);
			cairo_destroy(cr);
			g_object_unref(layout);
			*printops.is_approximate = false;
		}
	}
	
	update_expression_icons();
	if(title_set) {
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "menubar")), TRUE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "buttons")), TRUE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "convert")), TRUE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "historyview")), TRUE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "historyactions")), TRUE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "rpntab")), TRUE);
		gtk_window_set_title(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), _("Qalculate!"));
	}

	if(stack_index == 0) {
		update_result_bases();
		if(title_set) {
			gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "resultspinner")));
			gtk_spinner_stop(GTK_SPINNER(gtk_builder_get_object(main_builder, "resultspinner")));
			g_application_unmark_busy(g_application_get_default());
			while(gtk_events_pending()) gtk_main_iteration();
		}
		surface_result = NULL;
		if(tmp_surface) {
			showing_first_time_message = FALSE;
			first_draw_of_result = TRUE;
			surface_result = tmp_surface;
			gtk_widget_queue_draw(resultview);
			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "menu_item_save_image")), displayed_mstruct && !display_aborted);
			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_save_image")), displayed_mstruct && !display_aborted);
		}
	}
	if(register_moved) {
		update_parse = true;
		parsed_text = result_text;
	}
	if(current_inhistory_index < 0) {
		update_parse = true;
		current_inhistory_index = 0;
	}
	bool do_scroll = false;
	if(stack_index != 0) {
		if(result_text.length() > 500000) {
			result_text = "(…)";
		}		
		RPNRegisterChanged(result_text, stack_index);
		display_errors(NULL, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")), NULL, message_type == 0 ? 0 : 2);
	} else if(update_history) {
		if(result_text.length() > 500000) {
			result_text = "(…)";
		}
		if(parsed_text.length() > 500000) {
			parsed_text = "(…)";
		}
		if(update_parse) {
			gchar *expr_str = NULL;
			gtk_tree_model_get(GTK_TREE_MODEL(historystore), &history_iter, 0, &expr_str, -1);
			string str = expr_str;
			str += "<span font-style=\"italic\" foreground=\"";
			str += history_parse_color;
			str += "\">  ";
			string str2;
			if(!parsed_approx) {
				str2 = "=";
				inhistory_type.insert(inhistory_type.begin() + inhistory_index, QALCULATE_HISTORY_PARSE);
				inhistory_protected.insert(inhistory_protected.begin() + inhistory_index, false);
				inhistory_value.insert(inhistory_value.begin() + inhistory_index, nr_of_new_expressions);
			} else {
				if(printops.use_unicode_signs && can_display_unicode_string_function(SIGN_ALMOST_EQUAL, (void*) historyview)) {
					str2 = SIGN_ALMOST_EQUAL;
				} else {
					str2 = _("approx.");
				}
				inhistory_type.insert(inhistory_type.begin() + inhistory_index, QALCULATE_HISTORY_PARSE_APPROXIMATE);
				inhistory_protected.insert(inhistory_protected.begin() + inhistory_index, false);
				inhistory_value.insert(inhistory_value.begin() + inhistory_index, nr_of_new_expressions);
			}
			str += str2;
			str += " ";
			str += fix_history_string(parsed_text);
			str += "</span>";
			inhistory.insert(inhistory.begin() + inhistory_index, parsed_text);
			if(nr_of_new_expressions > 0 && parsed_mstruct && !history_parsed[nr_of_new_expressions - 1]) {
				history_parsed[nr_of_new_expressions - 1] = new MathStructure(*parsed_mstruct);
			}
			PangoLayout *layout = gtk_widget_create_pango_layout(historyview, "");
			pango_layout_set_markup(layout, str.c_str(), -1);
			gint w = 0;
			pango_layout_get_pixel_size(layout, &w, NULL);
			if(w > history_width_e) {
				str = expr_str;
				unfix_history_string(str);
				add_line_breaks(str, 1, 0);
				fix_history_string2(str);
				str2 += " ";
				size_t history_expr_i = str2.length();
				str2 += parsed_text;
				add_line_breaks(str2, 3, history_expr_i);
				fix_history_string2(str2);
				str += '\n';
				str += "<span font-style=\"italic\" foreground=\"";
				str += history_parse_color;
				str += "\">";
				str += str2;
				str += "</span>";
			}
			gtk_list_store_set(historystore, &history_iter, 0, str.c_str(), -1);
			g_object_unref(layout);
			g_free(expr_str);
		}
		int history_index_bak = history_index;
		display_errors(&history_index, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")), &inhistory_index, message_type);
		if(rpn_mode && !register_moved) {
			RPNRegisterChanged(result_text, stack_index);
		}

		string str;

		bool b_approx = result_text_approximate || mstruct->isApproximate();		
		if(!b_approx) {
			str = "=";
		} else {
			if(printops.use_unicode_signs && can_display_unicode_string_function(SIGN_ALMOST_EQUAL, (void*) historyview)) {
				str = SIGN_ALMOST_EQUAL;
			} else {
				str = "= ";
				str += _("approx.");
			}
		}
		string history_str;
		size_t trans_l = 0;
		if(!update_parse && current_inhistory_index >= 0 && !transformation.empty() && history_index == history_index_bak) {
			history_str = transformation;
			history_str += ":  ";
			trans_l = history_str.length();
		}
		history_str += str;
		history_str += " ";
		size_t history_expr_i = history_str.length();
		history_str += result_text;
		add_line_breaks(history_str, 2, history_expr_i);
		fix_history_string2(history_str);
		improve_result_text(history_str);
		if(trans_l > 0) {
			trans_l = history_str.find(":  ");
			if(trans_l != string::npos) {
				trans_l += 3;
				history_str.insert(trans_l, "</span>");
				history_str.insert(0, "<span font-style=\"italic\">");
			}
		}
		if(!update_parse && current_inhistory_index >= 0 && !transformation.empty() && history_index_bak == history_index) {
			gtk_list_store_set(historystore, &history_iter, 0, history_str.c_str(), 1, inhistory_index + 1, -1);
		} else {
			history_index++;
			gtk_list_store_insert_with_values(historystore, &history_iter, history_index, 0, history_str.c_str(), 1, inhistory_index, 3, nr_of_new_expressions, 4, 0, 5, history_scroll_width, 6, 1.0, 7, PANGO_ALIGN_RIGHT, -1);
		}
		inhistory.insert(inhistory.begin() + inhistory_index, result_text);
		current_inhistory_index = inhistory_index;
		if(b_approx) {
			inhistory_type.insert(inhistory_type.begin() + inhistory_index, QALCULATE_HISTORY_RESULT_APPROXIMATE);
		} else {
			inhistory_type.insert(inhistory_type.begin() + inhistory_index, QALCULATE_HISTORY_RESULT);
		}
		inhistory_protected.insert(inhistory_protected.begin() + inhistory_index, false);
		inhistory_value.insert(inhistory_value.begin() + inhistory_index, nr_of_new_expressions);
		if(nr_of_new_expressions > 0 && mstruct && nr_of_new_expressions <= (int) history_answer.size()) {
			if(!history_answer[nr_of_new_expressions - 1]) history_answer[nr_of_new_expressions - 1] = new MathStructure(*mstruct);
			else history_answer[nr_of_new_expressions - 1]->set(*mstruct);
		}
		
		GtkTreeIter index_iter = history_iter;
		gint index_hi = -1;
		while(gtk_tree_model_iter_previous(GTK_TREE_MODEL(historystore), &index_iter)) {
			gtk_tree_model_get(GTK_TREE_MODEL(historystore), &index_iter, 1, &index_hi, -1);
			if(index_hi >= 0) {
				gtk_list_store_set(historystore, &index_iter, 1, index_hi + 1, -1);
			}
		}		
		
		if(result_text.length() < 1000) {
			str += " ";
			if(result_text_long.empty()) {
				str += result_text;
			} else {
				str += result_text_long;
			}
			gtk_widget_set_tooltip_text(resultview, str.length() < 1000 ? str.c_str() : "");
		}
		do_scroll = true;
	} else {
		int history_index_bak = history_index;
		display_errors(&history_index, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")), &inhistory_index, message_type);
		do_scroll = (history_index != history_index_bak);
	}
	if(do_to) {
		printops.base = save_base;
		CALCULATOR->setCustomOutputBase(save_nbase);
		printops.use_unit_prefixes = save_pre;
		printops.use_all_prefixes = save_all;
		printops.use_prefixes_for_currencies = save_cur;
		printops.use_prefixes_for_all_units = save_allu;
		printops.use_denominator_prefix = save_den;
		CALCULATOR->useBinaryPrefixes(save_bin);
		printops.number_fraction_format = save_format;
		printops.restrict_fraction_length = save_restrict_fraction_length;
	}
	printops.prefix = NULL;
	b_busy = false;
	b_busy_result = false;
	
	while(gtk_events_pending()) gtk_main_iteration();
	if(do_scroll && gtk_widget_get_realized(historyview)) {
		GtkTreePath *path = gtk_tree_path_new_from_indices(0, -1);
		gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(historyview), path, history_index_column, FALSE, 0, 0);
		gtk_tree_view_scroll_to_point(GTK_TREE_VIEW(historyview), 0, 0);
		gtk_tree_path_free(path);
	}

	if(!register_moved && stack_index == 0 && mstruct->isMatrix() && (mstruct->rows() > 4 || mstruct->columns() > 4) && matrix_mstruct->isMatrix() && matrix_mstruct->columns() < 200) {
		while(gtk_events_pending()) gtk_main_iteration();
		gtk_widget_grab_focus(expressiontext);
		if(update_history && update_parse && force) {
			GtkTextIter istart, iend;
			gtk_text_buffer_get_start_iter(expressionbuffer, &istart);
			gtk_text_buffer_get_end_iter(expressionbuffer, &iend);
			gtk_text_buffer_select_range(expressionbuffer, &istart, &iend);
			gtk_text_buffer_remove_tag(expressionbuffer, expression_par_tag, &istart, &iend);
		}
		insert_matrix(matrix_mstruct, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")), false, true, true);
	}
	
	do_timeout = true;

}

void on_abort_command(GtkDialog*, gint, gpointer) {
	CALCULATOR->abort();
	int msecs = 5000;
	while(b_busy && msecs > 0) {
		sleep_ms(10);
		msecs -= 10;
	}
	if(b_busy) {
		command_thread->cancel();
		b_busy = false;
		CALCULATOR->stopControl();
		command_aborted = true;
	}
}

void CommandThread::run() {

	enableAsynchronousCancel();

	while(true) {
		int command_type = 0;
		if(!read(&command_type)) break;
		void *x = NULL;
		if(!read(&x)) break;
		CALCULATOR->startControl();
		switch(command_type) {
			case COMMAND_FACTORIZE: {
				if(!((MathStructure*) x)->integerFactorize()) {
					((MathStructure*) x)->structure(STRUCTURING_FACTORIZE, evalops, true);
				}
				break;
			}
			case COMMAND_EXPAND_PARTIAL_FRACTIONS: {
				((MathStructure*) x)->expandPartialFractions(evalops);
				break;
			}
			case COMMAND_EXPAND: {
				((MathStructure*) x)->expand(evalops);
				break;
			}
			case COMMAND_TRANSFORM: {
				string ceu_str;
				if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "convert_button_continuous_conversion")))) {
					ceu_str = CALCULATOR->unlocalizeExpression(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(main_builder, "convert_entry_unit"))), evalops.parse_options);
					remove_blank_ends(ceu_str);
					if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "convert_button_set_missing_prefixes"))) && !ceu_str.empty()) {
						if(ceu_str[0] != '0' && ceu_str[0] != '?' && ceu_str[0] != '+' && ceu_str[0] != '-' && (ceu_str.length() == 1 || ceu_str[1] != '?')) {
							ceu_str = "?" + ceu_str;
						}
					}
					if(!ceu_str.empty() && ceu_str[0] == '?') {
						to_prefix = 1;
					} else if(ceu_str.length() > 1 && ceu_str[1] == '?' && (ceu_str[0] == 'b' || ceu_str[0] == 'a' || ceu_str[0] == 'd')) {
						to_prefix = ceu_str[0];
					}
				}
				((MathStructure*) x)->set(CALCULATOR->calculate(*((MathStructure*) x), evalops, ceu_str));
				break;
			}
			case COMMAND_CONVERT_STRING: {
				((MathStructure*) x)->set(CALCULATOR->convert(*((MathStructure*) x), command_convert_units_string, evalops));
				break;
			}
			case COMMAND_CONVERT_UNIT: {
				((MathStructure*) x)->set(CALCULATOR->convert(*((MathStructure*) x), command_convert_unit, evalops, false));
				break;
			}
			case COMMAND_CONVERT_OPTIMAL: {
				((MathStructure*) x)->set(CALCULATOR->convertToOptimalUnit(*((MathStructure*) x), evalops, true));
				break;
			}
			case COMMAND_CONVERT_BASE: {
				((MathStructure*) x)->set(CALCULATOR->convertToBaseUnits(*((MathStructure*) x), evalops));
				break;
			}
			case COMMAND_CALCULATE: {
				EvaluationOptions eo2 = evalops;
				eo2.calculate_functions = false;
				eo2.sync_units = false;
				((MathStructure*) x)->calculatesub(eo2, eo2, true);
				break;
			}
			case COMMAND_EVAL: {
				((MathStructure*) x)->eval(evalops);
				break;
			}
		}
		b_busy = false;
		CALCULATOR->stopControl();
	}
}

void executeCommand(int command_type, bool show_result, string ceu_str, Unit *u, int run) {

	if(exit_in_progress) return;

	if(run == 1) {
		if(expression_has_changed && !rpn_mode && command_type != COMMAND_TRANSFORM) {
			execute_expression();
		}

		if(b_busy || b_busy_result || b_busy_expression || b_busy_command) return;
	
		do_timeout = false;
		b_busy = true;
		b_busy_command = true;
		command_aborted = false;
	
		if(command_type >= COMMAND_CONVERT_UNIT) {
			CALCULATOR->resetExchangeRatesUsed();
			command_convert_units_string = ceu_str;
			command_convert_unit = u;
		}
		if(command_type == COMMAND_CONVERT_UNIT || command_type == COMMAND_CONVERT_STRING || command_type == COMMAND_CONVERT_BASE || command_type == COMMAND_CONVERT_OPTIMAL) {
			to_prefix = 0;
		}
	}
	
	bool title_set = FALSE;
	update_expression_icons(EXPRESSION_STOP);
	int i = 0;
	
	MathStructure *mfactor = new MathStructure(*mstruct);
	
	rerun_command:

	if(!command_thread->running && !command_thread->start()) {do_timeout = true; b_busy = false; b_busy_command = false; return;}

	if(!command_thread->write(command_type)) {do_timeout = true; b_busy = false; b_busy_command = false; return;}
	if(!command_thread->write((void *) mfactor)) {do_timeout = true; b_busy = false; b_busy_command = false; return;}

	while(b_busy && command_thread->running && i < 50) {
		sleep_ms(10);
		i++;
	}
	i = 0;
	
	if(b_busy && command_thread->running) {
		string progress_str;
		switch(command_type) {
			case COMMAND_FACTORIZE: {
				progress_str = _("Factorizing…");
				break;
			}
			case COMMAND_EXPAND_PARTIAL_FRACTIONS: {
				progress_str = _("Expanding partial fractions…");
				break;
			}
			case COMMAND_EXPAND: {
				progress_str = _("Expanding…");
				break;
			}
			case COMMAND_EVAL: {}
			case COMMAND_TRANSFORM: {
				progress_str = _("Calculating…");
				break;
			}
			default: {
				progress_str = _("Converting…");
				break;
			}
		}
		gtk_window_set_title(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), progress_str.c_str());
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "menubar")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "buttons")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "convert")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "historyview")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "historyactions")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "rpntab")), FALSE);
		update_expression_icons(EXPRESSION_SPINNER);
		gtk_spinner_start(GTK_SPINNER(gtk_builder_get_object(main_builder, "expressionspinner")));
		g_application_mark_busy(g_application_get_default());
		title_set = TRUE;
	}
	while(b_busy && command_thread->running) {
		while(gtk_events_pending()) gtk_main_iteration();
		sleep_ms(100);
	}
	if(!command_thread->running) command_aborted = true;
	
	if(!command_aborted && run == 1 && command_type >= COMMAND_CONVERT_UNIT && check_exchange_rates(NULL, show_result)) {
		b_busy = true;
		mfactor->set(*mstruct);
		run = 2;
		goto rerun_command;
	}

	b_busy = false;
	b_busy_command = false;

	update_expression_icons();
	if(title_set) {
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "menubar")), TRUE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "buttons")), TRUE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "convert")), TRUE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "historyview")), TRUE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "historyactions")), TRUE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "rpntab")), TRUE);
		gtk_window_set_title(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), _("Qalculate!"));
		gtk_spinner_stop(GTK_SPINNER(gtk_builder_get_object(main_builder, "expressionspinner")));
		g_application_unmark_busy(g_application_get_default());
	}
	
	if(command_type == COMMAND_CONVERT_STRING && !ceu_str.empty()) {
		if(ceu_str[0] == '?') {
			to_prefix = 1;
		} else if(ceu_str.length() > 1 && ceu_str[1] == '?' && (ceu_str[0] == 'b' || ceu_str[0] == 'a' || ceu_str[0] == 'd')) {
			to_prefix = ceu_str[0];
		}
	}

	if(!command_aborted) {
		mstruct->set(*mfactor);
		mfactor->unref();
		switch(command_type) {
			case COMMAND_FACTORIZE: {
				printops.allow_factorization = true;
				break;
			}
			case COMMAND_EXPAND: {
				printops.allow_factorization = false;
				break;
			}
			default: {
				printops.allow_factorization = (evalops.structuring == STRUCTURING_FACTORIZE);
			}
		}
		if(show_result) {
			setResult(NULL, true, false, true, command_type == COMMAND_TRANSFORM ? ceu_str : "");
		}
	}
		
	do_timeout = true;

}

void fetch_exchange_rates(int timeout, int n) {
	bool b_busy_bak = b_busy;
	bool do_timeout_bak = do_timeout;
	b_busy = true;
	do_timeout = false;
	FetchExchangeRatesThread fetch_thread;
	if(fetch_thread.start() && fetch_thread.write(timeout) && fetch_thread.write(n)) {
		int i = 0;
		while(fetch_thread.running && i < 50) {
			while(gtk_events_pending()) gtk_main_iteration();
			sleep_ms(10);
			i++;
		}
		if(fetch_thread.running) {
			GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), (GtkDialogFlags) (GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL), GTK_MESSAGE_INFO, GTK_BUTTONS_NONE, _("Fetching exchange rates."));
			gtk_widget_show(dialog);
			while(fetch_thread.running) {
				while(gtk_events_pending()) gtk_main_iteration();
				sleep_ms(10);
			}
			gtk_widget_destroy(dialog);
		}
	}
	b_busy = b_busy_bak;
	do_timeout = do_timeout_bak;
}

void FetchExchangeRatesThread::run() {
	int timeout = 15;
	int n = -1;
	if(!read(&timeout)) return;
	if(!read(&n)) return;
	CALCULATOR->fetchExchangeRates(timeout, n);
}

void update_message_print_options() {
	PrintOptions message_printoptions = printops;
	message_printoptions.interval_display = INTERVAL_DISPLAY_PLUSMINUS;
	message_printoptions.show_ending_zeroes = false;
	message_printoptions.base = 10;
	if(printops.min_exp < -10 || printops.min_exp > 10 || ((printops.min_exp == EXP_PRECISION || printops.min_exp == EXP_NONE) && PRECISION > 10)) message_printoptions.min_exp = 10;
	else if(printops.min_exp == EXP_NONE) message_printoptions.min_exp = EXP_PRECISION;
	if(PRECISION > 10) {
		message_printoptions.use_max_decimals = true;
		message_printoptions.max_decimals = 10;
	}
	CALCULATOR->setMessagePrintOptions(message_printoptions);
}

void result_display_updated() {
	gtk_widget_queue_draw(resultview);
	update_message_print_options();
	update_status_text();
	expression_has_changed2 = true;
	display_parse_status();
}
void result_format_updated() {
	update_message_print_options();
	if(result_autocalculated) print_auto_calc();
	else setResult(NULL, true, false, false);
	update_status_text();
	expression_has_changed2 = true;
	display_parse_status();
}
void result_action_executed() {
	printops.allow_factorization = (evalops.structuring == STRUCTURING_FACTORIZE);
	setResult(NULL, true, false, true);
}
bool contains_prefix(const MathStructure &m) {
	if(m.isUnit() && (m.prefix() || m.unit()->subtype() == SUBTYPE_COMPOSITE_UNIT)) return true;
	for(size_t i = 0; i < m.size(); i++) {
		if(contains_prefix(m[i])) return true;
	}
	return false;
}
void result_prefix_changed(Prefix *prefix) {
	to_prefix = 0;
	bool b_use_unit_prefixes = printops.use_unit_prefixes;
	bool b_use_prefixes_for_all_units = printops.use_prefixes_for_all_units;
	if(contains_prefix(*mstruct)) {
		mstruct->unformat(evalops);
		executeCommand(COMMAND_CALCULATE, false);
	}
	if(!prefix) {
		//mstruct->unformat(evalops);
		printops.use_unit_prefixes = true; 
		printops.use_prefixes_for_all_units = true;
	}
	if(result_autocalculated) print_auto_calc();
	else setResult(prefix, true, false, true);
	printops.use_unit_prefixes = b_use_unit_prefixes;
	printops.use_prefixes_for_all_units = b_use_prefixes_for_all_units;
	
}
void expression_calculation_updated() {
	expression_has_changed2 = true;
	display_parse_status();
	if(!rpn_mode) {
		if(auto_calculate) do_auto_calc();
		else execute_expression(false);
	}
	update_status_text();
}
void expression_format_updated(bool recalculate) {
	expression_has_changed2 = true;
	if(rpn_mode) recalculate = false;
	display_parse_status();
	update_message_print_options();
	if(!expression_has_changed && !recalculate && !rpn_mode && !auto_calculate) {
		clearresult();
	}
	if(!rpn_mode) {
		if(auto_calculate) do_auto_calc();
		else if(recalculate) execute_expression(false);
	}
	update_status_text();
}


void on_abort_calculation(GtkDialog*, gint, gpointer) {
	CALCULATOR->abort();
}


void add_to_expression_history(string str) {
	for(size_t i = 0; i < expression_history.size(); i++) {
		if(expression_history[i] == str) {
			expression_history.erase(expression_history.begin() + i);
			break;
		}
	}
	if(expression_history.size() >= 100) {
		expression_history.pop_back();
	}
	expression_history.insert(expression_history.begin(), str);
	expression_history_index = 0;
}

void set_previous_expression() {
	if(rpn_mode) {
		clear_expression_text();
	} else {
		rpn_mode = true;
		gtk_text_buffer_set_text(expressionbuffer, previous_expression.c_str(), -1);
		rpn_mode = false;
		gtk_widget_grab_focus(expressiontext);
		GtkTextIter istart, iend;
		gtk_text_buffer_get_start_iter(expressionbuffer, &istart);
		gtk_text_buffer_get_end_iter(expressionbuffer, &iend);
		gtk_text_buffer_select_range(expressionbuffer, &istart, &iend);
		gtk_text_buffer_remove_tag(expressionbuffer, expression_par_tag, &istart, &iend);
	}
}

/*
	calculate entered expression and display result
*/
void execute_expression(bool force, bool do_mathoperation, MathOperation op, MathFunction *f, bool do_stack, size_t stack_index, string execute_str, string str, bool check_exrates) {

	if(block_expression_execution || exit_in_progress) return;

	string saved_execute_str = execute_str;
	
	if(b_busy || b_busy_result || b_busy_expression || b_busy_command) return;
	
	if(completion_timeout_id != 0) {
		g_source_remove(completion_timeout_id);
		completion_timeout_id = 0;
	}
	
	b_busy = true;
	b_busy_expression = true;

	bool do_factors = false, do_pfe = false, do_expand = false, do_conv = false;
	if(do_stack && !rpn_mode) do_stack = false;
	if(do_stack && do_mathoperation && f && stack_index == 0) do_stack = false;
	
	if(execute_str.empty()) {
		to_fraction = false; to_prefix = 0; to_base = 0; to_nbase.clear();
	}

	if(str.empty() && !do_mathoperation) {
		if(do_stack) {
			GtkTreeIter iter;
			gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(stackstore), &iter, NULL, stack_index);
			gchar *gstr;
			gtk_tree_model_get(GTK_TREE_MODEL(stackstore), &iter, 1, &gstr, -1);
			str = gstr;
			g_free(gstr);
			do_timeout = false;
		} else {
			GtkTextIter istart, iend;
			gtk_text_buffer_get_start_iter(expressionbuffer, &istart);
			gtk_text_buffer_get_end_iter(expressionbuffer, &iend);
			gchar *gstr = gtk_text_buffer_get_text(expressionbuffer, &istart, &iend, FALSE);
			str = gstr;
			g_free(gstr);
			if(!force && (expression_has_changed || str.find_first_not_of(SPACES) == string::npos)) {
				b_busy = false;
				b_busy_expression = false;
				return;
			}
			do_timeout = false;
			expression_has_changed = false;
			if(!do_mathoperation && !str.empty()) add_to_expression_history(str);
		}
	}
	
	string from_str = str, to_str;
	if(execute_str.empty() && CALCULATOR->separateToExpression(from_str, to_str, evalops, true, !do_stack)) {
		remove_duplicate_blanks(to_str);
		string to_str1, to_str2;
		size_t ispace = to_str.find_first_of(SPACES);
		if(ispace != string::npos) {
			to_str1 = to_str.substr(0, ispace);
			remove_blank_ends(to_str1);
			to_str2 = to_str.substr(ispace + 1);
			remove_blank_ends(to_str2);
		}
		bool do_to = false;
		if(equalsIgnoreCase(to_str, "hex") || equalsIgnoreCase(to_str, "hexadecimal") || equalsIgnoreCase(to_str, _("hexadecimal"))) {
			to_base = BASE_HEXADECIMAL;
			do_to = true;
		} else if(equalsIgnoreCase(to_str, "oct") || equalsIgnoreCase(to_str, "octal") || equalsIgnoreCase(to_str, _("octal"))) {
			to_base = BASE_OCTAL;
			do_to = true;
		} else if(equalsIgnoreCase(to_str, "dec") || equalsIgnoreCase(to_str, "decimal") || equalsIgnoreCase(to_str, _("decimal"))) {
			to_base = BASE_DECIMAL;
			do_to = true;
		} else if(equalsIgnoreCase(to_str, "duo") || equalsIgnoreCase(to_str, "duodecimal") || equalsIgnoreCase(to_str, _("duodecimal"))) {
			to_base = BASE_DUODECIMAL;
			do_to = true;
		} else if(equalsIgnoreCase(to_str, "bin") || equalsIgnoreCase(to_str, "binary") || equalsIgnoreCase(to_str, _("binary"))) {
			to_base = BASE_BINARY;
			do_to = true;
		} else if(equalsIgnoreCase(to_str, "roman") || equalsIgnoreCase(to_str, _("roman"))) {
			to_base = BASE_ROMAN_NUMERALS;
			do_to = true;
		} else if(equalsIgnoreCase(to_str, "bijective") || equalsIgnoreCase(to_str, _("bijective"))) {
			to_base = BASE_BIJECTIVE_26;
			do_to = true;
		} else if(equalsIgnoreCase(to_str, "sexa") || equalsIgnoreCase(to_str, "sexagesimal") || equalsIgnoreCase(to_str, _("sexagesimal"))) {
			to_base = BASE_SEXAGESIMAL;
			do_to = true;
		} else if(equalsIgnoreCase(to_str, "time") || equalsIgnoreCase(to_str, _("time"))) {
			to_base = BASE_TIME;
			do_to = true;
		} else if(equalsIgnoreCase(to_str, "Unicode")) {
			to_base = BASE_UNICODE;
			do_to = true;
		} else if(equalsIgnoreCase(to_str, "utc") || equalsIgnoreCase(to_str, "gmt")) {
			printops.time_zone = TIME_ZONE_UTC;
			b_busy = false;
			b_busy_expression = false;
			if(from_str.empty()) {setResult(NULL, true, false, false); set_previous_expression();}
			else execute_expression(force, do_mathoperation, op, f, do_stack, stack_index, from_str);
			printops.time_zone = TIME_ZONE_LOCAL;
			return;
		} else if(to_str.length() > 3 && (equalsIgnoreCase(to_str.substr(0, 3), "utc") || equalsIgnoreCase(to_str.substr(0, 3), "gmt"))) {
			to_str = to_str.substr(3);
			remove_blanks(to_str);
			bool b_minus = false;
			if(to_str[0] == '+') {
				to_str.erase(0, 1);
			} else if(to_str[0] == '-') {
				b_minus = true;
				to_str.erase(0, 1);
			} else if(to_str.find(SIGN_MINUS) == 0) {
				b_minus = true;
				to_str.erase(0, strlen(SIGN_MINUS));
			}
			unsigned int tzh = 0, tzm = 0;
			int itz = 0;
			if(!to_str.empty() && sscanf(to_str.c_str(), "%2u:%2u", &tzh, &tzm) > 0) {
				itz = tzh * 60 + tzm;
				if(b_minus) itz = -itz;
			} else {
				CALCULATOR->error(true, _("Time zone parsing failed."), NULL);
			}
			printops.time_zone = TIME_ZONE_CUSTOM;
			printops.custom_time_zone = itz;
			b_busy = false;
			b_busy_expression = false;
			if(from_str.empty()) {setResult(NULL, true, false, false); set_previous_expression();}
			else execute_expression(force, do_mathoperation, op, f, do_stack, stack_index, from_str);
			printops.custom_time_zone = 0;
			printops.time_zone = TIME_ZONE_LOCAL;
			return;
		} else if(to_str == "CET") {
			printops.time_zone = TIME_ZONE_CUSTOM;
			printops.custom_time_zone = 60;
			b_busy = false;
			b_busy_expression = false;
			if(from_str.empty()) {setResult(NULL, true, false, false); set_previous_expression();}
			else execute_expression(force, do_mathoperation, op, f, do_stack, stack_index, from_str);
			printops.custom_time_zone = 0;
			printops.time_zone = TIME_ZONE_LOCAL;
			return;
		} else if(equalsIgnoreCase(to_str, "bases") || equalsIgnoreCase(to_str, _("bases"))) {
			b_busy = false;
			b_busy_expression = false;
			if(from_str.empty()) {
				set_previous_expression();
				convert_number_bases(result_text.c_str());
			} else {
				execute_expression(force, do_mathoperation, op, f, do_stack, stack_index, from_str);
				convert_number_bases(from_str.c_str());
			}
			return;
		} else if(equalsIgnoreCase(to_str, "calendars") || equalsIgnoreCase(to_str, _("calendars"))) {
			b_busy = false;
			b_busy_expression = false;
			if(from_str.empty()) set_previous_expression();
			else execute_expression(force, do_mathoperation, op, f, do_stack, stack_index, from_str);
			on_popup_menu_item_calendarconversion_activate(NULL, NULL);
			return;
		} else if(equalsIgnoreCase(to_str, "rectangular") || equalsIgnoreCase(to_str, "cartesian") || equalsIgnoreCase(to_str, _("rectangular")) || equalsIgnoreCase(to_str, _("cartesian"))) {
			b_busy = false;
			b_busy_expression = false;
			ComplexNumberForm cnf_bak = evalops.complex_number_form;
			bool caf_bak = complex_angle_form;
			evalops.complex_number_form = COMPLEX_NUMBER_FORM_RECTANGULAR;
			complex_angle_form = false;
			if(from_str.empty()) {
				executeCommand(COMMAND_EVAL);
				set_previous_expression();
			} else {
				execute_expression(force, do_mathoperation, op, f, do_stack, stack_index, from_str);
			}
			complex_angle_form = caf_bak;
			evalops.complex_number_form = cnf_bak;
			return;
		} else if(equalsIgnoreCase(to_str, "exponential") || equalsIgnoreCase(to_str, _("exponential"))) {
			b_busy = false;
			b_busy_expression = false;
			ComplexNumberForm cnf_bak = evalops.complex_number_form;
			bool caf_bak = complex_angle_form;
			evalops.complex_number_form = COMPLEX_NUMBER_FORM_EXPONENTIAL;
			complex_angle_form = false;
			if(from_str.empty()) {
				executeCommand(COMMAND_EVAL);
				set_previous_expression();
			} else {
				execute_expression(force, do_mathoperation, op, f, do_stack, stack_index, from_str);
			}
			complex_angle_form = caf_bak;
			evalops.complex_number_form = cnf_bak;
			return;
		} else if(equalsIgnoreCase(to_str, "polar") || equalsIgnoreCase(to_str, _("polar"))) {
			b_busy = false;
			b_busy_expression = false;
			ComplexNumberForm cnf_bak = evalops.complex_number_form;
			bool caf_bak = complex_angle_form;
			evalops.complex_number_form = COMPLEX_NUMBER_FORM_POLAR;
			complex_angle_form = false;
			if(from_str.empty()) {
				executeCommand(COMMAND_EVAL);
				set_previous_expression();
			} else {
				execute_expression(force, do_mathoperation, op, f, do_stack, stack_index, from_str);
			}
			complex_angle_form = caf_bak;
			evalops.complex_number_form = cnf_bak;
			return;
		} else if(to_str == "cis") {
			b_busy = false;
			b_busy_expression = false;
			ComplexNumberForm cnf_bak = evalops.complex_number_form;
			bool caf_bak = complex_angle_form;
			evalops.complex_number_form = COMPLEX_NUMBER_FORM_CIS;
			complex_angle_form = false;
			if(from_str.empty()) {
				executeCommand(COMMAND_EVAL);
				set_previous_expression();
			} else {
				execute_expression(force, do_mathoperation, op, f, do_stack, stack_index, from_str);
			}
			complex_angle_form = caf_bak;
			evalops.complex_number_form = cnf_bak;
			return;
		} else if(equalsIgnoreCase(to_str, "phasor") || equalsIgnoreCase(to_str, _("phasor")) || equalsIgnoreCase(to_str, "angle") || equalsIgnoreCase(to_str, _("angle"))) {
			b_busy = false;
			b_busy_expression = false;
			ComplexNumberForm cnf_bak = evalops.complex_number_form;
			bool caf_bak = complex_angle_form;
			evalops.complex_number_form = COMPLEX_NUMBER_FORM_CIS;
			complex_angle_form = true;
			if(from_str.empty()) {
				executeCommand(COMMAND_EVAL);
				set_previous_expression();
			} else {
				execute_expression(force, do_mathoperation, op, f, do_stack, stack_index, from_str);
			}
			complex_angle_form = caf_bak;
			evalops.complex_number_form = cnf_bak;
			return;
		} else if(equalsIgnoreCase(to_str, "optimal") || equalsIgnoreCase(to_str, _("optimal"))) {
			b_busy = false;
			b_busy_expression = false;
			if(from_str.empty()) {
				executeCommand(COMMAND_CONVERT_OPTIMAL);
				set_previous_expression();
			} else {
				bool b_units_saved = evalops.parse_options.units_enabled;
				evalops.parse_options.units_enabled = true;
				AutoPostConversion save_auto_post_conversion = evalops.auto_post_conversion;
				evalops.auto_post_conversion = POST_CONVERSION_OPTIMAL_SI;
				execute_expression(force, do_mathoperation, op, f, do_stack, stack_index, from_str);
				evalops.auto_post_conversion = save_auto_post_conversion;
				evalops.parse_options.units_enabled = b_units_saved;
			}
			return;
		} else if(equalsIgnoreCase(to_str, "base") || equalsIgnoreCase(to_str, _("base"))) {
			b_busy = false;
			b_busy_expression = false;
			if(from_str.empty()) {
				executeCommand(COMMAND_CONVERT_BASE);
				set_previous_expression();
			} else {
				bool b_units_saved = evalops.parse_options.units_enabled;
				evalops.parse_options.units_enabled = true;
				AutoPostConversion save_auto_post_conversion = evalops.auto_post_conversion;
				evalops.auto_post_conversion = POST_CONVERSION_BASE;
				execute_expression(force, do_mathoperation, op, f, do_stack, stack_index, from_str);
				evalops.auto_post_conversion = save_auto_post_conversion;
				evalops.parse_options.units_enabled = b_units_saved;
			}
			return;
		} else if(!from_str.empty() && (equalsIgnoreCase(to_str, "mixed") || equalsIgnoreCase(to_str, _("mixed")))) {
			bool b_units_saved = evalops.parse_options.units_enabled;
			evalops.parse_options.units_enabled = true;
			AutoPostConversion save_auto_post_conversion = evalops.auto_post_conversion;
			MixedUnitsConversion save_mixed_units_conversion = evalops.mixed_units_conversion;
			evalops.auto_post_conversion = POST_CONVERSION_NONE;
			evalops.mixed_units_conversion = MIXED_UNITS_CONVERSION_FORCE_INTEGER;
			b_busy = false;
			b_busy_expression = false;
			execute_expression(force, do_mathoperation, op, f, do_stack, stack_index, from_str);
			evalops.auto_post_conversion = save_auto_post_conversion;
			evalops.mixed_units_conversion = save_mixed_units_conversion;
			evalops.parse_options.units_enabled = b_units_saved;
			return;
		} else if(equalsIgnoreCase(to_str, "fraction") || equalsIgnoreCase(to_str, _("fraction"))) {
			do_to = true;
			to_fraction = true;
		} else if(equalsIgnoreCase(to_str, "factors") || equalsIgnoreCase(to_str, _("factors")) || equalsIgnoreCase(to_str, "factor")) {
			if(from_str.empty()) {
				b_busy = false;
				b_busy_expression = false;
				executeCommand(COMMAND_FACTORIZE);
				set_previous_expression();
				return;
			}
			do_factors = true;
			execute_str = from_str;
		} else if(equalsIgnoreCase(to_str, "partial fraction") || equalsIgnoreCase(to_str, _("partial fraction"))) {
			if(from_str.empty()) {
				b_busy = false;
				b_busy_expression = false;
				executeCommand(COMMAND_EXPAND_PARTIAL_FRACTIONS);
				set_previous_expression();
				return;
			}
			do_pfe = true;
			execute_str = from_str;
		} else if(equalsIgnoreCase(to_str1, "base") || equalsIgnoreCase(to_str1, _("base"))) {
			if(equalsIgnoreCase(to_str2, "golden") || equalsIgnoreCase(to_str2, "golden ratio") || to_str2 == "φ") to_base = BASE_GOLDEN_RATIO;
			else if(to_str2 == "b26" || to_str2 == "B26") to_base = BASE_BIJECTIVE_26;
			else if(equalsIgnoreCase(to_str2, "unicode")) to_base = BASE_UNICODE;
			else if(equalsIgnoreCase(to_str2, "supergolden") || equalsIgnoreCase(to_str2, "supergolden ratio") || to_str2 == "ψ") to_base = BASE_SUPER_GOLDEN_RATIO;
			else if(equalsIgnoreCase(to_str2, "pi") || to_str2 == "π") to_base = BASE_PI;
			else if(to_str2 == "e") to_base = BASE_E;
			else if(to_str2 == "sqrt(2)" || to_str2 == "sqrt 2" || to_str2 == "sqrt2" || to_str2 == "√2") to_base = BASE_SQRT2;
			else {
				EvaluationOptions eo = evalops;
				eo.parse_options.base = 10;
				MathStructure m;
				eo.approximation = APPROXIMATION_TRY_EXACT;
				CALCULATOR->beginTemporaryStopMessages();
				CALCULATOR->calculate(&m, CALCULATOR->unlocalizeExpression(to_str2, eo.parse_options), 500, eo);
				if(CALCULATOR->endTemporaryStopMessages()) {
					to_base = BASE_CUSTOM;
					to_nbase.clear();
				} else if(m.isInteger() && m.number() >= 2 && m.number() <= 36) {
					to_base = m.number().intValue();
				} else {
					to_base = BASE_CUSTOM;
					to_nbase = m.number();
				}
			}
			do_to = true;
		} else if(from_str.empty()) {
			b_busy = false;
			b_busy_expression = false;
			executeCommand(COMMAND_CONVERT_STRING, true, to_str);
			set_previous_expression();
			return;
		} else {
			if(to_str[0] == '?') {
				do_to = true;
				to_prefix = 1;
			} else if(to_str.length() > 1 && to_str[1] == '?' && (to_str[0] == 'b' || to_str[0] == 'a' || to_str[0] == 'd')) {
				to_prefix = to_str[0];
				do_to = true;
				
			}
			if(do_to && from_str.empty()) {
				b_busy = false;
				b_busy_expression = false;
				setResult(NULL, true, false, false);
				set_previous_expression();
				return;
			}
			do_to = false;
			do_conv = true;
		}
		if(do_to) {
			if(from_str.empty()) {
				b_busy = false;
				b_busy_expression = false;
				setResult(NULL, true, false, false);
				set_previous_expression();
				return;
			} else {
				execute_str = from_str;
			}
		}
	} else if(execute_str.empty()) {
		size_t i = str.find_first_of(SPACES LEFT_PARENTHESIS);
		if(i != string::npos) {
			to_str = str.substr(0, i);
			if(to_str == "factor" || equalsIgnoreCase(to_str, "factorize") || equalsIgnoreCase(to_str, _("factorize"))) {
				execute_str = str.substr(i + 1);
				do_factors = true;
			} else if(equalsIgnoreCase(to_str, "expand") || equalsIgnoreCase(to_str, _("expand"))) {
				execute_str = str.substr(i + 1);
				do_expand = true;
			}
		}
	}

	size_t stack_size = 0;
	
	
	update_expression_icons(EXPRESSION_STOP);

	if(execute_str.empty() && !do_conv && gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "convert_button_continuous_conversion")))) {
		string ceu_str = CALCULATOR->unlocalizeExpression(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(main_builder, "convert_entry_unit"))), evalops.parse_options);
		remove_blank_ends(ceu_str);
		if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "convert_button_set_missing_prefixes"))) && !ceu_str.empty()) {
			if(!ceu_str.empty() && ceu_str[0] != '0' && ceu_str[0] != '?' && ceu_str[0] != '+' && ceu_str[0] != '-' && (ceu_str.length() == 1 || ceu_str[1] != '?')) {
				ceu_str = "?" + ceu_str;
			}
		}
		if(ceu_str.empty()) {
			parsed_tostruct->setUndefined();
		} else {
			if(ceu_str[0] == '?') {
				to_prefix = 1;
			} else if(ceu_str.length() > 1 && ceu_str[1] == '?' && (ceu_str[0] == 'b' || ceu_str[0] == 'a' || ceu_str[0] == 'd')) {
				to_prefix = ceu_str[0];
			}
			parsed_tostruct->set(ceu_str);
		}
	} else {
		parsed_tostruct->setUndefined();
	}
	CALCULATOR->resetExchangeRatesUsed();
	if(do_stack) {
		stack_size = CALCULATOR->RPNStackSize();
		if(do_mathoperation && f) {
			CALCULATOR->getRPNRegister(stack_index + 1)->transform(f);
			parsed_mstruct->set(*CALCULATOR->getRPNRegister(stack_index + 1));
			CALCULATOR->calculateRPNRegister(stack_index + 1, 0, evalops);
		} else {
			CALCULATOR->setRPNRegister(stack_index + 1, CALCULATOR->unlocalizeExpression(execute_str.empty() ? str : execute_str, evalops.parse_options), 0, evalops, parsed_mstruct, parsed_tostruct);
		}
	} else if(rpn_mode) {
		stack_size = CALCULATOR->RPNStackSize();
		if(do_mathoperation) {
			if(mstruct) lastx = *mstruct;
			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_lastx")), TRUE);
			if(f) CALCULATOR->calculateRPN(f, 0, evalops, parsed_mstruct);
			else CALCULATOR->calculateRPN(op, 0, evalops, parsed_mstruct);
		} else {
			string str2 = CALCULATOR->unlocalizeExpression(execute_str.empty() ? str : execute_str, evalops.parse_options);
			CALCULATOR->parseSigns(str2);
			remove_blank_ends(str2);
			MathStructure lastx_bak(lastx);
			if(mstruct) lastx = *mstruct;
			if(str2.length() == 1) {
				do_mathoperation = true;
				switch(str2[0]) {
					case '^': {CALCULATOR->calculateRPN(OPERATION_RAISE, 0, evalops, parsed_mstruct); break;}
					case '+': {CALCULATOR->calculateRPN(OPERATION_ADD, 0, evalops, parsed_mstruct); break;}
					case '-': {CALCULATOR->calculateRPN(OPERATION_SUBTRACT, 0, evalops, parsed_mstruct); break;}
					case '*': {CALCULATOR->calculateRPN(OPERATION_MULTIPLY, 0, evalops, parsed_mstruct); break;}
					case '/': {CALCULATOR->calculateRPN(OPERATION_DIVIDE, 0, evalops, parsed_mstruct); break;}
					case '&': {CALCULATOR->calculateRPN(OPERATION_BITWISE_AND, 0, evalops, parsed_mstruct); break;}
					case '|': {CALCULATOR->calculateRPN(OPERATION_BITWISE_OR, 0, evalops, parsed_mstruct); break;}
					case '~': {CALCULATOR->calculateRPNBitwiseNot(0, evalops, parsed_mstruct); break;}
					case '!': {CALCULATOR->calculateRPN(CALCULATOR->f_factorial, 0, evalops, parsed_mstruct); break;}
					case '>': {CALCULATOR->calculateRPN(OPERATION_GREATER, 0, evalops, parsed_mstruct); break;}
					case '<': {CALCULATOR->calculateRPN(OPERATION_LESS, 0, evalops, parsed_mstruct); break;}
					case '=': {CALCULATOR->calculateRPN(OPERATION_EQUALS, 0, evalops, parsed_mstruct); break;}
					case '\\': {
						MathFunction *fdiv = CALCULATOR->getActiveFunction("div");
						if(fdiv) {
							CALCULATOR->calculateRPN(fdiv, 0, evalops, parsed_mstruct);
							break;
						}
					}
					default: {do_mathoperation = false;}
				}
			} else if(str2.length() == 2) {
				if(str2 == "**") {
					CALCULATOR->calculateRPN(OPERATION_RAISE, 0, evalops, parsed_mstruct);
					do_mathoperation = true;
				} else if(str2 == "!!") {
					CALCULATOR->calculateRPN(CALCULATOR->f_factorial2, 0, evalops, parsed_mstruct);
					do_mathoperation = true;
				} else if(str2 == "!=" || str == "=!" || str == "<>") {
					CALCULATOR->calculateRPN(OPERATION_NOT_EQUALS, 0, evalops, parsed_mstruct);
					do_mathoperation = true;
				} else if(str2 == "<=" || str == "=<") {
					CALCULATOR->calculateRPN(OPERATION_EQUALS_LESS, 0, evalops, parsed_mstruct);
					do_mathoperation = true;
				} else if(str2 == ">=" || str == "=>") {
					CALCULATOR->calculateRPN(OPERATION_EQUALS_GREATER, 0, evalops, parsed_mstruct);
					do_mathoperation = true;
				} else if(str2 == "==") {
					CALCULATOR->calculateRPN(OPERATION_EQUALS, 0, evalops, parsed_mstruct);
					do_mathoperation = true;
				} else if(str2 == "//") {
					MathFunction *fdiv = CALCULATOR->getActiveFunction("div");
					if(fdiv) {
						CALCULATOR->calculateRPN(fdiv, 0, evalops, parsed_mstruct);
						do_mathoperation = true;
					}
				}
			} else if(str2.length() == 3) {
				if(str2 == "⊻") {
					CALCULATOR->calculateRPN(OPERATION_BITWISE_XOR, 0, evalops, parsed_mstruct);
					do_mathoperation = true;
				}
			}
			if(!do_mathoperation) {
				bool had_nonnum = false, test_function = true;
				int in_par = 0;
				for(size_t i = 0; i < str2.length(); i++) {
					if(is_in(NUMBERS, str2[i])) {
						if(!had_nonnum || in_par) {
							test_function = false;
							break;
						}
					} else if(str2[i] == '(') {
						if(in_par || !had_nonnum) {
							test_function = false;
							break;
						}
						in_par = i;
					} else if(str2[i] == ')') {
						if(i != str2.length() - 1) {
							test_function = false;
							break;
						}
					} else if(str2[i] == ' ') {
						if(!in_par) {
							test_function = false;
							break;
						}
					} else if(is_in(NOT_IN_NAMES, str2[i])) {
						test_function = false;
						break;
					} else {
						if(in_par) {
							test_function = false;
							break;
						}
						had_nonnum = true;
					}
				}
				f = NULL;
				if(test_function) {
					if(in_par) f = CALCULATOR->getActiveFunction(str2.substr(0, in_par));
					else f = CALCULATOR->getActiveFunction(str2);
				}
				if(f && f->minargs() > 0) {
					do_mathoperation = true;
					CALCULATOR->calculateRPN(f, 0, evalops, parsed_mstruct);
				} else {
					CALCULATOR->RPNStackEnter(str2, 0, evalops, parsed_mstruct, parsed_tostruct);
				}
				if(do_mathoperation) gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_lastx")), TRUE);
				else lastx = lastx_bak;
			}
		}
	} else {
		CALCULATOR->calculate(mstruct, CALCULATOR->unlocalizeExpression(execute_str.empty() ? str : execute_str, evalops.parse_options), 0, evalops, parsed_mstruct, parsed_tostruct);
		result_autocalculated = false;
	}

	int i = 0;
	while(CALCULATOR->busy() && i < 50) {
		sleep_ms(10);
		i++;
	}
	i = 0;
	//GtkWidget *dialog = NULL;
	bool title_set = FALSE;
	//bool progress_set = FALSE;
	if(CALCULATOR->busy()) {
		gtk_window_set_title(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), _("Calculating…"));
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "menubar")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "buttons")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "convert")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "historyview")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "historyactions")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "rpntab")), FALSE);
		update_expression_icons(EXPRESSION_SPINNER);
		gtk_spinner_start(GTK_SPINNER(gtk_builder_get_object(main_builder, "expressionspinner")));
		g_application_mark_busy(g_application_get_default());
		title_set = TRUE;
	}
	while(CALCULATOR->busy()) {
		while(gtk_events_pending()) gtk_main_iteration();
		sleep_ms(100);
	}
	update_expression_icons();
	if(title_set) {
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "menubar")), TRUE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "buttons")), TRUE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "convert")), TRUE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "historyview")), TRUE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "historyactions")), TRUE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "rpntab")), TRUE);
		gtk_window_set_title(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), _("Qalculate!"));
		gtk_spinner_stop(GTK_SPINNER(gtk_builder_get_object(main_builder, "expressionspinner")));
		g_application_unmark_busy(g_application_get_default());
	}

	b_busy = false;
	b_busy_expression = false;
	
	if(rpn_mode && (!do_stack || stack_index == 0)) {
		mstruct->unref();
		mstruct = CALCULATOR->getRPNRegister(1);
		if(!mstruct) mstruct = new MathStructure();
		else mstruct->ref();
	}
	
	//update "ans" variables
	if(!do_stack || stack_index == 0) {
		MathStructure m4(vans[3]->get());
		m4.replace(vans[4], vans[4]->get());
		vans[4]->set(m4);
		MathStructure m3(vans[2]->get());
		m3.replace(vans[3], vans[4]);
		vans[3]->set(m3);
		MathStructure m2(vans[1]->get());
		m2.replace(vans[2], vans[3]);
		vans[2]->set(m2);
		MathStructure m1(vans[0]->get());
		m1.replace(vans[1], vans[2]);
		vans[1]->set(m1);
		mstruct->replace(vans[0], vans[1]);
		vans[0]->set(*mstruct);
	}
	
	if(do_stack && stack_index > 0) {
	} else if(rpn_mode && do_mathoperation) {
		result_text = _("RPN Operation");
	} else {
		result_text = str;
	}
	printops.allow_factorization = (evalops.structuring == STRUCTURING_FACTORIZE);
	if(rpn_mode && (!do_stack || stack_index == 0)) {
		clear_expression_text();
		while(CALCULATOR->RPNStackSize() < stack_size) {
			RPNRegisterRemoved(1);
			stack_size--;
		}
		if(CALCULATOR->RPNStackSize() > stack_size) {
			RPNRegisterAdded("");
		}
	}
	
	
	if(rpn_mode && do_mathoperation && parsed_tostruct && !parsed_tostruct->isUndefined() && parsed_tostruct->isSymbolic()) {
		mstruct->set(CALCULATOR->convert(*mstruct, parsed_tostruct->symbol(), evalops));
	}
	
	if(!do_mathoperation && check_exrates && check_exchange_rates(NULL, (!do_stack || stack_index == 0) && !do_pfe && !do_factors && !do_expand)) {
		execute_expression(force, do_mathoperation, op, f, rpn_mode, do_stack ? stack_index : 0, saved_execute_str, str, false);
		return;
	}
	
	if(do_factors || do_pfe || do_expand) {
		if(do_stack && stack_index != 0) {
			MathStructure *save_mstruct = mstruct;
			mstruct = CALCULATOR->getRPNRegister(stack_index + 1);
			executeCommand(do_pfe ? COMMAND_EXPAND_PARTIAL_FRACTIONS : (do_expand ? COMMAND_EXPAND : COMMAND_FACTORIZE), false);
			mstruct = save_mstruct;
		} else {
			executeCommand(do_pfe ? COMMAND_EXPAND_PARTIAL_FRACTIONS  : (do_expand ? COMMAND_EXPAND : COMMAND_FACTORIZE), false);
		}
	}
	if(!do_stack) previous_expression = execute_str.empty() ? str : execute_str;
	setResult(NULL, true, !do_stack || stack_index == 0, true, "", do_stack ? stack_index : 0);

	if(!do_stack || stack_index == 0) {
		if(!block_conversion_category_switch) {
			Unit *u = CALCULATOR->findMatchingUnit(*mstruct);
			if(u && !u->category().empty()) {
				string s_cat = u->category();
				if(s_cat.empty()) s_cat = _("Uncategorized");
				if(s_cat != selected_unit_category) {
					GtkTreeIter iter = convert_category_map[s_cat];
					GtkTreePath *path = gtk_tree_model_get_path(gtk_tree_view_get_model(GTK_TREE_VIEW(tUnitSelectorCategories)), &iter);
					gtk_tree_view_expand_to_path(GTK_TREE_VIEW(tUnitSelectorCategories), path);
					gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(tUnitSelectorCategories), path, NULL, TRUE, 0.5, 0);
					gtk_tree_path_free(path);
					gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitSelectorCategories)), &iter);
				}
			}
			if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "convert_button_continuous_conversion")))) {
				gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitSelector)));
			}
		}
		gtk_widget_grab_focus(expressiontext);
		GtkTextIter istart, iend;
		gtk_text_buffer_get_start_iter(expressionbuffer, &istart);
		gtk_text_buffer_get_end_iter(expressionbuffer, &iend);
		gtk_text_buffer_select_range(expressionbuffer, &istart, &iend);
		gtk_text_buffer_remove_tag(expressionbuffer, expression_par_tag, &istart, &iend);

	}
	do_timeout = true;

}
void set_rpn_mode(bool b) {
	if(b == rpn_mode) return;
	rpn_mode = b;
	update_expression_icons();
	if(rpn_mode) {
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_equals")), _("Ent"));
		gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_equals")), _("Calculate expression and add to stack"));
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "expression_button_equals")), _("Ent"));
		gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(main_builder, "expression_button")), _("Calculate expression and add to stack"));
		gtk_widget_show(expander_stack);
		show_history = gtk_expander_get_expanded(GTK_EXPANDER(expander_history));
		show_keypad = gtk_expander_get_expanded(GTK_EXPANDER(expander_keypad));
		show_convert = gtk_expander_get_expanded(GTK_EXPANDER(expander_convert));
		if(show_stack) {
			gtk_expander_set_expanded(GTK_EXPANDER(expander_stack), TRUE);
		}
		expression_has_changed = true;
		expression_has_changed2 = true;
		expression_history_index = -1;
		clearresult();
		if(auto_calculate) {
			g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_autocalc"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_autocalc_activate, NULL);
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_autocalc")), FALSE);
			g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_autocalc"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_autocalc_activate, NULL);
		}
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "menu_item_autocalc")), FALSE);
	} else {
		gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "label_equals")), "<big>=</big>");
		gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_equals")), _("Calculate expression"));
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "expression_button_equals")), _("="));
		gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(main_builder, "expression_button")), _("Calculate expression"));
		gtk_widget_hide(expander_stack);
		show_stack = gtk_expander_get_expanded(GTK_EXPANDER(expander_stack));
		if(show_stack) {
			if(show_history) gtk_expander_set_expanded(GTK_EXPANDER(expander_history), TRUE);
			else if(show_keypad) gtk_expander_set_expanded(GTK_EXPANDER(expander_keypad), TRUE);
			else if(show_convert) gtk_expander_set_expanded(GTK_EXPANDER(expander_convert), TRUE);
			else gtk_expander_set_expanded(GTK_EXPANDER(expander_stack), FALSE);
		}
		CALCULATOR->clearRPNStack();
		g_signal_handlers_block_matched((gpointer) stackstore, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_stackstore_row_deleted, NULL);
		gtk_list_store_clear(stackstore);
		g_signal_handlers_unblock_matched((gpointer) stackstore, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_stackstore_row_deleted, NULL);
		clearresult();
		if(auto_calculate) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_autocalc")), auto_calculate);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "menu_item_autocalc")), TRUE);
	}
}

void updateRPNIndexes() {
	GtkTreeIter iter;
	if(!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(stackstore), &iter)) return;
	for(int i = 1; ; i++) {
		gtk_list_store_set(stackstore, &iter, 0, i2s(i).c_str(), -1);
		if(!gtk_tree_model_iter_next(GTK_TREE_MODEL(stackstore), &iter)) break;
	}
}

void calculateRPN(int op) {
	if(expression_has_changed) {
		if(get_expression_text().find_first_not_of(SPACES) != string::npos) {
			execute_expression(true);
		}
	}
	execute_expression(true, true, (MathOperation) op, NULL);
}
void calculateRPN(MathFunction *f) {
	if(expression_has_changed) {
		if(get_expression_text().find_first_not_of(SPACES) != string::npos) {
			execute_expression(true);
		}
	}
	execute_expression(true, true, OPERATION_ADD, f);
}
void RPNRegisterAdded(string text, gint index) {
	GtkTreeIter iter;
	g_signal_handlers_block_matched((gpointer) stackstore, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_stackstore_row_inserted, NULL);
	gtk_list_store_insert(stackstore, &iter, index);
	g_signal_handlers_unblock_matched((gpointer) stackstore, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_stackstore_row_inserted, NULL);
	gtk_list_store_set(stackstore, &iter, 0, i2s(index + 1).c_str(), 1, text.c_str(), -1);
	updateRPNIndexes();
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_clearstack")), TRUE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_copyregister")), TRUE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_deleteregister")), TRUE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_sqrt")), TRUE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_reciprocal")), TRUE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_negate")), TRUE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_add")), TRUE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_sub")), TRUE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_times")), TRUE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_divide")), TRUE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_xy")), TRUE);
	if(CALCULATOR->RPNStackSize() >= 2) {
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_registerdown")), TRUE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_registerup")), TRUE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_registerswap")), TRUE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_sum")), TRUE);
	}
	on_stackview_selection_changed(gtk_tree_view_get_selection(GTK_TREE_VIEW(stackview)), NULL);
}
void RPNRegisterRemoved(gint index) {
	GtkTreeIter iter;
	gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(stackstore), &iter, NULL, index);
	g_signal_handlers_block_matched((gpointer) stackstore, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_stackstore_row_deleted, NULL);
	gtk_list_store_remove(stackstore, &iter);
	g_signal_handlers_unblock_matched((gpointer) stackstore, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_stackstore_row_deleted, NULL);
	updateRPNIndexes();
	if(CALCULATOR->RPNStackSize() == 0) {
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_clearstack")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_copyregister")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_deleteregister")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_sqrt")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_reciprocal")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_negate")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_add")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_sub")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_times")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_divide")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_xy")), FALSE);
	}
	if(CALCULATOR->RPNStackSize() < 2) {
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_registerdown")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_registerup")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_registerswap")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_sum")), FALSE);
	}
	on_stackview_selection_changed(gtk_tree_view_get_selection(GTK_TREE_VIEW(stackview)), NULL);
}
void RPNRegisterChanged(string text, gint index) {
	GtkTreeIter iter;
	gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(stackstore), &iter, NULL, index);
	gtk_list_store_set(stackstore, &iter, 1, text.c_str(), -1);
}

/*
	general function used to insert text in expression entry
*/
void insert_text(const gchar *name) {
	if(b_busy) return;
	block_completion();
	overwrite_expression_selection(name);
	if(!gtk_widget_is_focus(expressiontext)) {
		gtk_widget_grab_focus(expressiontext);
	}
	unblock_completion();
}

void recreate_recent_functions() {
	GtkWidget *item, *sub;
	sub = f_menu;
	recent_function_items.clear();
	bool b = false;
	for(size_t i = 0; i < recent_functions.size(); i++) {
		if(!CALCULATOR->stillHasFunction(recent_functions[i])) {
			recent_functions.erase(recent_functions.begin() + i);
			i--;
		} else {
			if(!b) {
				MENU_SEPARATOR_PREPEND
				b = true;
			}
			item = gtk_menu_item_new_with_label(recent_functions[i]->title(true).c_str()); 
			recent_function_items.push_back(item);
			gtk_widget_show(item); 
			gtk_menu_shell_prepend(GTK_MENU_SHELL(sub), item);
			g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(insert_function), (gpointer) recent_functions[i]);
		}
	}
	update_mb_fx_menu();
}
void recreate_recent_variables() {
	GtkWidget *item, *sub;
	sub = v_menu;
	recent_variable_items.clear();
	bool b = false;
	for(size_t i = 0; i < recent_variables.size(); i++) {
		if(!CALCULATOR->stillHasVariable(recent_variables[i])) {
			recent_variables.erase(recent_variables.begin() + i);
			i--;
		} else {
			if(!b) {
				MENU_SEPARATOR_PREPEND
				b = true;
			}
			item = gtk_menu_item_new_with_label(recent_variables[i]->title(true).c_str()); 
			recent_variable_items.push_back(item);
			gtk_widget_show(item); 
			gtk_menu_shell_prepend(GTK_MENU_SHELL(sub), item);
			g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(insert_variable), (gpointer) recent_variables[i]);
		}
	}
	update_mb_pi_menu();
}
void recreate_recent_units() {
	GtkWidget *item, *sub;
	sub = u_menu;
	recent_unit_items.clear();
	bool b = false;
	for(size_t i = 0; i < recent_units.size(); i++) {
		if(!CALCULATOR->stillHasUnit(recent_units[i])) {
			recent_units.erase(recent_units.begin() + i);
			i--;
		} else {
			if(!b) {
				MENU_SEPARATOR_PREPEND
				b = true;
			}
			item = gtk_menu_item_new_with_label(recent_units[i]->title(true).c_str()); 
			recent_unit_items.push_back(item);
			gtk_widget_show(item); 
			gtk_menu_shell_prepend(GTK_MENU_SHELL(sub), item);
			g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(insert_unit), (gpointer) recent_units[i]);
		}
	}
	update_mb_units_menu();
}

void function_inserted(MathFunction *object) {
	if(!object) {
		return;
	}
	GtkWidget *item, *sub;
	sub = f_menu;
	if(recent_function_items.size() <= 0) {
		MENU_SEPARATOR_PREPEND
	}
	for(size_t i = 0; i < recent_functions.size(); i++) {
		if(recent_functions[i] == object) {
			recent_functions.erase(recent_functions.begin() + i);
			gtk_widget_destroy(recent_function_items[i]);
			recent_function_items.erase(recent_function_items.begin() + i);
			break;
		}
	}
	if(recent_function_items.size() >= 5) {
		recent_functions.erase(recent_functions.begin());
		gtk_widget_destroy(recent_function_items[0]);
		recent_function_items.erase(recent_function_items.begin());
	}
	item = gtk_menu_item_new_with_label(object->title(true).c_str()); 
	recent_function_items.push_back(item);
	recent_functions.push_back(object);
	gtk_widget_show(item); 
	gtk_menu_shell_prepend(GTK_MENU_SHELL(sub), item);
	g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(insert_function), (gpointer) object);
	update_mb_fx_menu();
}
void variable_inserted(Variable *object) {
	if(!object) {
		return;
	}
	GtkWidget *item, *sub;
	sub = v_menu;
	if(recent_variable_items.size() <= 0) {
		MENU_SEPARATOR_PREPEND
	}
	for(size_t i = 0; i < recent_variables.size(); i++) {
		if(recent_variables[i] == object) {
			recent_variables.erase(recent_variables.begin() + i);
			gtk_widget_destroy(recent_variable_items[i]);
			recent_variable_items.erase(recent_variable_items.begin() + i);
			break;
		}
	}
	if(recent_variable_items.size() >= 5) {
		recent_variables.erase(recent_variables.begin());
		gtk_widget_destroy(recent_variable_items[0]);
		recent_variable_items.erase(recent_variable_items.begin());
	}
	item = gtk_menu_item_new_with_label(object->title(true).c_str()); 
	recent_variable_items.push_back(item);
	recent_variables.push_back(object);
	gtk_widget_show(item); 
	gtk_menu_shell_prepend(GTK_MENU_SHELL(sub), item);
	g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(insert_variable), (gpointer) object);
	update_mb_pi_menu();
}
void unit_inserted(Unit *object) {
	if(!object) {
		return;
	}
	GtkWidget *item, *sub;
	sub = u_menu;
	if(recent_unit_items.size() <= 0) {
		MENU_SEPARATOR_PREPEND
	}
	for(size_t i = 0; i < recent_units.size(); i++) {
		if(recent_units[i] == object) {
			recent_units.erase(recent_units.begin() + i);
			gtk_widget_destroy(recent_unit_items[i]);
			recent_unit_items.erase(recent_unit_items.begin() + i);
			break;
		}
	}
	if(recent_unit_items.size() >= 5) {
		recent_units.erase(recent_units.begin());
		gtk_widget_destroy(recent_unit_items[0]);
		recent_unit_items.erase(recent_unit_items.begin());
	}
	item = gtk_menu_item_new_with_label(object->title(true).c_str()); 
	recent_unit_items.push_back(item);
	recent_units.push_back(object);
	gtk_widget_show(item); 
	gtk_menu_shell_prepend(GTK_MENU_SHELL(sub), item);
	g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(insert_unit), (gpointer) object);
	update_mb_units_menu();
}

void apply_function(MathFunction *f, GtkWidget* = NULL) {
	if(b_busy) return;
	if(rpn_mode) {
		calculateRPN(f);
		return;
	}
	string str = f->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressionbuffer).name;
	if(f->args() == 0) {
		str += "()";
	} else {
		str += "(";
		str += get_expression_text();
		str += ")";
	}
	add_to_undo = false;
	gtk_text_buffer_set_text(expressionbuffer, "", -1);
	add_to_undo = true;
	insert_text(str.c_str());
	execute_expression();
	function_inserted(f);
}

gint on_function_int_input(GtkSpinButton *entry, gpointer new_value, gpointer) {
	string str = gtk_entry_get_text(GTK_ENTRY(entry));
	remove_blank_ends(str);
	if(str.find_first_not_of(NUMBERS) != string::npos) {
		MathStructure value;
		CALCULATOR->beginTemporaryStopMessages();
		CALCULATOR->calculate(&value, CALCULATOR->unlocalizeExpression(str, evalops.parse_options), 200, evalops);
		CALCULATOR->endTemporaryStopMessages();
		if(!value.isNumber()) return GTK_INPUT_ERROR;
		bool overflow = false;
		*((gdouble*) new_value) = value.number().intValue(&overflow);
		if(overflow) return GTK_INPUT_ERROR;
		return TRUE;
	}
	return FALSE;
}

struct FunctionDialog {
	GtkWidget *dialog;
	GtkWidget *b_cancel, *b_exec, *b_insert, *b_keepopen, *w_result;
	vector<GtkWidget*> label;
	vector<GtkWidget*> entry;
	vector<GtkWidget*> type_label;
	vector<GtkWidget*> boolean_buttons;
	vector<int> boolean_index;
	GtkListStore *properties_store;
	bool add_to_menu, keep_open, rpn;
	int args;
};

unordered_map<MathFunction*, FunctionDialog*> function_dialogs;

void insert_function_do(MathFunction *f, FunctionDialog *fd) {
	string str = f->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext).name + "(", str2;
	
	int argcount = fd->args;
	if(f->maxargs() > 0 && f->minargs() < f->maxargs() && argcount > f->minargs()) {
		while(true) {
			string defstr = f->getDefaultValue(argcount);
			remove_blank_ends(defstr);
			if(f->getArgumentDefinition(argcount) && f->getArgumentDefinition(argcount)->type() == ARGUMENT_TYPE_BOOLEAN) {
				if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(fd->boolean_buttons[fd->boolean_index[argcount - 1]]))) {
					str2 = "1";
				} else {
					str2 = "0";
				}
			} else if(evalops.parse_options.base != BASE_DECIMAL && f->getArgumentDefinition(argcount) && f->getArgumentDefinition(argcount)->type() == ARGUMENT_TYPE_INTEGER) {
				Number nr(gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(fd->entry[argcount - 1])), 1);
				str2 = print_with_evalops(nr);
			} else if(fd->properties_store && f->getArgumentDefinition(argcount) && f->getArgumentDefinition(argcount)->type() == ARGUMENT_TYPE_DATA_PROPERTY) {
				GtkTreeIter iter;
				DataProperty *dp = NULL;
				if(gtk_combo_box_get_active_iter(GTK_COMBO_BOX(fd->entry[argcount - 1]), &iter)) {
					gtk_tree_model_get(GTK_TREE_MODEL(fd->properties_store), &iter, 1, &dp, -1);
				}	
				if(dp) {
					str2 = dp->getName();
				} else {
					str2 = "info";
				}
			} else {
				str2 = gtk_entry_get_text(GTK_ENTRY(fd->entry[argcount - 1]));
				remove_blank_ends(str2);
			}
			if(!str2.empty() && f->getArgumentDefinition(argcount) && (f->getArgumentDefinition(argcount)->suggestsQuotes() || (f->getArgumentDefinition(argcount)->type() == ARGUMENT_TYPE_TEXT && str2.find(CALCULATOR->getComma()) != string::npos))) {
				if(str2.length() < 1 || (str2[0] != '\"' && str[0] != '\'')) { 
					str2.insert(0, "\"");
					str2 += "\"";
				}
			}
			if(str2.empty() || str2 == defstr) argcount--;
			else break;
			if(argcount == 0 || argcount == f->minargs()) break;
		}
	}
			
	for(int i = 0; i < argcount; i++) {
		if(f->getArgumentDefinition(i + 1) && f->getArgumentDefinition(i + 1)->type() == ARGUMENT_TYPE_BOOLEAN) {
			if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(fd->boolean_buttons[fd->boolean_index[i]]))) {
				str2 = "1";
			} else {
				str2 = "0";
			}
		} else if(evalops.parse_options.base != BASE_DECIMAL && f->getArgumentDefinition(i + 1) && f->getArgumentDefinition(i + 1)->type() == ARGUMENT_TYPE_INTEGER) {
			Number nr(gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(fd->entry[i])), 1);
			str2 = print_with_evalops(nr);
		} else if(fd->properties_store && f->getArgumentDefinition(i + 1) && f->getArgumentDefinition(i + 1)->type() == ARGUMENT_TYPE_DATA_PROPERTY) {
			GtkTreeIter iter;
			DataProperty *dp = NULL;
			if(gtk_combo_box_get_active_iter(GTK_COMBO_BOX(fd->entry[i]), &iter)) {
				gtk_tree_model_get(GTK_TREE_MODEL(fd->properties_store), &iter, 1, &dp, -1);
			}	
			if(dp) {
				str2 = dp->getName();
			} else {
				str2 = "info";
			}
		} else {
			str2 = gtk_entry_get_text(GTK_ENTRY(fd->entry[i]));
			remove_blank_ends(str2);
		}
		if((i < f->minargs() || !str2.empty()) && f->getArgumentDefinition(i + 1) && (f->getArgumentDefinition(i + 1)->suggestsQuotes() || (f->getArgumentDefinition(i + 1)->type() == ARGUMENT_TYPE_TEXT && str2.find(CALCULATOR->getComma()) != string::npos))) {
			if(str2.length() < 1 || (str2[0] != '\"' && str[0] != '\'')) { 
				str2.insert(0, "\"");
				str2 += "\"";
			}
		}
		if(i > 0) {
			str += CALCULATOR->getComma();
			str += " ";
		}
		str += str2;
	}
	str += ")";
	insert_text(str.c_str());
	if(fd->add_to_menu) function_inserted(f);
}

void on_insert_function_delete(GtkWidget*, GdkEvent*, gpointer p) {
	MathFunction *f = (MathFunction*) p;
	FunctionDialog *fd = function_dialogs[f];
	gtk_widget_destroy(fd->dialog);
	delete fd;
	function_dialogs.erase(f);
}
void on_insert_function_close(GtkWidget*, gpointer p) {
	MathFunction *f = (MathFunction*) p;
	FunctionDialog *fd = function_dialogs[f];
	gtk_widget_destroy(fd->dialog);
	delete fd;
	function_dialogs.erase(f);
}
void on_insert_function_exec(GtkWidget*, gpointer p) {
	MathFunction *f = (MathFunction*) p;
	FunctionDialog *fd = function_dialogs[f];
	if(!fd->keep_open) gtk_widget_hide(fd->dialog);
	gtk_text_buffer_set_text(expressionbuffer, "", -1);
	insert_function_do(f, fd);
	execute_expression();
	if(fd->keep_open) {
		string str;
		bool b_approx = result_text_approximate || (mstruct && mstruct->isApproximate());
		if(!b_approx) {
			str = "=";
		} else {
			if(printops.use_unicode_signs && can_display_unicode_string_function(SIGN_ALMOST_EQUAL, (void*) historyview)) {
				str = SIGN_ALMOST_EQUAL;
			} else {
				str = "= ";
				str += _("approx.");
			}
		}
		str += " <span font-weight=\"bold\">";
		str += fix_history_string(result_text);
		str += "</span> ";
		gtk_label_set_markup(GTK_LABEL(fd->w_result), str.c_str());
		gtk_widget_grab_focus(fd->entry[0]);
	} else {
		gtk_widget_destroy(fd->dialog);
		delete fd;
		function_dialogs.erase(f);
	}
}
void on_insert_function_insert(GtkWidget*, gpointer p) {
	MathFunction *f = (MathFunction*) p;
	FunctionDialog *fd = function_dialogs[f];
	if(!fd->keep_open) gtk_widget_hide(fd->dialog);
	insert_function_do(f, fd);
	if(fd->keep_open) {
		gtk_widget_grab_focus(fd->entry[0]);
	} else {
		gtk_widget_destroy(fd->dialog);
		delete fd;
		function_dialogs.erase(f);
	}
}
void on_insert_function_rpn(GtkWidget *w, gpointer p) {
	MathFunction *f = (MathFunction*) p;
	FunctionDialog *fd = function_dialogs[f];
	if(!fd->keep_open) gtk_widget_hide(fd->dialog);
	calculateRPN(f);
	if(fd->add_to_menu) function_inserted(f);
	if(fd->keep_open) {
		gtk_widget_grab_focus(fd->entry[0]);
	} else {
		gtk_widget_destroy(fd->dialog);
		delete fd;
		function_dialogs.erase(f);
	}
}
void on_insert_function_keepopen(GtkToggleButton *w, gpointer p) {
	MathFunction *f = (MathFunction*) p;
	FunctionDialog *fd = function_dialogs[f];
	fd->keep_open = gtk_toggle_button_get_active(w);
	keep_function_dialog_open = fd->keep_open;
}
void on_insert_function_changed(GtkWidget *w, gpointer p) {
	MathFunction *f = (MathFunction*) p;
	FunctionDialog *fd = function_dialogs[f];
	gtk_label_set_text(GTK_LABEL(fd->w_result), "");
}
void on_insert_function_entry_activated(GtkWidget *w, gpointer p) {
	MathFunction *f = (MathFunction*) p;
	FunctionDialog *fd = function_dialogs[f];
	for(int i = 0; i < fd->args; i++) {
		if(fd->entry[i] == w) {
			if(i == fd->args - 1) {
				if(fd->rpn) on_insert_function_rpn(w, p);
				else if(fd->keep_open || rpn_mode) on_insert_function_exec(w, p);
				else on_insert_function_insert(w, p);
			} else {
				if(f->getArgumentDefinition(i + 2) && f->getArgumentDefinition(i + 2)->type() == ARGUMENT_TYPE_BOOLEAN) {
					gtk_widget_grab_focus(fd->boolean_buttons[fd->boolean_index[i + 1]]);
				} else {
					gtk_widget_grab_focus(fd->entry[i + 1]);
				}
			}
			break;
		}
	}
	
}

/*
	insert function
	pops up an argument entry dialog and inserts function into expression entry
	parent is parent window
*/
void insert_function(MathFunction *f, GtkWidget *parent = NULL, bool add_to_menu = true) {
	if(!f) {
		return;
	}
	
	//if function takes no arguments, do not display dialog and insert function directly
	if(f->args() == 0) {
		string str = f->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext).name + "()";
		gchar *gstr = g_strdup(str.c_str());
		function_inserted(f);
		insert_text(gstr);
		g_free(gstr);
		return;
	}
	
	GtkTextIter istart, iend;
	gtk_text_buffer_get_selection_bounds(expressionbuffer, &istart, &iend);
	
	if(function_dialogs.find(f) != function_dialogs.end()) {
		FunctionDialog *fd = function_dialogs[f];
		if(fd->args > 0) {
			Argument *arg = f->getArgumentDefinition(1);
			if(arg && arg->type() == ARGUMENT_TYPE_BOOLEAN) {
			} else if(fd->properties_store && arg && arg->type() == ARGUMENT_TYPE_DATA_PROPERTY) {
			} else {
				g_signal_handlers_block_matched((gpointer) fd->entry[0], G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_insert_function_changed, NULL);
				//insert selection in expression entry into the first argument entry
				gtk_entry_set_text(GTK_ENTRY(fd->entry[0]), get_selected_expression_text(true).c_str());
				if(arg && arg->type() == ARGUMENT_TYPE_INTEGER) {
					gtk_spin_button_update(GTK_SPIN_BUTTON(fd->entry[0]));
				}
				g_signal_handlers_unblock_matched((gpointer) fd->entry[0], G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_insert_function_changed, NULL);
			}
			gtk_widget_grab_focus(fd->entry[0]);
		}
		gtk_window_present(GTK_WINDOW(fd->dialog));
		return;
	}
	
	FunctionDialog *fd = new FunctionDialog;
	
	function_dialogs[f] = fd;
	
	int args = 0;
	bool has_vector = false;
	if(f->args() > 0) {
		args = f->args();
	} else if(f->minargs() > 0) {
		args = f->minargs() + 1;
		has_vector = true;
	} else {
		args = 1;
		has_vector = true;
	}
	fd->args = args;
	
	fd->rpn = rpn_mode && expression_is_empty() && CALCULATOR->RPNStackSize() >= (f->minargs() <= 0 ? 1 : (size_t) f->minargs());
	fd->add_to_menu = add_to_menu;
	
	string f_title = f->title(true);
	fd->dialog = gtk_dialog_new();
	gtk_window_set_title(GTK_WINDOW(fd->dialog), f_title.c_str());
	gtk_window_set_transient_for(GTK_WINDOW(fd->dialog), GTK_WINDOW(parent));
	gtk_window_set_destroy_with_parent(GTK_WINDOW(fd->dialog), TRUE);
	
	fd->b_keepopen = gtk_check_button_new_with_label(_("Keep open"));
	gtk_dialog_add_action_widget(GTK_DIALOG(fd->dialog), fd->b_keepopen, GTK_RESPONSE_NONE);
	fd->keep_open = keep_function_dialog_open;
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fd->b_keepopen), fd->keep_open);

	fd->b_cancel = gtk_button_new_with_mnemonic(_("_Close"));
	gtk_dialog_add_action_widget(GTK_DIALOG(fd->dialog), fd->b_cancel, GTK_RESPONSE_REJECT);

	fd->b_exec = gtk_button_new_with_mnemonic(rpn_mode ? _("Enter") : _("C_alculate"));
	gtk_dialog_add_action_widget(GTK_DIALOG(fd->dialog), fd->b_exec, GTK_RESPONSE_APPLY);

	fd->b_insert = gtk_button_new_with_mnemonic(rpn_mode ? _("Apply to Stack") : _("_Insert"));
	if(rpn_mode && CALCULATOR->RPNStackSize() < (f->minargs() <= 0 ? 1 : (size_t) f->minargs())) gtk_widget_set_sensitive(fd->b_insert, FALSE);
	gtk_dialog_add_action_widget(GTK_DIALOG(fd->dialog), fd->b_insert, GTK_RESPONSE_ACCEPT);

	gtk_container_set_border_width(GTK_CONTAINER(fd->dialog), 6);
	gtk_window_set_resizable(GTK_WINDOW(fd->dialog), FALSE);
	GtkWidget *vbox_pre = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12);
	gtk_container_set_border_width(GTK_CONTAINER(vbox_pre), 12);
	gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(fd->dialog))), vbox_pre);
	f_title.insert(0, "<b>");
	f_title += "</b>";
	GtkWidget *title_label = gtk_label_new(f_title.c_str());
	gtk_label_set_use_markup(GTK_LABEL(title_label), TRUE);
	gtk_widget_set_halign(title_label, GTK_ALIGN_START);

	gtk_container_add(GTK_CONTAINER(vbox_pre), title_label);

	GtkWidget *table = gtk_grid_new();
	gtk_grid_set_row_spacing(GTK_GRID(table), 6);
	gtk_grid_set_column_spacing(GTK_GRID(table), 12);
	gtk_container_add(GTK_CONTAINER(vbox_pre), table);
	gtk_widget_set_hexpand(table, TRUE);
	fd->label.resize(args, NULL);
	fd->entry.resize(args, NULL);
	fd->type_label.resize(args, NULL);
	fd->boolean_index.resize(args, 0);

	fd->w_result = gtk_label_new("");
	gtk_label_set_max_width_chars(GTK_LABEL(fd->w_result), 20);
	gtk_label_set_ellipsize(GTK_LABEL(fd->w_result), PANGO_ELLIPSIZE_MIDDLE);
	gtk_widget_set_hexpand(fd->w_result, TRUE);
	gtk_label_set_selectable(GTK_LABEL(fd->w_result), TRUE);

#if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 16
	gtk_label_set_xalign(GTK_LABEL(fd->w_result), 1.0);
#else
	gtk_misc_set_alignment(GTK_MISC(fd->w_result), 1.0, 0.5);
#endif 

	int bindex = 0;
	string argstr, typestr, defstr; 
	string argtype;
	Argument *arg;
	//create argument entries
	fd->properties_store = NULL;
	for(int i = 0; i < args; i++) {
		arg = f->getArgumentDefinition(i + 1);
		if(!arg || arg->name().empty()) {
			if(args == 1) {
				argstr = _("Value");
			} else {
				argstr = _("Argument");
				argstr += " ";
				argstr += i2s(i + 1);
			}
		} else {
			argstr = arg->name();
		}
		typestr = "";
		argtype = "";
		defstr = f->getDefaultValue(i + 1);
		if(arg && (arg->suggestsQuotes() || arg->type() == ARGUMENT_TYPE_TEXT) && defstr.length() >= 2 && defstr[0] == '\"' && defstr[defstr.length() - 1] == '\"') {
			defstr = defstr.substr(1, defstr.length() - 2);
		}
		fd->label[i] = gtk_label_new(argstr.c_str());
		gtk_widget_set_halign(fd->label[i], GTK_ALIGN_END);
		gtk_widget_set_hexpand(fd->label[i], FALSE);
		if(arg) {
			switch(arg->type()) {
				case ARGUMENT_TYPE_INTEGER: {
					IntegerArgument *iarg = (IntegerArgument*) arg;
					glong min = LONG_MIN, max = LONG_MAX;
					if(iarg->min()) {
						min = iarg->min()->lintValue();
					}
					if(iarg->max()) {
						max = iarg->max()->lintValue();
					}
					fd->entry[i] = gtk_spin_button_new_with_range(min, max, 1);
					gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(fd->entry[i]), evalops.parse_options.base != BASE_DECIMAL);
					gtk_entry_set_alignment(GTK_ENTRY(fd->entry[i]), 1.0);
					g_signal_connect(GTK_SPIN_BUTTON(fd->entry[i]), "input", G_CALLBACK(on_function_int_input), NULL);
					if(!f->getDefaultValue(i + 1).empty()) {
						gtk_spin_button_set_value(GTK_SPIN_BUTTON(fd->entry[i]), s2i(f->getDefaultValue(i + 1)));
					} else if(!arg->zeroForbidden() && min <= 0 && max >= 0) {
						gtk_spin_button_set_value(GTK_SPIN_BUTTON(fd->entry[i]), 0);
					} else {
						if(max < 0) {
							gtk_spin_button_set_value(GTK_SPIN_BUTTON(fd->entry[i]), max);
						} else if(min <= 1) {
							gtk_spin_button_set_value(GTK_SPIN_BUTTON(fd->entry[i]), 1);
						} else {
							gtk_spin_button_set_value(GTK_SPIN_BUTTON(fd->entry[i]), min);
						}
					}
					g_signal_connect((gpointer) fd->entry[i], "changed", G_CALLBACK(on_insert_function_changed), (gpointer) f);
					g_signal_connect((gpointer) fd->entry[i], "activate", G_CALLBACK(on_insert_function_entry_activated), (gpointer) f);
					break;
				}
				case ARGUMENT_TYPE_BOOLEAN: {
					fd->boolean_index[i] = bindex;
					bindex += 2;
					fd->entry[i] = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
					gtk_box_set_homogeneous(GTK_BOX(fd->entry[i]), TRUE);
					gtk_widget_set_halign(fd->entry[i], GTK_ALIGN_START);
					fd->boolean_buttons.push_back(gtk_radio_button_new_with_label(NULL, _("True")));
					gtk_box_pack_start(GTK_BOX(fd->entry[i]), fd->boolean_buttons[fd->boolean_buttons.size() - 1], TRUE, TRUE, 0);
					fd->boolean_buttons.push_back(gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(fd->boolean_buttons[fd->boolean_buttons.size() - 1]), _("False")));
					gtk_box_pack_end(GTK_BOX(fd->entry[i]), fd->boolean_buttons[fd->boolean_buttons.size() - 1], TRUE, TRUE, 0);
					gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fd->boolean_buttons[fd->boolean_buttons.size() - 1]), TRUE);
					g_signal_connect((gpointer) fd->boolean_buttons[fd->boolean_buttons.size() - 1], "toggled", G_CALLBACK(on_insert_function_changed), (gpointer) f);
					g_signal_connect((gpointer) fd->boolean_buttons[fd->boolean_buttons.size() - 2], "toggled", G_CALLBACK(on_insert_function_changed), (gpointer) f);
					break;
				}
				case ARGUMENT_TYPE_DATA_PROPERTY: {
					if(f->subtype() == SUBTYPE_DATA_SET) {
						fd->properties_store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_POINTER);
						gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(fd->properties_store), 0, string_sort_func, GINT_TO_POINTER(0), NULL);
						gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(fd->properties_store), 0, GTK_SORT_ASCENDING);
						fd->entry[i] = gtk_combo_box_new_with_model(GTK_TREE_MODEL(fd->properties_store));
						GtkCellRenderer *cell = gtk_cell_renderer_text_new();
						gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(fd->entry[i]), cell, TRUE);
						gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(fd->entry[i]), cell, "text", 0);
						DataPropertyIter it;
						DataSet *ds = (DataSet*) f;
						DataProperty *dp = ds->getFirstProperty(&it);
						GtkTreeIter iter;
						bool active_set = false;
						if(fd->rpn && (size_t) i < CALCULATOR->RPNStackSize()) {
							GtkTreeIter iter;
							if(gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(stackstore), &iter, NULL, i)) {
								gchar *gstr;
								gtk_tree_model_get(GTK_TREE_MODEL(stackstore), &iter, 1, &gstr, -1);
								defstr = gstr;
								g_free(gstr);
							}
						}
						while(dp) {
							if(!dp->isHidden()) {
								gtk_list_store_append(fd->properties_store, &iter);
								if(!active_set && defstr == dp->getName()) {
									gtk_combo_box_set_active_iter(GTK_COMBO_BOX(fd->entry[i]), &iter);
									active_set = true;
								}
								gtk_list_store_set(fd->properties_store, &iter, 0, dp->title().c_str(), 1, (gpointer) dp, -1);
							}
							dp = ds->getNextProperty(&it);
						}
						gtk_list_store_append(fd->properties_store, &iter);
						if(!active_set) {
							gtk_combo_box_set_active_iter(GTK_COMBO_BOX(fd->entry[i]), &iter);
						}
						gtk_list_store_set(fd->properties_store, &iter, 0, _("Info"), 1, (gpointer) NULL, -1);
						g_signal_connect((gpointer) fd->entry[i], "changed", G_CALLBACK(on_insert_function_changed), (gpointer) f);
						break;
					}
				}
				default: {
					argtype = arg->print();
					typestr = "";
					if(!argtype.empty()) {
						typestr = "(";
						typestr += argtype;
						typestr += ")";
					}
					fd->entry[i] = gtk_entry_new();
					if(i >= f->minargs() && !has_vector) {
						gtk_entry_set_placeholder_text(GTK_ENTRY(fd->entry[i]), _("optional"));
					}
					gtk_entry_set_alignment(GTK_ENTRY(fd->entry[i]), 1.0);
					g_signal_connect((gpointer) fd->entry[i], "changed", G_CALLBACK(on_insert_function_changed), (gpointer) f);
					g_signal_connect((gpointer) fd->entry[i], "activate", G_CALLBACK(on_insert_function_entry_activated), (gpointer) f);
				}
			}
		} else {
			fd->entry[i] = gtk_entry_new();
			if(i >= f->minargs() && !has_vector) {
				gtk_entry_set_placeholder_text(GTK_ENTRY(fd->entry[i]), _("optional"));
			}
			gtk_entry_set_alignment(GTK_ENTRY(fd->entry[i]), 1.0);
			g_signal_connect((gpointer) fd->entry[i], "changed", G_CALLBACK(on_insert_function_changed), (gpointer) f);
			g_signal_connect((gpointer) fd->entry[i], "activate", G_CALLBACK(on_insert_function_entry_activated), (gpointer) f);
		}
		gtk_widget_set_hexpand(fd->entry[i], TRUE);
		if(arg) {
			switch(arg->type()) {		
				case ARGUMENT_TYPE_DATE: {
					typestr = typestr.substr(1, typestr.length() - 2);
					fd->type_label[i] = gtk_button_new_with_label(typestr.c_str());
					g_signal_connect((gpointer) fd->type_label[i], "clicked", G_CALLBACK(on_type_label_date_clicked), (gpointer) fd->entry[i]);
					break;
				}
				case ARGUMENT_TYPE_FILE: {
					typestr = typestr.substr(1, typestr.length() - 2);
					fd->type_label[i] = gtk_button_new_with_label(typestr.c_str());
					g_signal_connect((gpointer) fd->type_label[i], "clicked", G_CALLBACK(on_type_label_file_clicked), (gpointer) fd->entry[i]);
					break;
				}
				default: {
					fd->type_label[i] = gtk_label_new(typestr.c_str());
				}
			}
		} else if(!typestr.empty()) {
			fd->type_label[i] = gtk_label_new(typestr.c_str());
		} else {
			fd->type_label[i] = NULL;
		}
		if(fd->rpn && (size_t) i < CALCULATOR->RPNStackSize()) {
			GtkTreeIter iter;
			if(gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(stackstore), &iter, NULL, i)) {
				gchar *gstr;
				gtk_tree_model_get(GTK_TREE_MODEL(stackstore), &iter, 1, &gstr, -1);
				if(arg && arg->type() == ARGUMENT_TYPE_BOOLEAN) {
					if(g_strcmp0(gstr, "1") == 0) {
						g_signal_handlers_block_matched((gpointer) fd->boolean_buttons[fd->boolean_buttons.size() - 2], G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_insert_function_changed, NULL);
						gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fd->boolean_buttons[fd->boolean_buttons.size() - 2]), TRUE);
						g_signal_handlers_unblock_matched((gpointer) fd->boolean_buttons[fd->boolean_buttons.size() - 2], G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_insert_function_changed, NULL);
					}
				} else if(fd->properties_store && arg && arg->type() == ARGUMENT_TYPE_DATA_PROPERTY) {
				} else {
					g_signal_handlers_block_matched((gpointer) fd->entry[i], G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_insert_function_changed, NULL);
					if(i == 0 && args == 1 && (has_vector || arg->type() == ARGUMENT_TYPE_VECTOR)) {
						string rpn_vector = gstr;
						while(gtk_tree_model_iter_next(GTK_TREE_MODEL(stackstore), &iter)) {
							g_free(gstr);
							gtk_tree_model_get(GTK_TREE_MODEL(stackstore), &iter, 1, &gstr, -1);
							rpn_vector += CALCULATOR->getComma();
							rpn_vector += " ";
							rpn_vector += gstr;
						}
						gtk_entry_set_text(GTK_ENTRY(fd->entry[i]), rpn_vector.c_str());
					} else {
						gtk_entry_set_text(GTK_ENTRY(fd->entry[i]), gstr);
						if(arg && arg->type() == ARGUMENT_TYPE_INTEGER) {
							gtk_spin_button_update(GTK_SPIN_BUTTON(fd->entry[i]));
						}
					}
					g_signal_handlers_unblock_matched((gpointer) fd->entry[i], G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_insert_function_changed, NULL);
				}
				g_free(gstr);
			}
		} else if(arg && arg->type() == ARGUMENT_TYPE_BOOLEAN) {
			if(defstr == "1") {
				g_signal_handlers_block_matched((gpointer) fd->boolean_buttons[fd->boolean_buttons.size() - 2], G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_insert_function_changed, NULL);
				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fd->boolean_buttons[fd->boolean_buttons.size() - 2]), TRUE);
				g_signal_handlers_unblock_matched((gpointer) fd->boolean_buttons[fd->boolean_buttons.size() - 2], G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_insert_function_changed, NULL);
			}
		} else if(fd->properties_store && arg && arg->type() == ARGUMENT_TYPE_DATA_PROPERTY) {
		} else {
			g_signal_handlers_block_matched((gpointer) fd->entry[i], G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_insert_function_changed, NULL);
			if(i < f->minargs() || has_vector || defstr != "undefined") gtk_entry_set_text(GTK_ENTRY(fd->entry[i]), defstr.c_str());
			//insert selection in expression entry into the first argument entry
			if(i == 0) {
				gtk_entry_set_text(GTK_ENTRY(fd->entry[i]), get_selected_expression_text(true).c_str());
				if(arg && arg->type() == ARGUMENT_TYPE_INTEGER) {
					gtk_spin_button_update(GTK_SPIN_BUTTON(fd->entry[i]));
				}
			}
			g_signal_handlers_unblock_matched((gpointer) fd->entry[i], G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_insert_function_changed, NULL);
		}
		gtk_grid_attach(GTK_GRID(table), fd->label[i], 0, i, 1, 1);
		gtk_grid_attach(GTK_GRID(table), fd->entry[i], 1, i, 1, 1);
		if(fd->type_label[i]) {
			gtk_widget_set_hexpand(fd->type_label[i], FALSE);
			gtk_widget_set_halign(fd->type_label[i], GTK_ALIGN_START);
			gtk_grid_attach(GTK_GRID(table), fd->type_label[i], 2, i, 1, 1);
		}
	}
	
	//display function description
	if(!f->description().empty() || !f->example(true).empty()) {
		GtkWidget *descr_frame = gtk_scrolled_window_new(NULL, NULL);
		gtk_container_add(GTK_CONTAINER(vbox_pre), descr_frame);
		gtk_container_add(GTK_CONTAINER(vbox_pre), fd->w_result);
		GtkWidget *descr = gtk_text_view_new();
		gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(descr), GTK_WRAP_WORD);
		gtk_text_view_set_editable(GTK_TEXT_VIEW(descr), FALSE);
		GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(descr));
		string str;
		if(!f->description().empty()) str += f->description();
		if(!f->example(true).empty()) {
			if(!str.empty()) str += "\n\n";
			str += _("Example:");
			str += " ";
			str += f->example(false);
		}
		gtk_text_buffer_set_text(buffer, str.c_str(), -1);
		gtk_container_add(GTK_CONTAINER(descr_frame), descr);
#if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 18
		gtk_text_view_set_left_margin(GTK_TEXT_VIEW(descr), 12);
		gtk_text_view_set_right_margin(GTK_TEXT_VIEW(descr), 12);
		gtk_text_view_set_top_margin(GTK_TEXT_VIEW(descr), 12);
		gtk_text_view_set_bottom_margin(GTK_TEXT_VIEW(descr), 12);
#else 
		gtk_text_view_set_left_margin(GTK_TEXT_VIEW(descr), 6);
		gtk_text_view_set_right_margin(GTK_TEXT_VIEW(descr), 6);
#endif
		gtk_widget_show_all(vbox_pre);
		gint nw, mw, nh, mh;
		gtk_widget_get_preferred_width(vbox_pre, &mw, &nw);
		gtk_widget_get_preferred_height(vbox_pre, &mh, &nh);
		PangoLayout *layout_test = gtk_widget_create_pango_layout(descr, NULL);
		pango_layout_set_text(layout_test, str.c_str(), -1);
		pango_layout_set_width(layout_test, (nw - 24) * PANGO_SCALE);
		pango_layout_set_wrap(layout_test, PANGO_WRAP_WORD);
		gint w, h;
		pango_layout_get_pixel_size(layout_test, &w, &h);
		h *= 1.2;
		if(h > nh) h = nh;
		if(h < 100) h = 100;
		gtk_widget_set_size_request(descr_frame, -1, h);
	} else {
		gtk_grid_attach(GTK_GRID(table), fd->w_result, 0, args, 2, 1);
	}
	
	g_signal_connect((gpointer) fd->b_exec, "clicked", G_CALLBACK(on_insert_function_exec), (gpointer) f);
	g_signal_connect((gpointer) fd->b_insert, "clicked", G_CALLBACK(on_insert_function_rpn), (gpointer) f);
	g_signal_connect((gpointer) fd->b_insert, "clicked", G_CALLBACK(on_insert_function_insert), (gpointer) f);
	g_signal_connect((gpointer) fd->b_cancel, "clicked", G_CALLBACK(on_insert_function_close), (gpointer) f);
	g_signal_connect((gpointer) fd->b_keepopen, "toggled", G_CALLBACK(on_insert_function_keepopen), (gpointer) f);
	g_signal_connect((gpointer) fd->dialog, "delete-event", G_CALLBACK(on_insert_function_delete), (gpointer) f);
	
	gtk_widget_show_all(fd->dialog);
	
	add_to_undo = false;
	gtk_text_buffer_select_range(expressionbuffer, &istart, &iend);
	add_to_undo = true;

}

/*
	called from function menu
*/
void insert_function(GtkMenuItem*, gpointer user_data) {
	if(!CALCULATOR->stillHasFunction((MathFunction*) user_data)) return;
	insert_function((MathFunction*) user_data, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")));
}

/*
	called from variable menu
	just insert text data stored in menu item
*/
void insert_variable(GtkMenuItem*, gpointer user_data) {
	Variable *v = (Variable*) user_data;
	if(!CALCULATOR->stillHasVariable(v)) {
		show_message(_("Variable does not exist anymore."), GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")));
		update_vmenu();
		return;
	}
	insert_text(v->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext).name.c_str());
	variable_inserted((Variable*) user_data);
}
void insert_var(Variable *v) {
	if(!CALCULATOR->stillHasVariable(v)) {
		show_message(_("Variable does not exist anymore."), GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")));
		return;
	}
	insert_text(v->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext).name.c_str());
}
void insert_button_variable(GtkWidget*, gpointer user_data) {
	insert_var((Variable*) user_data);
}

//from prefix menu
void insert_prefix(GtkMenuItem*, gpointer user_data) {
	insert_text(((Prefix*) user_data)->name(printops.abbreviate_names, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) expressiontext).c_str());
}
//from unit menu
void insert_unit(GtkMenuItem*, gpointer user_data) {
	if(!CALCULATOR->stillHasUnit((Unit*) user_data)) return;
	if(((Unit*) user_data)->subtype() == SUBTYPE_COMPOSITE_UNIT) {
		insert_text(((CompositeUnit*) user_data)->print(true, printops.abbreviate_names, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) expressiontext).c_str());
	} else {
		insert_text(((Unit*) user_data)->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, true, false, &can_display_unicode_string_function, (void*) expressiontext).name.c_str());
	}
	unit_inserted((Unit*) user_data);
}

void insert_button_unit(GtkMenuItem*, gpointer user_data) {
	if(!CALCULATOR->stillHasUnit((Unit*) user_data)) return;
	if(((Unit*) user_data)->subtype() == SUBTYPE_COMPOSITE_UNIT) {
		insert_text(((CompositeUnit*) user_data)->print(true, printops.abbreviate_names, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) expressiontext).c_str());
	} else {
		insert_text(((Unit*) user_data)->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, true, false, &can_display_unicode_string_function, (void*) expressiontext).name.c_str());
	}
	if((Unit*) user_data != latest_button_unit) {
		latest_button_unit = (Unit*) user_data;
		string si_label_str;
		if(((Unit*) user_data)->subtype() == SUBTYPE_COMPOSITE_UNIT) {
			si_label_str = ((CompositeUnit*) latest_button_unit)->print(false, true, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) expressiontext);
		} else {
		
			si_label_str = latest_button_unit->preferredDisplayName(true, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext).name;
		}
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_si")), si_label_str.c_str());
		gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(main_builder, "label_si")), latest_button_unit->title(true).c_str());
	}
}
void insert_button_currency(GtkMenuItem*, gpointer user_data) {
	if(!CALCULATOR->stillHasUnit((Unit*) user_data)) return;
	if(((Unit*) user_data)->subtype() == SUBTYPE_COMPOSITE_UNIT) {
		insert_text(((CompositeUnit*) user_data)->print(true, printops.abbreviate_names, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) expressiontext).c_str());
	} else {
		insert_text(((Unit*) user_data)->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, true, false, &can_display_unicode_string_function, (void*) expressiontext).name.c_str());
	}
	if((Unit*) user_data != latest_button_currency) {
		latest_button_currency = (Unit*) user_data;
		string currency_label_str;
		if(((Unit*) user_data)->subtype() == SUBTYPE_COMPOSITE_UNIT) {
			currency_label_str = ((CompositeUnit*) latest_button_currency)->print(false, true, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) expressiontext);
		} else {
		
			currency_label_str = latest_button_currency->preferredDisplayName(true, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext).name;
		}
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_euro")), currency_label_str.c_str());
		gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(main_builder, "label_euro")), latest_button_currency->title(true).c_str());
	}
}

void set_name_label_and_entry(ExpressionItem *item, GtkWidget *entry, GtkWidget *label) {
	const ExpressionName *ename = &item->getName(1);
	gtk_entry_set_text(GTK_ENTRY(entry), ename->name.c_str());
	if(item->countNames() > 1) {
		string str = "+ ";
		for(size_t i = 2; i <= item->countNames(); i++) {
			if(i > 2) str += ", ";
			str += item->getName(i).name;
		}
		gtk_label_set_text(GTK_LABEL(label), str.c_str());
	}
}
void set_edited_names(ExpressionItem *item, string str) {
	if(item->isBuiltin() && !(item->type() == TYPE_FUNCTION && item->subtype() == SUBTYPE_DATA_SET)) return;
	if(names_edited) {
		item->clearNames();
		GtkTreeIter iter;
		if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tNames_store), &iter)) {
			ExpressionName ename;
			gchar *gstr;
			while(true) {	
				gboolean abbreviation = FALSE, suffix = FALSE, unicode = FALSE, plural = FALSE;
				gboolean reference = FALSE, avoid_input = FALSE, case_sensitive = FALSE, completion_only = FALSE;
				gtk_tree_model_get(GTK_TREE_MODEL(tNames_store), &iter, NAMES_NAME_COLUMN, &gstr, NAMES_ABBREVIATION_COLUMN, &abbreviation, NAMES_SUFFIX_COLUMN, &suffix, NAMES_UNICODE_COLUMN, &unicode, NAMES_PLURAL_COLUMN, &plural, NAMES_REFERENCE_COLUMN, &reference, NAMES_AVOID_INPUT_COLUMN, &avoid_input, NAMES_CASE_SENSITIVE_COLUMN, &case_sensitive, NAMES_COMPLETION_ONLY_COLUMN, &completion_only, -1);
				ename.name = gstr; ename.abbreviation = abbreviation; ename.suffix = suffix;
				ename.unicode = unicode; ename.plural = plural; ename.reference = reference; 
				ename.avoid_input = avoid_input; ename.case_sensitive = case_sensitive;
				ename.completion_only = completion_only;
				item->addName(ename);
				g_free(gstr);
				if(!gtk_tree_model_iter_next(GTK_TREE_MODEL(tNames_store), &iter)) break;
			}
		} else {
			item->addName(str);
		}
	} else {
		if(item->countNames() == 0) {
			ExpressionName ename(str);
			ename.reference = true;
			item->setName(ename, 1);
		} else {
			item->setName(str, 1);
		}
		
	}
}

/*
	display edit/new unit dialog
	creates new unit if u == NULL, win is parent window
*/
void edit_unit(const char *category = "", Unit *u = NULL, GtkWidget *win = NULL) {

	edited_unit = u;
	names_edited = false;
	editing_unit = true;
	GtkWidget *dialog = get_unit_edit_dialog();
	if(win) gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(win));
	
	if(u) {
		if(u->isLocal())
			gtk_window_set_title(GTK_WINDOW(dialog), _("Edit Unit"));
		else
			gtk_window_set_title(GTK_WINDOW(dialog), _("Edit Unit (global)"));
	} else {
		gtk_window_set_title(GTK_WINDOW(dialog), _("New Unit"));
	}

	gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(unitedit_builder, "unit_edit_combo_category")))), category);

	//clear entries
	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_name")), "");
	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_desc")), "");
	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_base")), "");
	gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_spinbutton_exp")), 1);
	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_relation")), "");
	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_reversed")), "");
	gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(unitedit_builder, "unit_edit_combo_system")))), "");
	gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(unitedit_builder, "unit_edit_label_names")), "");

	if(u) {
		//fill in original parameters
		if(u->subtype() == SUBTYPE_BASE_UNIT) {
			gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(unitedit_builder, "unit_edit_combobox_class")), UNIT_CLASS_BASE_UNIT);
		} else if(u->subtype() == SUBTYPE_ALIAS_UNIT) {
			gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(unitedit_builder, "unit_edit_combobox_class")), UNIT_CLASS_ALIAS_UNIT);
		} else if(u->subtype() == SUBTYPE_COMPOSITE_UNIT) {
			gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(unitedit_builder, "unit_edit_combobox_class")), UNIT_CLASS_COMPOSITE_UNIT);
		}
		on_unit_edit_combobox_class_changed(GTK_COMBO_BOX(gtk_builder_get_object(unitedit_builder, "unit_edit_combobox_class")), NULL);	
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_combobox_class")), !u->isBuiltin());

		//gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_combobox_class")), u->isLocal() && !u->isBuiltin());

		set_name_label_and_entry(u, GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_name")), GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_label_names")));
		
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_name")), !u->isBuiltin());
		
		gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(unitedit_builder, "unit_edit_combo_system")))), u->system().c_str());
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_combo_system")), !u->isBuiltin());

		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_checkbutton_hidden")), u->isHidden());
		
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_checkbutton_use_prefixes")), u->useWithPrefixesByDefault());
		
		gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(unitedit_builder, "unit_edit_combo_category")))), u->category().c_str());
		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_desc")), u->title(false).c_str());
		
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_checkbutton_mix")), FALSE);
		gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_spinbutton_mix_priority")), 1);
		gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_spinbutton_mix_min")), 1);		

		switch(u->subtype()) {
			case SUBTYPE_ALIAS_UNIT: {
				AliasUnit *au = (AliasUnit*) u;
				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_base")), ((CompositeUnit*) (au->firstBaseUnit()))->preferredDisplayName(printops.abbreviate_names, true, false, false, &can_display_unicode_string_function, (void*) gtk_builder_get_object(unitedit_builder, "unit_edit_entry_base")).name.c_str());
				gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_spinbutton_exp")), au->firstBaseExponent());
				if(au->firstBaseExponent() != 1) gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_frame_mix")), FALSE);
				bool is_relative = false;
				if(au->uncertainty(&is_relative).empty()) {
					gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_relation")), CALCULATOR->localizeExpression(au->expression()).c_str());
				} else if(is_relative) {
					string value = CALCULATOR->f_uncertainty->referenceName();
					value += "(";
					value += au->expression();
					value += CALCULATOR->getComma();
					value += " ";
					value += CALCULATOR->localizeExpression(au->uncertainty());
					value += CALCULATOR->getComma();
					value += " 1)";
					gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_relation")), CALCULATOR->localizeExpression(value).c_str());
				} else {
					gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_relation")), CALCULATOR->localizeExpression(au->expression() + SIGN_PLUSMINUS + au->uncertainty()).c_str());
				}
				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_reversed")), CALCULATOR->localizeExpression(au->inverseExpression()).c_str());
				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_box_reversed")), au->hasNonlinearExpression());
				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_checkbutton_exact")), !au->isApproximate());
				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_relation")), !u->isBuiltin());
				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_reversed")), !u->isBuiltin());
				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_checkbutton_exact")), !u->isBuiltin());
				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_spinbutton_exp")), !u->isBuiltin());
				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_base")), !u->isBuiltin());
				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_frame_mix")), !u->isBuiltin());
				if(au->mixWithBase() > 0) {
					gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_checkbutton_mix")), TRUE);
					gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_spinbutton_mix_priority")), au->mixWithBase());
					gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_spinbutton_mix_min")), au->mixWithBaseMinimum() > 1 ? au->mixWithBaseMinimum() : 1);
					on_unit_edit_checkbutton_mix_toggled(GTK_TOGGLE_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_checkbutton_mix")), NULL);
				}
				break;
			}
			case SUBTYPE_COMPOSITE_UNIT: {
				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_base")), ((CompositeUnit*) u)->print(false, printops.abbreviate_names, true, &can_display_unicode_string_function, (void*) gtk_builder_get_object(unitedit_builder, "unit_edit_entry_base")).c_str());
				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_base")), !u->isBuiltin());
			}
			default: {				
				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_frame_mix")), FALSE);
			}
		}
	} else {
		//default values
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_checkbutton_hidden")), false);
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_checkbutton_exact")), TRUE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_box_reversed")), false);
		gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(unitedit_builder, "unit_edit_combobox_class")), UNIT_CLASS_ALIAS_UNIT);
		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_relation")), "1");
		on_unit_edit_combobox_class_changed(GTK_COMBO_BOX(gtk_builder_get_object(unitedit_builder, "unit_edit_combobox_class")), NULL);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_button_ok")), TRUE);
	}
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_button_ok")), FALSE);

run_unit_edit_dialog:
	gint response = gtk_dialog_run(GTK_DIALOG(dialog));
	if(response == GTK_RESPONSE_OK) {
		//clicked "OK"
		string str;
		str = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_name")));
		remove_blank_ends(str);
		GtkTreeIter iter;
		if(str.empty() && (!names_edited || !gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tNames_store), &iter))) {
			//no name given
			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_name")));
			show_message(_("Empty name field."), dialog);
			goto run_unit_edit_dialog;
		}

		//unit with the same name exists -- overwrite or open the dialog again
		if((!u || !u->hasName(str)) && (!names_edited || !gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tNames_store), &iter)) && CALCULATOR->unitNameTaken(str, u) && !ask_question(_("A variable or unit with the same name already exists.\nDo you want to overwrite it?"), dialog)) {
			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_name")));
			goto run_unit_edit_dialog;
		}
		bool add_unit = false;
		if(u) {
			//edited an existing unit -- update unit
			u->setLocal(true);
			gint i1 = gtk_combo_box_get_active(GTK_COMBO_BOX(gtk_builder_get_object(unitedit_builder, "unit_edit_combobox_class")));
			switch(u->subtype()) {
				case SUBTYPE_ALIAS_UNIT: {
					if(i1 != UNIT_CLASS_ALIAS_UNIT) {
						u->destroy();
						u = NULL;
						break;
					}
					if(!u->isBuiltin()) {
						AliasUnit *au = (AliasUnit*) u;
						Unit *bu = CALCULATOR->getUnit(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_base"))));
						if(!bu) bu = CALCULATOR->getCompositeUnit(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_base"))));
						if(!bu) {
							gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_base")));
							show_message(_("Base unit does not exist."), dialog);
							goto run_unit_edit_dialog;
						}
						au->setBaseUnit(bu);
						au->setExpression(CALCULATOR->unlocalizeExpression(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_relation"))), evalops.parse_options));
						au->setInverseExpression(au->hasNonlinearExpression() ? CALCULATOR->unlocalizeExpression(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_reversed"))), evalops.parse_options) : "");
						au->setExponent(gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_spinbutton_exp"))));
						au->setApproximate(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_checkbutton_exact"))));
						if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_checkbutton_mix")))) {
							au->setMixWithBase(gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_spinbutton_mix_priority"))));
							au->setMixWithBaseMinimum(gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_spinbutton_mix_min"))));
						} else {
							au->setMixWithBase(0);
						}
					}
					break;
				}
				case SUBTYPE_COMPOSITE_UNIT: {
					if(i1 != UNIT_CLASS_COMPOSITE_UNIT) {
						u->destroy();
						u = NULL;
						break;
					}
					if(!u->isBuiltin()) {
						((CompositeUnit*) u)->setBaseExpression(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_base"))));
					}
					break;
				}
				case SUBTYPE_BASE_UNIT: {
					if(i1 != UNIT_CLASS_BASE_UNIT) {
						u->destroy();
						u = NULL;
						break;
					}
					break;
				}
			}
			if(u) {
				u->setTitle(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_desc"))));
				u->setCategory(gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(gtk_builder_get_object(unitedit_builder, "unit_edit_combo_category"))));
			}
		}
		if(!u) {
			//new unit
			switch(gtk_combo_box_get_active(GTK_COMBO_BOX(gtk_builder_get_object(unitedit_builder, "unit_edit_combobox_class")))) {
				case UNIT_CLASS_ALIAS_UNIT: {
					Unit *bu = CALCULATOR->getUnit(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_base"))));
					if(!bu) bu = CALCULATOR->getCompositeUnit(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_base"))));
					if(!bu) {
						gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_base")));
						show_message(_("Base unit does not exist."), dialog);
						goto run_unit_edit_dialog;
					}
					u = new AliasUnit(gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(gtk_builder_get_object(unitedit_builder, "unit_edit_combo_category"))), "", "", "", gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_desc"))), bu, CALCULATOR->unlocalizeExpression(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_relation"))), evalops.parse_options), gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_spinbutton_exp"))), CALCULATOR->unlocalizeExpression(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_reversed"))), evalops.parse_options), true);
					((AliasUnit*) u)->setApproximate(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_checkbutton_exact"))));
					if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_checkbutton_mix")))) {
						((AliasUnit*) u)->setMixWithBase(gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_spinbutton_mix_priority"))));
						((AliasUnit*) u)->setMixWithBaseMinimum(gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_spinbutton_mix_min"))));
					}
					break;
				}
				case UNIT_CLASS_COMPOSITE_UNIT: {
					CompositeUnit *cu = new CompositeUnit(gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(gtk_builder_get_object(unitedit_builder, "unit_edit_combo_category"))), "", gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_desc"))), gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_base"))), true);
					u = cu;
					break;
				}
				default: {
					u = new Unit(gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(gtk_builder_get_object(unitedit_builder, "unit_edit_combo_category"))), "", "", "", gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_desc"))), true);
					break;
				}
			}
			add_unit = true;
		}
		if(u) {
			u->setHidden(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_checkbutton_hidden"))));			
			if(!u->isBuiltin()) {
				u->setSystem(gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(gtk_builder_get_object(unitedit_builder, "unit_edit_combo_system"))));
			}
			if(u->subtype() != SUBTYPE_COMPOSITE_UNIT) {
				u->setUseWithPrefixesByDefault(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_checkbutton_use_prefixes"))));
			}
			set_edited_names(u, str);
			if(add_unit) {
				CALCULATOR->addUnit(u);
			}
			//select the new unit
			selected_unit = u;
			if(!u->isActive()) {
				selected_unit_category = _("Inactive");
			} else if(u->category().empty()) {
				selected_unit_category = _("Uncategorized");
			} else {
				selected_unit_category = "/";
				selected_unit_category += u->category();
			}
		}
		update_umenus();
		unit_inserted(u);
	} else if(response == GTK_RESPONSE_HELP) {
		show_help("qalculate-units.html#qalculate-unit-creation", gtk_builder_get_object(unitedit_builder, "unit_edit_dialog")); 
		goto run_unit_edit_dialog;
	}
	edited_unit = NULL;
	names_edited = false;
	editing_unit = false;
	gtk_widget_hide(dialog);
}

bool edit_argument(Argument *arg) {
	if(!arg) {
		arg = new Argument();
	}
	edited_argument = arg;
	GtkWidget *dialog = get_argument_rules_dialog();	
	gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gtk_builder_get_object(functionedit_builder, "function_edit_dialog")));
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_enable_test")), arg->tests());
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_allow_matrix")), arg->matrixAllowed());
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_allow_matrix")), TRUE);
	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(argumentrules_builder, "argument_rules_entry_condition")), CALCULATOR->localizeExpression(arg->getCustomCondition()).c_str());
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_enable_condition")), !arg->getCustomCondition().empty());
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(argumentrules_builder, "argument_rules_entry_condition")), !arg->getCustomCondition().empty());
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_forbid_zero")), arg->zeroForbidden());
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_handle_vector")), arg->handlesVector());
	switch(arg->type()) {
		case ARGUMENT_TYPE_NUMBER: {
			NumberArgument *farg = (NumberArgument*) arg;
			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(argumentrules_builder, "argument_rules_box_min")), TRUE);
			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_enable_min")), farg->min() != NULL);
			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_min_include_equals")), farg->includeEqualsMin());
			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(argumentrules_builder, "argument_rules_spinbutton_min")), farg->min() != NULL);
			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_min_include_equals")), TRUE);
			gtk_spin_button_set_digits(GTK_SPIN_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_spinbutton_min")), 8);
			gtk_adjustment_set_lower(GTK_ADJUSTMENT(gtk_builder_get_object(argumentrules_builder, "adjustment_min")), INT_MIN);
			gtk_adjustment_set_upper(GTK_ADJUSTMENT(gtk_builder_get_object(argumentrules_builder, "adjustment_min")), INT_MAX);
			if(farg->min()) {
				gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_spinbutton_max")), farg->min()->floatValue());
			} else {
				gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_spinbutton_min")), 0);
			}
			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(argumentrules_builder, "argument_rules_box_max")), TRUE);
			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_enable_max")), farg->max() != NULL);
			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_max_include_equals")), farg->includeEqualsMax());
			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(argumentrules_builder, "argument_rules_spinbutton_max")), farg->max() != NULL);
			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_max_include_equals")), TRUE);
			gtk_spin_button_set_digits(GTK_SPIN_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_spinbutton_max")), 8);
			gtk_adjustment_set_lower(GTK_ADJUSTMENT(gtk_builder_get_object(argumentrules_builder, "adjustment_max")), INT_MIN);
			gtk_adjustment_set_upper(GTK_ADJUSTMENT(gtk_builder_get_object(argumentrules_builder, "adjustment_max")), INT_MAX);
			if(farg->max()) {
				gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_spinbutton_max")), farg->max()->floatValue());
			} else {
				gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_spinbutton_max")), 0);
			}			
			break;
		}
		case ARGUMENT_TYPE_INTEGER: {
			IntegerArgument *iarg = (IntegerArgument*) arg;
			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(argumentrules_builder, "argument_rules_box_min")), TRUE);
			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_enable_min")), iarg->min() != NULL);
			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_min_include_equals")), TRUE);
			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(argumentrules_builder, "argument_rules_spinbutton_min")), iarg->min() != NULL);
			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_min_include_equals")), FALSE);
			gtk_spin_button_set_digits(GTK_SPIN_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_spinbutton_min")), 0);
			gtk_adjustment_set_lower(GTK_ADJUSTMENT(gtk_builder_get_object(argumentrules_builder, "adjustment_min")), INT_MIN);
			gtk_adjustment_set_upper(GTK_ADJUSTMENT(gtk_builder_get_object(argumentrules_builder, "adjustment_min")), INT_MAX);
			if(iarg->min()) {
				gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_spinbutton_min")), iarg->min()->intValue());		
			} else {
				gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_spinbutton_min")), 0);
			}
			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(argumentrules_builder, "argument_rules_box_max")), TRUE);
			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_enable_max")), iarg->max() != NULL);
			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_max_include_equals")), TRUE);
			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(argumentrules_builder, "argument_rules_spinbutton_max")), iarg->max() != NULL);
			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_max_include_equals")), FALSE);
			gtk_spin_button_set_digits(GTK_SPIN_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_spinbutton_max")), 0);
			gtk_adjustment_set_lower(GTK_ADJUSTMENT(gtk_builder_get_object(argumentrules_builder, "adjustment_max")), INT_MIN);
			gtk_adjustment_set_upper(GTK_ADJUSTMENT(gtk_builder_get_object(argumentrules_builder, "adjustment_max")), INT_MAX);
			if(iarg->max()) {
				gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_spinbutton_max")), iarg->max()->intValue());		
			} else {
				gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_spinbutton_max")), 0);
			}	
			break;
		}
		case ARGUMENT_TYPE_FREE: {}
		case ARGUMENT_TYPE_MATRIX: {		
			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_allow_matrix")), TRUE);
			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_allow_matrix")), FALSE);	
		}
		default: {
			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_enable_min")), FALSE);
			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_enable_max")), FALSE);
			gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_spinbutton_min")), 0);
			gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_spinbutton_max")), 0);
			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(argumentrules_builder, "argument_rules_box_min")), FALSE);
			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(argumentrules_builder, "argument_rules_box_max")), FALSE);
		}
	}
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(argumentrules_builder, "argument_rules_button_ok")), FALSE);
	if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) {
		arg->setTests(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_enable_test"))));
		arg->setMatrixAllowed(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_allow_matrix"))));
		arg->setZeroForbidden(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_forbid_zero"))));
		arg->setHandleVector(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_handle_vector"))));
		if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_enable_condition")))) {
			arg->setCustomCondition(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(argumentrules_builder, "argument_rules_entry_condition"))));
		} else {
			arg->setCustomCondition("");
		}
		if(arg->type() == ARGUMENT_TYPE_NUMBER) {
			NumberArgument *farg = (NumberArgument*) arg;
			farg->setIncludeEqualsMin(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_min_include_equals"))));
			farg->setIncludeEqualsMax(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_max_include_equals"))));
			if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_enable_min")))) {
				Number nr;
				nr.setFloat(gtk_spin_button_get_value(GTK_SPIN_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_spinbutton_min"))));
				farg->setMin(&nr);
			} else {
				farg->setMin(NULL);
			}
			if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_enable_max")))) {
				Number nr;
				nr.setFloat(gtk_spin_button_get_value(GTK_SPIN_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_spinbutton_max"))));
				farg->setMax(&nr);
			} else {
				farg->setMax(NULL);
			}			
		} else if(arg->type() == ARGUMENT_TYPE_INTEGER) {
			IntegerArgument *iarg = (IntegerArgument*) arg;
			if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_enable_min")))) {
				Number integ(gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_spinbutton_min"))), 1);
				iarg->setMin(&integ);
			} else {
				iarg->setMin(NULL);
			}
			if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_enable_max")))) {
				Number integ(gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_spinbutton_max"))), 1);
				iarg->setMax(&integ);
			} else {
				iarg->setMax(NULL);
			}			
		}
		GtkTreeModel *model;
		GtkTreeIter iter;
		GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tFunctionArguments));
		if(gtk_tree_selection_get_selected(select, &model, &iter)) {
			gtk_list_store_set(tFunctionArguments_store, &iter, 0, arg->name().c_str(), 1, arg->printlong().c_str(), 2, (gpointer) arg, -1);
		}
		edited_argument = NULL;
		gtk_widget_hide(dialog);
		return true;
	}
	edited_argument = NULL;
	gtk_widget_hide(dialog);
	return false;
}


void delete_function(MathFunction *f) {
	if(f && f->isLocal()) {
		for(size_t i = 0; i < recent_functions.size(); i++) {
			if(recent_functions[i] == f) {
				recent_functions.erase(recent_functions.begin() + i);
				gtk_widget_destroy(recent_function_items[i]);
				recent_function_items.erase(recent_function_items.begin() + i);
				break;
			}
		}
		//ensure removal of all references in Calculator
		f->destroy();
		//update menus and trees
		update_fmenu();
	}
}

/*
	display edit/new function dialog
	creates new function if f == NULL, win is parent window
*/
void edit_function(const char *category = "", MathFunction *f = NULL, GtkWidget *win = NULL, const char *name = NULL, const char *expression = NULL, bool enable_ok = true) {

	if(f && f->subtype() == SUBTYPE_DATA_SET) {
		edit_dataset((DataSet*) f, win);
		return;
	}

	GtkWidget *dialog = get_function_edit_dialog();	
	if(win) gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(win));

	edited_function = f;
	names_edited = false;
	editing_function = true;
	
	if(f) {
		if(f->isLocal())
			gtk_window_set_title(GTK_WINDOW(dialog), _("Edit Function"));
		else
			gtk_window_set_title(GTK_WINDOW(dialog), _("Edit Function (global)"));		
	} else {
		gtk_window_set_title(GTK_WINDOW(dialog), _("New Function"));
	}

	GtkTextBuffer *description_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtk_builder_get_object(functionedit_builder, "function_edit_textview_description")));
	GtkTextBuffer *expression_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtk_builder_get_object(functionedit_builder, "function_edit_textview_expression")));	

	//clear entries
	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(functionedit_builder, "function_edit_entry_name")), "");
	gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(functionedit_builder, "function_edit_label_names")), "");
	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(functionedit_builder, "function_edit_entry_condition")), "");
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_entry_condition")), !f || !f->isBuiltin());
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_entry_name")), !f || !f->isBuiltin());
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_textview_expression")), !f || !f->isBuiltin());
	gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(functionedit_builder, "function_edit_combo_category")))), category);
	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(functionedit_builder, "function_edit_entry_desc")), "");
	gtk_text_buffer_set_text(description_buffer, "", -1);
	gtk_text_buffer_set_text(expression_buffer, "", -1);
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(functionedit_builder, "function_edit_checkbutton_hidden")), false);
	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(functionedit_builder, "function_edit_entry_argument_name")), "");

	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_combobox_argument_type")), !f || !f->isBuiltin());
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_button_add_argument")), !f || !f->isBuiltin());

	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_button_subfunctions")), !f || !f->isBuiltin());
	gtk_list_store_clear(tSubfunctions_store);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_button_modify_subfunction")), FALSE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_button_remove_subfunction")), FALSE);		
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_button_add_subfunction")), !f || !f->isBuiltin());
	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(functionedit_builder, "function_edit_entry_subexpression")), "");
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(functionedit_builder, "function_edit_checkbutton_precalculate")), TRUE);
	selected_subfunction = 0;
	last_subfunction_index = 0;
	if(f) {
		//fill in original paramaters
		set_name_label_and_entry(f, GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_entry_name")), GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_label_names")));
		if(!f->isBuiltin()) {
			gtk_text_buffer_set_text(expression_buffer, CALCULATOR->localizeExpression(((UserFunction*) f)->formula()).c_str(), -1);
		}
		gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(functionedit_builder, "function_edit_combo_category")))), f->category().c_str());
		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(functionedit_builder, "function_edit_entry_desc")), f->title(false).c_str());
		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(functionedit_builder, "function_edit_entry_condition")), CALCULATOR->localizeExpression(f->condition()).c_str());
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(functionedit_builder, "function_edit_checkbutton_hidden")), f->isHidden());
		gtk_text_buffer_set_text(description_buffer, f->description().c_str(), -1);
		
		if(!f->isBuiltin()) {
			GtkTreeIter iter;
			string str, str2;
			for(size_t i = 1; i <= ((UserFunction*) f)->countSubfunctions(); i++) {
				gtk_list_store_append(tSubfunctions_store, &iter);
				if(((UserFunction*) f)->subfunctionPrecalculated(i)) {
					str = _("Yes");
				} else {
					str = _("No");
				}
				str2 = "\\";
				str2 += i2s(i);
				gtk_list_store_set(tSubfunctions_store, &iter, 0, str2.c_str(), 1, ((UserFunction*) f)->getSubfunction(i).c_str(), 2, str.c_str(), 3, i, 4, ((UserFunction*) f)->subfunctionPrecalculated(i), -1);
				last_subfunction_index = i;
			}
		}
	}
	if(name) gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(functionedit_builder, "function_edit_entry_name")), name);
	if(expression) gtk_text_buffer_set_text(expression_buffer, expression, -1);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_button_ok")), enable_ok && (name || expression));
	update_function_arguments_list(f);
	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_entry_name")));
	gtk_notebook_set_current_page(GTK_NOTEBOOK(gtk_builder_get_object(functionedit_builder, "function_edit_tabs")), 0);
	
run_function_edit_dialog:
	gint response = gtk_dialog_run(GTK_DIALOG(dialog));
	if(response == GTK_RESPONSE_OK) {
		//clicked "OK"
		string str = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(functionedit_builder, "function_edit_entry_name")));
		remove_blank_ends(str);
		GtkTreeIter iter;
		if(str.empty() && (!names_edited || !gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tNames_store), &iter))) {
			//no name -- open dialog again
			gtk_notebook_set_current_page(GTK_NOTEBOOK(gtk_builder_get_object(functionedit_builder, "function_edit_tabs")), 0);
			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_entry_name")));
			show_message(_("Empty name field."), dialog);
			goto run_function_edit_dialog;
		}
		GtkTextIter e_iter_s, e_iter_e;
		gtk_text_buffer_get_start_iter(expression_buffer, &e_iter_s);
		gtk_text_buffer_get_end_iter(expression_buffer, &e_iter_e);
		gchar *gstr = gtk_text_buffer_get_text(expression_buffer, &e_iter_s, &e_iter_e, FALSE);
		string str2 = CALCULATOR->unlocalizeExpression(gstr, evalops.parse_options);
		g_free(gstr);
		remove_blank_ends(str2);
		gsub("\n", " ", str2);
		if(!(f && f->isBuiltin()) && str2.empty()) {
			//no expression/relation -- open dialog again
			gtk_notebook_set_current_page(GTK_NOTEBOOK(gtk_builder_get_object(functionedit_builder, "function_edit_tabs")), 1);
			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_textview_expression")));
			show_message(_("Empty expression field."), dialog);
			goto run_function_edit_dialog;
		}
		GtkTextIter d_iter_s, d_iter_e;
		gtk_text_buffer_get_start_iter(description_buffer, &d_iter_s);
		gtk_text_buffer_get_end_iter(description_buffer, &d_iter_e);
		gchar *gstr_descr = gtk_text_buffer_get_text(description_buffer, &d_iter_s, &d_iter_e, FALSE);
		//function with the same name exists -- overwrite or open the dialog again
		if((!f || !f->hasName(str)) && (!names_edited || !gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tNames_store), &iter)) && CALCULATOR->functionNameTaken(str, f) && !ask_question(_("A function with the same name already exists.\nDo you want to overwrite the function?"), dialog)) {
			gtk_notebook_set_current_page(GTK_NOTEBOOK(gtk_builder_get_object(functionedit_builder, "function_edit_tabs")), 0);
			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_entry_name")));
			goto run_function_edit_dialog;
		}
		bool add_func = false;
		if(f) {
			f->setLocal(true);
			//edited an existing function
			f->setCategory(gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(gtk_builder_get_object(functionedit_builder, "function_edit_combo_category"))));
			f->setTitle(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(functionedit_builder, "function_edit_entry_desc"))));
			f->setDescription(gstr_descr);
			if(!f->isBuiltin()) {				
				f->clearArgumentDefinitions();
			}	
		} else {
			//new function
			f = new UserFunction(gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT((gtk_builder_get_object(functionedit_builder, "function_edit_combo_category")))), "", "", true, -1, gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(functionedit_builder, "function_edit_entry_desc"))), gstr_descr);
			add_func = true;
		}
		g_free(gstr_descr);
		if(f) {
			f->setCondition(CALCULATOR->unlocalizeExpression(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(functionedit_builder, "function_edit_entry_condition"))), evalops.parse_options));
			GtkTreeIter iter;
			bool b = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tFunctionArguments_store), &iter);
			int i = 1;
			Argument *arg;
			while(b) {
				gtk_tree_model_get(GTK_TREE_MODEL(tFunctionArguments_store), &iter, 2, &arg, -1);
				if(arg && f->isBuiltin() && f->getArgumentDefinition(i)) {
					f->getArgumentDefinition(i)->setName(arg->name());
					delete arg;
				} else if(arg) {
					f->setArgumentDefinition(i, arg);
				}
				b = gtk_tree_model_iter_next(GTK_TREE_MODEL(tFunctionArguments_store), &iter);
				i++;
			}
			if(!f->isBuiltin()) {
				((UserFunction*) f)->clearSubfunctions();
				b = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tSubfunctions_store), &iter);
				while(b) {
					gchar *gstr;
					gboolean g_b = FALSE;
					gtk_tree_model_get(GTK_TREE_MODEL(tSubfunctions_store), &iter, 1, &gstr, 4, &g_b, -1);
					((UserFunction*) f)->addSubfunction(gstr, g_b);
					b = gtk_tree_model_iter_next(GTK_TREE_MODEL(tSubfunctions_store), &iter);
					g_free(gstr);
				}
				((UserFunction*) f)->setFormula(str2);
			}
			f->setHidden(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(functionedit_builder, "function_edit_checkbutton_hidden"))));
			set_edited_names(f, str);
			if(add_func) {
				CALCULATOR->addFunction(f);
			}
			if(!f->isActive()) {
				selected_function_category = _("Inactive");
			} else if(f->category().empty()) {
				selected_function_category = _("Uncategorized");
			} else {
				selected_function_category = "/";
				selected_function_category += f->category();
			}
			//select the new function
			selected_function = f;
		}
		update_fmenu();	
		function_inserted(f);
	} else if(response == GTK_RESPONSE_HELP) {
		show_help("qalculate-functions.html#qalculate-function-creation", gtk_builder_get_object(functionedit_builder, "function_edit_dialog")); 
		goto run_function_edit_dialog;
	}
	edited_function = NULL;
	names_edited = false;
	editing_function = false;
	gtk_widget_hide(dialog);
}

/*
	display edit/new function dialog
	creates new function if f == NULL, win is parent window
*/
void edit_function_simple(const char *category = "", MathFunction *f = NULL, GtkWidget *win = NULL) {

	if(f && f->subtype() == SUBTYPE_DATA_SET) {
		edit_dataset((DataSet*) f, win);
		return;
	}

	GtkWidget *dialog = get_simple_function_edit_dialog();
	if(win) gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(win));

	edited_function = f;
	editing_function = true;
	
	if(f) {
		if(f->isLocal() && f->subtype() == SUBTYPE_USER_FUNCTION) gtk_window_set_title(GTK_WINDOW(dialog), _("Edit Function"));
		else return edit_function(category, f, win);
		if(((UserFunction*) f)->countSubfunctions() > 0 || f->countNames() > 1 || !f->condition().empty() || f->lastArgumentDefinitionIndex() > 0 || !f->description().empty() || !f->title(false).empty() || !f->category().empty()) return edit_function(category, f, win);
	} else {
		gtk_window_set_title(GTK_WINDOW(dialog), _("New Function"));
	}

	GtkTextBuffer *expression_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtk_builder_get_object(simplefunctionedit_builder, "simple_function_edit_textview_expression")));

	//clear entries
	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(simplefunctionedit_builder, "simple_function_edit_entry_name")), "");
	gtk_text_buffer_set_text(expression_buffer, "", -1);

	if(f) {
		//fill in original paramaters
		gtk_text_buffer_set_text(expression_buffer, CALCULATOR->localizeExpression(((UserFunction*) f)->formula()).c_str(), -1);
		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(simplefunctionedit_builder, "simple_function_edit_entry_name")), f->getName(1).name.c_str());
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(simplefunctionedit_builder, "simple_function_edit_radiobutton_slash")), TRUE);
	} else {
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(simplefunctionedit_builder, "simple_function_edit_radiobutton_noslash")), TRUE);
	}
	
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(simplefunctionedit_builder, "simple_function_edit_button_ok")), FALSE);

	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(simplefunctionedit_builder, "simple_function_edit_entry_name")));
	
run_simple_function_edit_dialog:
	gint response = gtk_dialog_run(GTK_DIALOG(dialog));
	if(response == GTK_RESPONSE_OK) {
		//clicked "OK"
		string str = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(simplefunctionedit_builder, "simple_function_edit_entry_name")));
		remove_blank_ends(str);
		if(str.empty()) {
			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(simplefunctionedit_builder, "simple_function_edit_entry_name")));
			show_message(_("Empty name field."), dialog);
			goto run_simple_function_edit_dialog;
		}
		GtkTextIter e_iter_s, e_iter_e;
		gtk_text_buffer_get_start_iter(expression_buffer, &e_iter_s);
		gtk_text_buffer_get_end_iter(expression_buffer, &e_iter_e);;
		gchar *gstr = gtk_text_buffer_get_text(expression_buffer, &e_iter_s, &e_iter_e, FALSE);
		string str2 = CALCULATOR->unlocalizeExpression(gstr, evalops.parse_options);
		g_free(gstr);
		remove_blank_ends(str2);
		gsub("\n", " ", str2);
		if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(simplefunctionedit_builder, "simple_function_edit_radiobutton_noslash")))) {
			gsub("x", "\\x", str2);
			gsub("y", "\\y", str2);
			gsub("z", "\\z", str2);
		}
		if(str2.empty()) {
			//no expression/relation -- open dialog again
			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(simplefunctionedit_builder, "simple_function_edit_textview_expression")));
			show_message(_("Empty expression field."), dialog);
			goto run_simple_function_edit_dialog;
		}
		//function with the same name exists -- overwrite or open the dialog again
		if((!f || !f->hasName(str)) && CALCULATOR->functionNameTaken(str, f) && !ask_question(_("A function with the same name already exists.\nDo you want to overwrite the function?"), dialog)) {
			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(simplefunctionedit_builder, "simple_function_edit_entry_name")));
			goto run_simple_function_edit_dialog;
		}
		if(f) {
			//edited an existing function
			f->setLocal(true);
			((UserFunction*) f)->setFormula(str2);
			f->setName(str, 1);
		} else {
			//new function
			f = new UserFunction(category, str, str2);
			CALCULATOR->addFunction(f);
		}
		update_fmenu();
		function_inserted(f);
	}
	edited_function = NULL;
	names_edited = false;
	editing_function = false;
	gtk_widget_hide(dialog);
	if(response == 1) {
		GtkTextIter e_iter_s, e_iter_e;
		gtk_text_buffer_get_start_iter(expression_buffer, &e_iter_s);
		gtk_text_buffer_get_end_iter(expression_buffer, &e_iter_e);;
		gchar *gstr = gtk_text_buffer_get_text(expression_buffer, &e_iter_s, &e_iter_e, FALSE);
		string str2 = gstr;
		g_free(gstr);
		if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(simplefunctionedit_builder, "simple_function_edit_radiobutton_noslash")))) {
			gsub("x", "\\x", str2);
			gsub("y", "\\y", str2);
			gsub("z", "\\z", str2);
		}
		edit_function(category, f, win, gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(simplefunctionedit_builder, "simple_function_edit_entry_name"))), str2.c_str(), gtk_widget_get_sensitive(GTK_WIDGET(gtk_builder_get_object(simplefunctionedit_builder, "simple_function_edit_button_ok"))));
	}
}

/*
	"New function" menu item selected
*/
void new_function(GtkMenuItem*, gpointer)
{
	edit_function("", NULL, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")));
}
/*
	"New unit" menu item selected
*/
void new_unit(GtkMenuItem*, gpointer)
{
	edit_unit("", NULL, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")));
}

/*
	a unit selected in result menu, convert result
*/
void convert_to_unit(GtkMenuItem*, gpointer user_data)
{
	GtkWidget *edialog;
	Unit *u = (Unit*) user_data;
	if(!u) {
		edialog = gtk_message_dialog_new(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("Unit does not exist"));
		gtk_dialog_run(GTK_DIALOG(edialog));
		gtk_widget_destroy(edialog);
	}
	//result is stored in MathStructure *mstruct
	executeCommand(COMMAND_CONVERT_UNIT, true, "", u);
	focus_keeping_selection();
}

void convert_to_unit_noprefix(GtkMenuItem*, gpointer user_data)
{
	GtkWidget *edialog;
	Unit *u = (Unit*) user_data;
	if(!u) {
		edialog = gtk_message_dialog_new(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("Unit does not exist"));
		gtk_dialog_run(GTK_DIALOG(edialog));
		gtk_widget_destroy(edialog);
	}
	string ceu_str = u->name();
	//result is stored in MathStructure *mstruct
	executeCommand(COMMAND_CONVERT_STRING, true, ceu_str);
	focus_keeping_selection();
}

void edit_unknown(const char *category, Variable *var, GtkWidget *win) {

	if(var != NULL && var->isKnown()) {
		edit_variable(category, var, NULL, win);
		return;
	}
	
	UnknownVariable *v = (UnknownVariable*) var;
	edited_unknown = v;
	names_edited = false;
	editing_unknown = true;
	
	GtkWidget *dialog = get_unknown_edit_dialog();
	if(win) gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(win));
	
	if(v) {
		if(v->isLocal())
			gtk_window_set_title(GTK_WINDOW(dialog), _("Edit Unknown Variable"));
		else
			gtk_window_set_title(GTK_WINDOW(dialog), _("Edit Unknown Variable (global)"));
	} else {
		gtk_window_set_title(GTK_WINDOW(dialog), _("New Unknown Variable"));
	}
	
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(unknownedit_builder, "unknown_edit_combobox_type"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_unknown_edit_combobox_type_changed, NULL);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(unknownedit_builder, "unknown_edit_combobox_sign"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_unknown_edit_combobox_sign_changed, NULL);
	if(v) {
		//fill in original parameters
		set_name_label_and_entry(v, GTK_WIDGET(gtk_builder_get_object(unknownedit_builder, "unknown_edit_entry_name")), GTK_WIDGET(gtk_builder_get_object(unknownedit_builder, "unknown_edit_label_names")));
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unknownedit_builder, "unknown_edit_entry_name")), !v->isBuiltin());
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unknownedit_builder, "unknown_edit_combobox_type")), !v->isBuiltin());
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unknownedit_builder, "unknown_edit_combobox_sign")), !v->isBuiltin());
		gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(unknownedit_builder, "unknown_edit_combo_category")))), v->category().c_str());
		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(unknownedit_builder, "unknown_edit_entry_desc")), v->title(false).c_str());
		if(v->assumptions()) {
			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(unknownedit_builder, "unknown_edit_checkbutton_custom_assumptions")), TRUE);
			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unknownedit_builder, "unknown_edit_hbox_type")), TRUE);
			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unknownedit_builder, "unknown_edit_hbox_sign")), TRUE);
			gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(unknownedit_builder, "unknown_edit_combobox_type")), v->assumptions()->type() - 2);
			gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(unknownedit_builder, "unknown_edit_combobox_sign")), v->assumptions()->sign());
		} else {
			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(unknownedit_builder, "unknown_edit_checkbutton_custom_assumptions")), FALSE);
			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unknownedit_builder, "unknown_edit_hbox_type")), FALSE);
			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unknownedit_builder, "unknown_edit_hbox_sign")), FALSE);
			gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(unknownedit_builder, "unknown_edit_combobox_type")), CALCULATOR->defaultAssumptions()->type() - 2);
			gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(unknownedit_builder, "unknown_edit_combobox_sign")), CALCULATOR->defaultAssumptions()->sign());
		}
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unknownedit_builder, "unknown_edit_button_ok")), FALSE);
	} else {
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unknownedit_builder, "unknown_edit_entry_name")), TRUE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unknownedit_builder, "unknown_edit_combobox_type")), TRUE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unknownedit_builder, "unknown_edit_combobox_sign")), TRUE);

		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(unknownedit_builder, "unknown_edit_checkbutton_custom_assumptions")), TRUE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unknownedit_builder, "unknown_edit_hbox_type")), TRUE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unknownedit_builder, "unknown_edit_hbox_sign")), TRUE);

		//fill in default values
		string v_name = CALCULATOR->getName();
		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(unknownedit_builder, "unknown_edit_entry_name")), v_name.c_str());
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(unknownedit_builder, "unknown_edit_label_names")), "");
		gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(unknownedit_builder, "unknown_edit_combo_category")))), category);
		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(unknownedit_builder, "unknown_edit_entry_desc")), "");
		gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(unknownedit_builder, "unknown_edit_combobox_type")), CALCULATOR->defaultAssumptions()->type() - 2);
		gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(unknownedit_builder, "unknown_edit_combobox_sign")), CALCULATOR->defaultAssumptions()->sign());
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unknownedit_builder, "unknown_edit_button_ok")), TRUE);
	}
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(unknownedit_builder, "unknown_edit_combobox_type"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_unknown_edit_combobox_type_changed, NULL);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(unknownedit_builder, "unknown_edit_combobox_sign"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_unknown_edit_combobox_sign_changed, NULL);
	
	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(unknownedit_builder, "unknown_edit_entry_name")));

run_unknown_edit_dialog:
	gint response = gtk_dialog_run(GTK_DIALOG(dialog));
	if(response == GTK_RESPONSE_OK) {
		//clicked "OK"
		string str = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(unknownedit_builder, "unknown_edit_entry_name")));
		remove_blank_ends(str);
		GtkTreeIter iter;
		if(str.empty() && (!names_edited || !gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tNames_store), &iter))) {
			//no name -- open dialog again
			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(unknownedit_builder, "unknown_edit_entry_name")));
			show_message(_("Empty name field."), dialog);
			goto run_unknown_edit_dialog;
		}

		//unknown with the same name exists -- overwrite or open dialog again
		if((!v || !v->hasName(str)) && (!names_edited || !gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tNames_store), &iter)) && CALCULATOR->variableNameTaken(str, v) && !ask_question(_("An unit or variable with the same name already exists.\nDo you want to overwrite it?"), dialog)) {
			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(unknownedit_builder, "unknown_edit_entry_name")));
			goto run_unknown_edit_dialog;
		}
		if(!v) {
			//no need to create a new unknown when a unknown with the same name exists
			var = CALCULATOR->getActiveVariable(str);
			if(var && var->isLocal() && !var->isKnown()) v = (UnknownVariable*) var;
		}
		bool add_var = false;
		if(v) {
			//update existing unknown
			v->setLocal(true);
		} else {
			//new unknown
			v = new UnknownVariable("", "", "", true);
			add_var = true;
		}
		if(v) {
			if(!v->isBuiltin()) {
				if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(unknownedit_builder, "unknown_edit_checkbutton_custom_assumptions")))) {
					if(!v->assumptions()) v->setAssumptions(new Assumptions());
					v->assumptions()->setType((AssumptionType) (gtk_combo_box_get_active(GTK_COMBO_BOX(gtk_builder_get_object(unknownedit_builder, "unknown_edit_combobox_type"))) + 2));
					v->assumptions()->setSign((AssumptionSign) gtk_combo_box_get_active(GTK_COMBO_BOX(gtk_builder_get_object(unknownedit_builder, "unknown_edit_combobox_sign"))));
				} else {
					v->setAssumptions(NULL);
				}
			}
			v->setCategory(gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(gtk_builder_get_object(unknownedit_builder, "unknown_edit_combo_category"))));
			v->setTitle(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(unknownedit_builder, "unknown_edit_entry_desc"))));
			set_edited_names(v, str);
			if(add_var) {
				CALCULATOR->addVariable(v);
			}
			//select the new unknown
			selected_variable = v;
			if(!v->isActive()) {
				selected_variable_category = _("Inactive");
			} else if(v->category().empty()) {
				selected_variable_category = _("Uncategorized");
			} else {
				selected_variable_category = "/";
				selected_variable_category += v->category();
			}
		}
		update_vmenu();
		variable_inserted(v);
	} else if(response == GTK_RESPONSE_HELP) {
		show_help("qalculate-variables.html#qalculate-variable-creation", gtk_builder_get_object(unknownedit_builder, "unknown_edit_dialog")); 
		goto run_unknown_edit_dialog;
	}
	edited_unknown = NULL;
	names_edited = false;
	editing_unknown = false;
	gtk_widget_hide(dialog);
}

void delete_variable(Variable *v) {
	if(v && !CALCULATOR->stillHasVariable(v)) {
		show_message(_("Variable does not exist anymore."), GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_dialog")));
		update_vmenu();
		return;
	}
	if(v && v->isLocal()) {
		for(size_t i = 0; i < recent_variables.size(); i++) {
			if(recent_variables[i] == v) {
				recent_variables.erase(recent_variables.begin() + i);
				gtk_widget_destroy(recent_variable_items[i]);
				recent_variable_items.erase(recent_variable_items.begin() + i);
				break;
			}
		}
		//ensure that all references are removed in Calculator
		v->destroy();
		update_vmenu();
	}
}


/*
	display edit/new variable dialog
	creates new variable if v == NULL, mstruct_ is forced value, win is parent window
*/
void edit_variable(const char *category, Variable *var, MathStructure *mstruct_, GtkWidget *win) {

	if(var != NULL && !var->isKnown()) {
		edit_unknown(category, var, win);
		return;
	}
	KnownVariable *v = (KnownVariable*) var;
	
	CALCULATOR->beginTemporaryStopMessages();
	if(v != NULL && v->get().isVector() && (!mstruct_ || mstruct_->isVector()) && (v->get().size() != 1 || !v->get()[0].isVector() || v->get()[0].size() > 0)) {
		CALCULATOR->endTemporaryStopMessages();
		edit_matrix(category, v, mstruct_, win);
		return;
	}

	edited_variable = v;
	names_edited = false;
	editing_variable = true;
	GtkWidget *dialog = get_variable_edit_dialog();
	if(win) gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(win));

	if(v) {
		if(v->isLocal())
			gtk_window_set_title(GTK_WINDOW(dialog), _("Edit Variable"));
		else
			gtk_window_set_title(GTK_WINDOW(dialog), _("Edit Variable (global)"));
	} else {
		gtk_window_set_title(GTK_WINDOW(dialog), _("New Variable"));
	}

	gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(variableedit_builder, "variable_edit_label_names")), "");

	if(mstruct_) {
		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(variableedit_builder, "variable_edit_box_names")));
		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(variableedit_builder, "variable_edit_box_value")));
		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(variableedit_builder, "variable_edit_checkbutton_exact")));
	} else {
		gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(variableedit_builder, "variable_edit_box_names")));
		gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(variableedit_builder, "variable_edit_box_value")));
		gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(variableedit_builder, "variable_edit_checkbutton_exact")));
	}

	if(v) {
		//fill in original parameters
		set_name_label_and_entry(v, GTK_WIDGET(gtk_builder_get_object(variableedit_builder, "variable_edit_entry_name")), GTK_WIDGET(gtk_builder_get_object(variableedit_builder, "variable_edit_label_names")));
		string value_str;
		if(v->isExpression()) {
			value_str = CALCULATOR->localizeExpression(v->expression());
			bool is_relative = false;
			if(!v->uncertainty(&is_relative).empty()) {
				if(is_relative) {
					value_str.insert(0, "(");
					value_str.insert(0, CALCULATOR->f_uncertainty->referenceName());
					value_str += CALCULATOR->getComma();
					value_str += " ";
					value_str += v->uncertainty();
					value_str += CALCULATOR->getComma();
					value_str += " 1)";
				} else {
					value_str += SIGN_PLUSMINUS;
					value_str += v->uncertainty();
				}
			}
			if(!v->unit().empty() && v->unit() != "auto") {value_str += " "; value_str += v->unit();}
		} else {
			value_str = get_value_string(v->get(), false, NULL);
		}
		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(variableedit_builder, "variable_edit_entry_value")), value_str.c_str());
		bool b_approx = *printops.is_approximate || v->isApproximate();
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(variableedit_builder, "variable_edit_checkbutton_exact")), !b_approx);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(variableedit_builder, "variable_edit_entry_name")), !v->isBuiltin());
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(variableedit_builder, "variable_edit_entry_value")), !v->isBuiltin());
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(variableedit_builder, "variable_edit_checkbutton_exact")), !v->isBuiltin());
		gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(variableedit_builder, "variable_edit_combo_category")))), v->category().c_str());
		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(variableedit_builder, "variable_edit_entry_desc")), v->title(false).c_str());
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(variableedit_builder, "variable_edit_button_ok")), FALSE);
	} else {
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(variableedit_builder, "variable_edit_entry_name")), TRUE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(variableedit_builder, "variable_edit_entry_value")), TRUE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(variableedit_builder, "variable_edit_checkbutton_exact")), TRUE);

		//fill in default values
		string v_name = CALCULATOR->getName();
		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(variableedit_builder, "variable_edit_entry_name")), v_name.c_str());
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(variableedit_builder, "variable_edit_label_names")), "");
		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(variableedit_builder, "variable_edit_entry_value")), displayed_mstruct ? get_value_string(*mstruct).c_str() : get_expression_text().c_str());
		gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(variableedit_builder, "variable_edit_combo_category")))), category);
		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(variableedit_builder, "variable_edit_entry_desc")), "");
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(variableedit_builder, "variable_edit_checkbutton_exact")), !mstruct_ || !mstruct_->isApproximate());
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(variableedit_builder, "variable_edit_button_ok")), TRUE);
	}
	
	CALCULATOR->endTemporaryStopMessages();
	
	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(variableedit_builder, "variable_edit_entry_name")));

run_variable_edit_dialog:
	gint response = gtk_dialog_run(GTK_DIALOG(dialog));
	if(response == GTK_RESPONSE_OK) {
		//clicked "OK"
		string str = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(variableedit_builder, "variable_edit_entry_name")));
		string str2 = CALCULATOR->unlocalizeExpression(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(variableedit_builder, "variable_edit_entry_value"))), evalops.parse_options);
		remove_blank_ends(str);
		remove_blank_ends(str2);
		GtkTreeIter iter;
		if(str.empty() && (!names_edited || !gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tNames_store), &iter))) {
			//no name -- open dialog again
			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(variableedit_builder, "variable_edit_entry_name")));
			show_message(_("Empty name field."), dialog);
			goto run_variable_edit_dialog;
		}
		if(str2.empty() && !mstruct_) {
			//no value -- open dialog again
			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(variableedit_builder, "variable_edit_entry_value")));
			show_message(_("Empty value field."), dialog);
			goto run_variable_edit_dialog;
		}
		//variable with the same name exists -- overwrite or open dialog again
		if((!v || !v->hasName(str)) && (!names_edited || !gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tNames_store), &iter)) && CALCULATOR->variableNameTaken(str, v) && !ask_question(_("An unit or variable with the same name already exists.\nDo you want to overwrite it?"), dialog)) {
			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(variableedit_builder, "variable_edit_entry_name")));
			goto run_variable_edit_dialog;
		}
		if(!v) {
			//no need to create a new variable when a variable with the same name exists
			var = CALCULATOR->getActiveVariable(str);
			if(var && var->isLocal() && var->isKnown()) v = (KnownVariable*) var;
		}
		bool add_var = false;
		if(v) {
			//update existing variable
			v->setLocal(true);
			if(!v->isBuiltin()) {
				if(mstruct_) {
					v->set(*mstruct_);
				} else {
					v->set(str2);
				}
				v->setApproximate(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(variableedit_builder, "variable_edit_checkbutton_exact"))));
			}
		} else {
			//new variable
			if(mstruct_) {
				//forced value
				v = new KnownVariable("", "", *mstruct_, "", true);
			} else {
				v = new KnownVariable("", "", str2, "", true);
				v->setApproximate(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(variableedit_builder, "variable_edit_checkbutton_exact"))));
			}
			add_var = true;
		}
		if(v) {
			v->setCategory(gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(gtk_builder_get_object(variableedit_builder, "variable_edit_combo_category"))));
			v->setTitle(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(variableedit_builder, "variable_edit_entry_desc"))));
			set_edited_names(v, str);
			if(add_var) {
				CALCULATOR->addVariable(v);
			}
			//select the new variable
			selected_variable = v;
			if(!v->isActive()) {
				selected_variable_category = _("Inactive");
			} else if(v->category().empty()) {
				selected_variable_category = _("Uncategorized");
			} else {
				selected_variable_category = "/";
				selected_variable_category += v->category();
			}
		}
		update_vmenu();
		variable_inserted(v);
	} else if(response == GTK_RESPONSE_HELP) {
		show_help("qalculate-variables.html#qalculate-variable-creation", gtk_builder_get_object(variableedit_builder, "variable_edit_dialog")); 
		goto run_variable_edit_dialog;
	}
	edited_variable = NULL;
	names_edited = false;
	editing_variable = false;
	gtk_widget_hide(dialog);
}

/*
	display edit/new matrix dialog
	creates new matrix if v == NULL, mstruct_ is forced value, win is parent window
*/
void edit_matrix(const char *category, Variable *var, MathStructure *mstruct_, GtkWidget *win, gboolean create_vector) {

	if(var != NULL && !var->isKnown()) {
		edit_unknown(category, var, win);
		return;
	}
	
	KnownVariable *v = (KnownVariable*) var;

	if((v && !v->get().isVector()) || (mstruct_ && !mstruct_->isVector())) {
		edit_variable(category, v, mstruct_, win);
		return;
	}
	
	edited_matrix = v;
	names_edited = false;
	editing_matrix = true;

	GtkWidget *dialog = get_matrix_edit_dialog();
	if(win) gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(win));
	if(mstruct_) {
		create_vector = !mstruct_->isMatrix();
	} else if(v) {
		create_vector = !v->get().isMatrix();	
	}
	if(create_vector) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(matrixedit_builder, "matrix_edit_radiobutton_vector")), TRUE);
	else gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(matrixedit_builder, "matrix_edit_radiobutton_matrix")), TRUE);

	if(create_vector) {
		if(v) {
			if(v->isLocal())
				gtk_window_set_title(GTK_WINDOW(dialog), _("Edit Vector"));
			else
				gtk_window_set_title(GTK_WINDOW(dialog), _("Edit Vector (global)"));
		} else {
			gtk_window_set_title(GTK_WINDOW(dialog), _("New Vector"));
		}
	} else {
		if(v) {
			if(v->isLocal())
				gtk_window_set_title(GTK_WINDOW(dialog), _("Edit Matrix"));
			else
				gtk_window_set_title(GTK_WINDOW(dialog), _("Edit Matrix (global)"));
		} else {
			gtk_window_set_title(GTK_WINDOW(dialog), _("New Matrix"));
		}	
	}

	int r = 4, c = 4;
	const MathStructure *old_vctr = NULL;
	if(v) {
		if(create_vector) {
			old_vctr = &v->get();
		} else {
			c = v->get().columns();
			r = v->get().rows();
		}	
		//fill in original parameters
		set_name_label_and_entry(v, GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_entry_name")), GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_label_names")));
		//can only change name and value of user variable
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_entry_name")), !v->isBuiltin());
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_spinbutton_rows")), !v->isBuiltin());		
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_spinbutton_columns")), !v->isBuiltin());				
		//gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_table_elements")), !v->isBuiltin());
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_radiobutton_matrix")), !v->isBuiltin());						
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_radiobutton_vector")), !v->isBuiltin());								
		gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(matrixedit_builder, "matrix_edit_combo_category")))), v->category().c_str());
		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(matrixedit_builder, "matrix_edit_entry_desc")), v->title(false).c_str());	
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_button_ok")), FALSE);
	} else {
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_entry_name")), TRUE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_spinbutton_rows")), TRUE);		
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_spinbutton_columns")), TRUE);				
		//gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_table_elements")), TRUE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_radiobutton_matrix")), TRUE);						
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_radiobutton_vector")), TRUE);								
	
		//fill in default values
		string v_name = CALCULATOR->getName();
		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(matrixedit_builder, "matrix_edit_entry_name")), v_name.c_str());
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(matrixedit_builder, "matrix_edit_label_names")), "");
		gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(matrixedit_builder, "matrix_edit_combo_category")))), category);
		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(matrixedit_builder, "matrix_edit_entry_desc")), "");
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_button_ok")), TRUE);
	}
	if(mstruct_) {
		//forced value
		if(create_vector) {
			old_vctr = mstruct_;
		} else {
			c = mstruct_->columns();
			r = mstruct_->rows();
		}
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_spinbutton_rows")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_spinbutton_columns")), FALSE);				
		//gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_table_elements")), FALSE);						
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_radiobutton_matrix")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_radiobutton_vector")), FALSE);
		
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_button_ok")), TRUE);
	}

	if(create_vector) {
		if(old_vctr) {
			r = old_vctr->countChildren();
			c = (int) ::sqrt(::sqrt((double) r)) + 8;
			if(c < 10) c = 10;
			if(r % c > 0) {
				r = r / c + 1;
			} else {
				r = r / c;
			}
			if(r < 100) r = 100;
		} else {
			c = 10;
			r = 100;
		}
	}

	gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(matrixedit_builder, "matrix_edit_spinbutton_rows")), r);	
	gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(matrixedit_builder, "matrix_edit_spinbutton_columns")), c);
	on_matrix_edit_spinbutton_columns_value_changed(GTK_SPIN_BUTTON(gtk_builder_get_object(matrixedit_builder, "matrix_edit_spinbutton_columns")), NULL);
	on_matrix_edit_spinbutton_rows_value_changed(GTK_SPIN_BUTTON(gtk_builder_get_object(matrixedit_builder, "matrix_edit_spinbutton_rows")), NULL);		

	CALCULATOR->startControl(2000);
	PrintOptions po;
	po.number_fraction_format = FRACTION_DECIMAL_EXACT;
	po.interval_display = INTERVAL_DISPLAY_PLUSMINUS;
	while(gtk_events_pending()) gtk_main_iteration();
	GtkTreeIter iter;
	bool b = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tMatrixEdit_store), &iter);
	for(size_t index_r = 0; b && index_r < (size_t) r; index_r++) {
		for(size_t index_c = 0; index_c < (size_t) c; index_c++) {
			if(create_vector) {
				if(old_vctr && index_r * c + index_c < old_vctr->countChildren()) {
					gtk_list_store_set(GTK_LIST_STORE(tMatrixEdit_store), &iter, index_c, old_vctr->getChild(index_r * c + index_c + 1)->print(po).c_str(), -1);
				} else {
					gtk_list_store_set(GTK_LIST_STORE(tMatrixEdit_store), &iter, index_c, "", -1);
				}
			} else {
				if(v) {
					gtk_list_store_set(GTK_LIST_STORE(tMatrixEdit_store), &iter, index_c, v->get().getElement(index_r + 1, index_c + 1)->print(po).c_str(), -1);
				} else if(mstruct_) {
					gtk_list_store_set(GTK_LIST_STORE(tMatrixEdit_store), &iter, index_c, mstruct_->getElement(index_r + 1, index_c + 1)->print(po).c_str(), -1);
				} else {
					gtk_list_store_set(GTK_LIST_STORE(tMatrixEdit_store), &iter, index_c, "0", -1);
				}
			}
		}
		b = gtk_tree_model_iter_next(GTK_TREE_MODEL(tMatrixEdit_store), &iter);
	}
	CALCULATOR->stopControl();
	if(r > 0 && c > 0) {
		GtkTreePath *path = gtk_tree_path_new_from_indices(0, -1);
		gtk_tree_view_set_cursor(GTK_TREE_VIEW(tMatrixEdit), path, matrix_edit_columns[0], TRUE);
		while(gtk_events_pending()) gtk_main_iteration();
		gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(tMatrixEdit), path, matrix_edit_columns[0], FALSE, 0.0, 0.0);
		on_tMatrixEdit_cursor_changed(GTK_TREE_VIEW(tMatrixEdit), NULL);
		gtk_tree_path_free(path);
	} else {
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(matrixedit_builder, "matrix_edit_label_position")), "");
	}
	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_entry_name")));
	
run_matrix_edit_dialog:
	gint response = gtk_dialog_run(GTK_DIALOG(dialog));
	if(response == GTK_RESPONSE_OK) {
		//clicked "OK"
		string str = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(matrixedit_builder, "matrix_edit_entry_name")));
		remove_blank_ends(str);
		GtkTreeIter iter;
		if(str.empty() && (!names_edited || !gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tNames_store), &iter))) {
			//no name -- open dialog again
			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_entry_name")));
			show_message(_("Empty name field."), dialog);
			goto run_matrix_edit_dialog;
		}

		//variable with the same name exists -- overwrite or open dialog again
		if((!v || !v->hasName(str)) && (!names_edited || !gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tNames_store), &iter)) && CALCULATOR->variableNameTaken(str) && !ask_question(_("An unit or variable with the same name already exists.\nDo you want to overwrite it?"), dialog)) {
			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_entry_name")));
			goto run_matrix_edit_dialog;
		}
		if(!v) {
			//no need to create a new variable when a variable with the same name exists
			var = CALCULATOR->getActiveVariable(str);
			if(var && var->isLocal() && var->isKnown()) v = (KnownVariable*) var;
		}
		MathStructure mstruct_new;
		if(!mstruct_) {
			b = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tMatrixEdit_store), &iter);
			c = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_builder_get_object(matrixedit_builder, "matrix_edit_spinbutton_columns")));
			r = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_builder_get_object(matrixedit_builder, "matrix_edit_spinbutton_rows")));
			gchar *gstr = NULL;
			string mstr;
			do_timeout = false;
			if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(matrixedit_builder, "matrix_edit_radiobutton_vector")))) {
				mstruct_new.clearVector();
				for(size_t index_r = 0; index_r < (size_t) r && b; index_r++) {
					for(size_t index_c = 0; index_c < (size_t) c; index_c++) {
						gtk_tree_model_get(GTK_TREE_MODEL(tMatrixEdit_store), &iter, index_c, &gstr, -1);
						mstr = gstr;
						g_free(gstr);
						remove_blank_ends(mstr);
						if(!mstr.empty()) {
							mstruct_new.addChild(CALCULATOR->parse(CALCULATOR->unlocalizeExpression(mstr, evalops.parse_options), evalops.parse_options));
						}
					}
					b = gtk_tree_model_iter_next(GTK_TREE_MODEL(tMatrixEdit_store), &iter);
				}
			} else {
				mstruct_new.clearMatrix();
				mstruct_new.resizeMatrix((size_t) r, (size_t) c, m_undefined);
				for(size_t index_r = 0; index_r < (size_t) r && b; index_r++) {
					for(size_t index_c = 0; index_c < (size_t) c; index_c++) {
						gtk_tree_model_get(GTK_TREE_MODEL(tMatrixEdit_store), &iter, index_c, &gstr, -1);
						mstr = gstr;
						g_free(gstr);
						remove_blank_ends(mstr);
						mstruct_new.setElement(CALCULATOR->parse(CALCULATOR->unlocalizeExpression(mstr, evalops.parse_options), evalops.parse_options), index_r + 1, index_c + 1);
					}
					b = gtk_tree_model_iter_next(GTK_TREE_MODEL(tMatrixEdit_store), &iter);
				}
			}
			display_errors(NULL, dialog);
			do_timeout = true;
		}
		bool add_var = false;
		if(v) {
			v->setLocal(true);
			//update existing variable
			if(!v->isBuiltin()) {
				if(mstruct_) {
					v->set(*mstruct_);
				} else {
					v->set(mstruct_new);
				}
			}
		} else {
			//new variable
			if(mstruct_) {
				v = new KnownVariable("", "", *mstruct_, "", true);
			} else {
				v = new KnownVariable("", "", mstruct_new, "", true);
			}
			add_var = true;
		}
		if(v) {
			v->setCategory(gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(gtk_builder_get_object(matrixedit_builder, "matrix_edit_combo_category"))));
			v->setTitle(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(matrixedit_builder, "matrix_edit_entry_desc"))));
			set_edited_names(v, str);
			if(add_var) {
				CALCULATOR->addVariable(v);
			}
			//select the new variable
			selected_variable = v;
			if(!v->isActive()) {
				selected_variable_category = _("Inactive");
			} else if(v->category().empty()) {
				selected_variable_category = _("Uncategorized");
			} else {
				selected_variable_category = "/";
				selected_variable_category += v->category();
			}
		}
		update_vmenu();
		variable_inserted(v);
	} else if(response == GTK_RESPONSE_HELP) {
		show_help("qalculate-variables.html#qalculate-vectors-matrices", gtk_builder_get_object(matrixedit_builder, "matrix_edit_dialog")); 
		goto run_matrix_edit_dialog;
	}
	edited_matrix = NULL;
	names_edited = false;
	editing_matrix = false;
	gtk_widget_hide(dialog);
}

void insert_matrix(const MathStructure *initial_value, GtkWidget *win, gboolean create_vector, bool is_text_struct, bool is_result) {

	GtkWidget *dialog = get_matrix_dialog();
	if(win) gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(win));

	if(initial_value && !initial_value->isVector()) {
		return;
	}
	
	GtkTextIter istart, iend;
	gtk_text_buffer_get_selection_bounds(expressionbuffer, &istart, &iend);

	if(initial_value) {
		create_vector = !initial_value->isMatrix();
	}
	if(create_vector) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(matrix_builder, "matrix_radiobutton_vector")), TRUE);
	else gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(matrix_builder, "matrix_radiobutton_matrix")), TRUE);

	if(is_result) {
		gtk_button_set_label(GTK_BUTTON(gtk_builder_get_object(matrix_builder, "matrix_button_cancel")), _("_Close"));
		gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(matrix_builder, "matrix_button_cancel")));
		if(create_vector) {
			gtk_window_set_title(GTK_WINDOW(dialog), _("Vector Result"));
		} else {
			gtk_window_set_title(GTK_WINDOW(dialog), _("Matrix Result"));
		}
	} else {
		gtk_button_set_label(GTK_BUTTON(gtk_builder_get_object(matrix_builder, "matrix_button_cancel")), _("_Cancel"));
		gtk_widget_grab_focus(tMatrix);
		if(create_vector) {
			gtk_window_set_title(GTK_WINDOW(dialog), _("Vector"));
		} else {
			gtk_window_set_title(GTK_WINDOW(dialog), _("Matrix"));
		}
	}

	int r = 4, c = 4;
	if(create_vector) {
		if(initial_value) {
			r = initial_value->countChildren();
			c = (int) sqrt(::sqrt(r)) + 8;
			if(c < 10) c = 10;
			if(r % c > 0) {
				r = r / c + 1;
			} else {
				r = r / c;
			}
			if(r < 100) r = 100;
		} else {
			c = 10;
			r = 100;
		}
	} else if(initial_value) {
		c = initial_value->columns();
		r = initial_value->rows();
	}

	gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(matrix_builder, "matrix_spinbutton_rows")), r);
	gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(matrix_builder, "matrix_spinbutton_columns")), c);
	on_matrix_spinbutton_columns_value_changed(GTK_SPIN_BUTTON(gtk_builder_get_object(matrix_builder, "matrix_spinbutton_columns")), NULL);
	on_matrix_spinbutton_rows_value_changed(GTK_SPIN_BUTTON(gtk_builder_get_object(matrix_builder, "matrix_spinbutton_rows")), NULL);


	printops.can_display_unicode_string_arg = (void*) tMatrix;
	while(gtk_events_pending()) gtk_main_iteration();
	GtkTreeIter iter;
	bool b = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tMatrix_store), &iter);
	CALCULATOR->startControl(5000);
	for(size_t index_r = 0; b && index_r < (size_t) r; index_r++) {
		for(size_t index_c = 0; index_c < (size_t) c; index_c++) {
			if(create_vector) {
				if(initial_value && index_r * c + index_c < initial_value->countChildren()) {
					if(is_text_struct) gtk_list_store_set(GTK_LIST_STORE(tMatrix_store), &iter, index_c, initial_value->getChild(index_r * c + index_c + 1)->symbol().c_str(), -1);
					else gtk_list_store_set(GTK_LIST_STORE(tMatrix_store), &iter, index_c, initial_value->getChild(index_r * c + index_c + 1)->print(printops).c_str(), -1);
				} else {
					gtk_list_store_set(GTK_LIST_STORE(tMatrix_store), &iter, index_c, "", -1);
				}
			} else {
				if(initial_value) {
					if(is_text_struct) gtk_list_store_set(GTK_LIST_STORE(tMatrix_store), &iter, index_c, initial_value->getElement(index_r + 1, index_c + 1)->symbol().c_str(), -1);
					else gtk_list_store_set(GTK_LIST_STORE(tMatrix_store), &iter, index_c, initial_value->getElement(index_r + 1, index_c + 1)->print(printops).c_str(), -1);
				} else {
					gtk_list_store_set(GTK_LIST_STORE(tMatrix_store), &iter, index_c, "0", -1);
				}
			}
		}
		b = gtk_tree_model_iter_next(GTK_TREE_MODEL(tMatrix_store), &iter);
	}
	CALCULATOR->stopControl();

	if(r > 0 && c > 0) {
		GtkTreePath *path = gtk_tree_path_new_from_indices(0, -1);
		gtk_tree_view_set_cursor(GTK_TREE_VIEW(tMatrix), path, matrix_columns[0], TRUE);
		while(gtk_events_pending()) gtk_main_iteration();
		gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(tMatrix), path, matrix_columns[0], FALSE, 0.0, 0.0);
		on_tMatrix_cursor_changed(GTK_TREE_VIEW(tMatrix), NULL);
		gtk_tree_path_free(path);
	} else {
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(matrix_builder, "matrix_label_position")), "");
	}
	printops.can_display_unicode_string_arg = NULL;

	gint response = gtk_dialog_run(GTK_DIALOG(dialog));
	if(response == GTK_RESPONSE_OK) {
		//clicked "OK"
		string matrixstr, str;
		bool b = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tMatrix_store), &iter);
		c = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_builder_get_object(matrix_builder, "matrix_spinbutton_columns")));
		r = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_builder_get_object(matrix_builder, "matrix_spinbutton_rows")));
		gchar *gstr = NULL;
		if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(matrix_builder, "matrix_radiobutton_vector")))) {
			bool b1 = false;
			matrixstr = "[";
			for(size_t index_r = 0; index_r < (size_t) r && b; index_r++) {
				for(size_t index_c = 0; index_c < (size_t) c; index_c++) {
					gtk_tree_model_get(GTK_TREE_MODEL(tMatrix_store), &iter, index_c, &gstr, -1);
					str = gstr;
					g_free(gstr);
					remove_blank_ends(str);
					if(!str.empty()) {
						if(b1) {
							matrixstr += CALCULATOR->getComma();
							matrixstr += " ";
						} else {
							b1 = true;
						}
						matrixstr += str;
					}
				}
				b = gtk_tree_model_iter_next(GTK_TREE_MODEL(tMatrix_store), &iter);
			}
			matrixstr += "]";
		} else {
			matrixstr = "[";
			bool b1 = false;
			for(size_t index_r = 0; index_r < (size_t) r && b; index_r++) {
				if(b1) {
					matrixstr += CALCULATOR->getComma();
					matrixstr += " ";
				} else {
					b1 = true;
				}
				matrixstr += "[";
				bool b2 = false;
				for(size_t index_c = 0; index_c < (size_t) c; index_c++) {
					if(b2) {
						matrixstr += CALCULATOR->getComma();
						matrixstr += " ";
					} else {
						b2 = true;
					}
					gtk_tree_model_get(GTK_TREE_MODEL(tMatrix_store), &iter, index_c, &gstr, -1);
					str = gstr;
					remove_blank_ends(str);
					g_free(gstr);
					matrixstr += str;
				}
				matrixstr += "]";
				b = gtk_tree_model_iter_next(GTK_TREE_MODEL(tMatrix_store), &iter);
			}
			matrixstr += "]";
		}
		gtk_text_buffer_select_range(expressionbuffer, &istart, &iend);
		insert_text(matrixstr.c_str());
	}
	gtk_widget_hide(dialog);
}


void edit_dataobject(DataSet *ds, DataObject *o, GtkWidget *win) {
	if(!ds) return;
	GtkWidget *dialog = get_dataobject_edit_dialog();
	if(o) {
		gtk_window_set_title(GTK_WINDOW(dialog), _("Edit Data Object"));
	} else {
		gtk_window_set_title(GTK_WINDOW(dialog), _("New Data Object"));
	}
	if(win) gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(win));
	GtkWidget *ptable = GTK_WIDGET(gtk_builder_get_object(datasets_builder, "dataobject_edit_grid"));
	GList *childlist = gtk_container_get_children(GTK_CONTAINER(ptable));
	for(guint i = 0; ; i++) {
		GtkWidget *w = (GtkWidget*) g_list_nth_data(childlist, i);
		if(!w) break;
		gtk_widget_destroy(w);
	}
	g_list_free(childlist);
	DataPropertyIter it;
	DataProperty *dp = ds->getFirstProperty(&it);
	string sval;
	int rows = 1;
	gtk_grid_remove_column(GTK_GRID(ptable), 0);
	gtk_grid_remove_column(GTK_GRID(ptable), 1);
	gtk_grid_remove_column(GTK_GRID(ptable), 2);
	gtk_grid_remove_column(GTK_GRID(ptable), 3);
	gtk_grid_set_column_spacing(GTK_GRID(ptable), 20);
	GtkWidget *label, *entry, *om;
	vector<GtkWidget*> value_entries;
	vector<GtkWidget*> approx_menus;
	string str;
	while(dp) {
		label = gtk_label_new(dp->title().c_str()); gtk_widget_set_halign(label, GTK_ALIGN_START);
		gtk_grid_attach(GTK_GRID(ptable), label, 0, rows - 1, 1, 1);
		
		entry = gtk_entry_new();
		value_entries.push_back(entry);
		int iapprox = -1;
		if(o) {
			gtk_entry_set_text(GTK_ENTRY(entry), o->getProperty(dp, &iapprox).c_str());
		}
		gtk_grid_attach(GTK_GRID(ptable), entry, 1, rows - 1, 1, 1);
		
		label = gtk_label_new(dp->getUnitString().c_str()); gtk_widget_set_halign(label, GTK_ALIGN_START);
		gtk_grid_attach(GTK_GRID(ptable), label, 2, rows - 1, 1, 1);
		
		om = gtk_combo_box_text_new();
		approx_menus.push_back(om);
		gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(om), NULL, _("Default"));
		gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(om), NULL, _("Approximate"));
		gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(om), NULL, _("Exact"));
		gtk_combo_box_set_active(GTK_COMBO_BOX(om), iapprox + 1);
		
		g_signal_connect(entry, "changed", G_CALLBACK(on_dataobject_changed), NULL);
		g_signal_connect(om, "changed", G_CALLBACK(on_dataobject_changed), NULL);

		gtk_grid_attach(GTK_GRID(ptable), om, 3, rows - 1, 1, 1);

		rows++;
		dp = ds->getNextProperty(&it);
	}
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasets_builder, "dataobject_edit_button_ok")), FALSE);
	gtk_widget_show_all(ptable);
	if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) {
		bool new_object = (o == NULL);
		if(new_object) {
			o = new DataObject(ds);
			ds->addObject(o);
		}
		dp = ds->getFirstProperty(&it);
		size_t i = 0;
		string val;
		while(dp) {
			val = gtk_entry_get_text(GTK_ENTRY(value_entries[i]));
			remove_blank_ends(val);
			if(!val.empty()) {
				o->setProperty(dp, val, gtk_combo_box_get_active(GTK_COMBO_BOX(approx_menus[i])) - 1);
			} else if(!new_object) {
				o->eraseProperty(dp);
			}
			dp = ds->getNextProperty(&it);
			i++;
		}
		o->setUserModified();
		selected_dataobject = o;
		update_dataobjects();
	}
	/*for(size_t i = 0; i < approx_menus.size(); i++) {
		menu = gtk_option_menu_get_menu(GTK_OPTION_MENU(approx_menus[i]));
		gtk_widget_destroy(menu);
	}*/
	gtk_widget_hide(dialog);
}

void update_dataset_property_list(DataSet*) {
	if(!datasetedit_builder) return;
	selected_dataproperty = NULL;
	gtk_list_store_clear(tDataProperties_store);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasetedit_builder, "dataset_edit_button_edit_property")), FALSE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasetedit_builder, "dataset_edit_button_del_property")), FALSE);
	GtkTreeIter iter;
	string str;
	for(size_t i = 0; i < tmp_props.size(); i++) {
		if(tmp_props[i]) {
			gtk_list_store_append(tDataProperties_store, &iter);
			str = "";
			switch(tmp_props[i]->propertyType()) {
				case PROPERTY_STRING: {
					str += _("text");
					break;
				}
				case PROPERTY_NUMBER: {
					if(tmp_props[i]->isApproximate()) {
						str += _("approximate");
						str += " ";
					}
					str += _("number");
					break;
				}
				case PROPERTY_EXPRESSION: {
					if(tmp_props[i]->isApproximate()) {
						str += _("approximate");
						str += " ";
					}
					str += _("expression");
					break;
				}
			}
			if(tmp_props[i]->isKey()) {
				str += " (";
				str += _("key");
				str += ")";
			}
			gtk_list_store_set(tDataProperties_store, &iter, 0, tmp_props[i]->title(false).c_str(), 1, tmp_props[i]->getName().c_str(), 2, str.c_str(), 3, (gpointer) tmp_props[i], -1);
		}
	}
}

bool edit_dataproperty(DataProperty *dp, bool new_property = false) {

	GtkWidget *dialog = get_dataproperty_edit_dialog();	
	gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gtk_builder_get_object(datasetedit_builder, "dataset_edit_dialog")));

	edited_dataproperty = dp;	
	names_edited = false;
	editing_dataproperty = true;

	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_entry_name")), dp->getName().c_str());
	if(dp->countNames() > 1) {
		string str = "+ ";
		for(size_t i = 2; i <= dp->countNames(); i++) {
			if(i > 2) str += ", ";
			str += dp->getName(i);
		}
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_label_names")), str.c_str());
	} else {
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_label_names")), "");
	}

	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_entry_title")), dp->title(false).c_str());
	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_entry_unit")), dp->getUnitString().c_str());

	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_checkbutton_hide")), dp->isHidden());
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_checkbutton_key")), dp->isKey());
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_checkbutton_approximate")), dp->isApproximate());
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_checkbutton_case")), dp->isCaseSensitive());
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_checkbutton_brackets")), dp->usesBrackets());
	
	GtkTextBuffer *description_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_textview_description")));
	gtk_text_buffer_set_text(description_buffer, dp->description().c_str(), -1);

	switch(dp->propertyType()) {	
		case PROPERTY_STRING: {
			gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_combobox_type")), 0);
			break;
		}
		case PROPERTY_NUMBER: {
			gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_combobox_type")), 1);
			break;
		}
		case PROPERTY_EXPRESSION: {
			gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_combobox_type")), 2);
			break;
		}
	}
	
	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_entry_name")));
	
	bool return_val = false;
	
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_button_ok")), new_property);

	run_dataproperty_edit_dialog:
	if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) {
	
		string str = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_entry_name")));
		remove_blank_ends(str);
		GtkTreeIter iter;
		if(str.empty() && (!names_edited || !gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tNames_store), &iter))) {
			//no name -- open dialog again
			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_entry_name")));
			show_message(_("Empty name field."), dialog);
			goto run_dataproperty_edit_dialog;
		}
	
		dp->setTitle(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_entry_title"))));
		dp->setUnit(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_entry_unit"))));
		
		dp->setHidden(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_checkbutton_hide"))));
		dp->setKey(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_checkbutton_key"))));
		dp->setApproximate(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_checkbutton_approximate"))));
		dp->setCaseSensitive(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_checkbutton_case"))));
		dp->setUsesBrackets(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_checkbutton_brackets"))));
	
		GtkTextIter e_iter_s, e_iter_e;
		gtk_text_buffer_get_start_iter(description_buffer, &e_iter_s);
		gtk_text_buffer_get_end_iter(description_buffer, &e_iter_e);
		gchar *gstr = gtk_text_buffer_get_text(description_buffer, &e_iter_s, &e_iter_e, FALSE);
		dp->setDescription(gstr);
		g_free(gstr);
		
		switch(gtk_combo_box_get_active(GTK_COMBO_BOX(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_combobox_type")))) {
			case 0: {
				dp->setPropertyType(PROPERTY_STRING);
				break;
			}
			case 1: {
				dp->setPropertyType(PROPERTY_NUMBER);
				break;
			}
			case 2: {
				dp->setPropertyType(PROPERTY_EXPRESSION);
				break;
			}
		}
		if(names_edited) {
			dp->clearNames();
			GtkTreeIter iter;
			if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tNames_store), &iter)) {
				gchar *gstr;
				while(true) {	
					gboolean reference = FALSE;
					gtk_tree_model_get(GTK_TREE_MODEL(tNames_store), &iter, NAMES_NAME_COLUMN, &gstr, NAMES_REFERENCE_COLUMN, &reference, -1);
					dp->addName(gstr, reference);
					g_free(gstr);
					if(!gtk_tree_model_iter_next(GTK_TREE_MODEL(tNames_store), &iter)) break;
				}
			} else {
				dp->addName(str);
			}
		} else {
			dp->setName(str, 1);
		}
		
		return_val = true;
			
	}
	
	names_edited = false;
	editing_dataproperty = false;
	edited_dataproperty = NULL;
	
	gtk_widget_hide(dialog);
	
	return return_val;
	
}


void edit_dataset(DataSet *ds, GtkWidget *win) {
	GtkWidget *dialog = get_dataset_edit_dialog();
	if(win) gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(win));
	
	edited_dataset = ds;
	names_edited = false;
	editing_dataset = true;
	
	if(ds) {
		if(ds->isLocal())
			gtk_window_set_title(GTK_WINDOW(dialog), _("Edit Data Set"));
		else
			gtk_window_set_title(GTK_WINDOW(dialog), _("Edit Data Set (global)"));		
	} else {
		gtk_window_set_title(GTK_WINDOW(dialog), _("New Data Set"));
	}

	GtkTextBuffer *description_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtk_builder_get_object(datasetedit_builder, "dataset_edit_textview_description")));
	GtkTextBuffer *copyright_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtk_builder_get_object(datasetedit_builder, "dataset_edit_textview_copyright")));

	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasetedit_builder, "dataset_edit_textview_copyright")), !ds || ds->isLocal());
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasetedit_builder, "dataset_edit_entry_file")), !ds || ds->isLocal());

	//clear entries
	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataset_edit_entry_name")), "");
	gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(datasetedit_builder, "dataset_edit_label_names")), "");
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasetedit_builder, "dataset_edit_entry_name")), TRUE);
	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataset_edit_entry_desc")), "");
	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataset_edit_entry_file")), "");
	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataset_edit_entry_object_name")), "");
	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataset_edit_entry_property_name")), "");
	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataset_edit_entry_default_property")), _("info"));
	gtk_text_buffer_set_text(description_buffer, "", -1);
	gtk_text_buffer_set_text(copyright_buffer, "", -1);

	gtk_list_store_clear(tDataProperties_store);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasetedit_builder, "dataset_edit_button_edit_property")), FALSE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasetedit_builder, "dataset_edit_button_del_property")), FALSE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasetedit_builder, "dataset_edit_button_new_property")), TRUE);
	
	if(ds) {
		//fill in original paramaters
		set_name_label_and_entry(ds, GTK_WIDGET(gtk_builder_get_object(datasetedit_builder, "dataset_edit_entry_name")), GTK_WIDGET(gtk_builder_get_object(datasetedit_builder, "dataset_edit_label_names")));
		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataset_edit_entry_desc")), ds->title(false).c_str());
		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataset_edit_entry_file")), ds->defaultDataFile().c_str());
		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataset_edit_entry_default_property")), ds->defaultProperty().c_str());
		Argument *arg = ds->getArgumentDefinition(1);
		if(arg) {
			gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataset_edit_entry_object_name")), arg->name().c_str());
		}
		arg = ds->getArgumentDefinition(2);
		if(arg) {
			gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataset_edit_entry_property_name")), arg->name().c_str());
		}
		gtk_text_buffer_set_text(description_buffer, ds->description().c_str(), -1);
		gtk_text_buffer_set_text(copyright_buffer, ds->copyright().c_str(), -1);
		DataPropertyIter it;
		DataProperty *dp = ds->getFirstProperty(&it);
		while(dp) {
			tmp_props.push_back(new DataProperty(*dp));
			tmp_props_orig.push_back(dp);
			dp = ds->getNextProperty(&it);
		}
		
	}
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasetedit_builder, "dataset_edit_button_ok")), FALSE);
	
	update_dataset_property_list(ds);
	
	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(datasetedit_builder, "dataset_edit_entry_name")));
	gtk_notebook_set_current_page(GTK_NOTEBOOK(gtk_builder_get_object(datasetedit_builder, "dataset_edit_tabs")), 0);
	
	run_dataset_edit_dialog:
	if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) {
		//clicked "OK"
		string str = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataset_edit_entry_name")));
		remove_blank_ends(str);
		GtkTreeIter iter;
		if(str.empty() && (!names_edited || !gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tNames_store), &iter))) {
			//no name -- open dialog again
			gtk_notebook_set_current_page(GTK_NOTEBOOK(gtk_builder_get_object(datasetedit_builder, "dataset_edit_tabs")), 2);
			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(datasetedit_builder, "dataset_edit_entry_name")));
			show_message(_("Empty name field."), dialog);
			goto run_dataset_edit_dialog;
		}
		GtkTextIter d_iter_s, d_iter_e;
		gtk_text_buffer_get_start_iter(description_buffer, &d_iter_s);
		gtk_text_buffer_get_end_iter(description_buffer, &d_iter_e);
		GtkTextIter c_iter_s, c_iter_e;
		gtk_text_buffer_get_start_iter(copyright_buffer, &c_iter_s);
		gtk_text_buffer_get_end_iter(copyright_buffer, &c_iter_e);
		//dataset with the same name exists -- overwrite or open the dialog again
		if((!ds || !ds->hasName(str)) && (!names_edited || !gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tNames_store), &iter)) && CALCULATOR->functionNameTaken(str, ds) && !ask_question(_("A function with the same name already exists.\nDo you want to overwrite the function?"), dialog)) {
			gtk_notebook_set_current_page(GTK_NOTEBOOK(gtk_builder_get_object(datasetedit_builder, "dataset_edit_tabs")), 2);
			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(datasetedit_builder, "dataset_edit_entry_name")));
			goto run_dataset_edit_dialog;
		}
		bool add_func = false;
		gchar *gstr_descr = gtk_text_buffer_get_text(description_buffer, &d_iter_s, &d_iter_e, FALSE);
		if(ds) {
			//edited an existing dataset
			ds->setTitle(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataset_edit_entry_desc"))));
			if(ds->isLocal()) ds->setDefaultDataFile(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataset_edit_entry_file"))));
			ds->setDescription(gstr_descr);
		} else {
			//new dataset
			ds = new DataSet(_("Data Sets"), "", gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataset_edit_entry_file"))), gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataset_edit_entry_desc"))), gstr_descr, true);
			add_func = true;
		}
		g_free(gstr_descr);
		string str2;
		if(ds) {
			str2 = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataset_edit_entry_object_name")));
			remove_blank_ends(str2);
			if(str2.empty()) str2 = _("Object");
			Argument *arg = ds->getArgumentDefinition(1);
			if(arg) {
				arg->setName(str2);
			}
			str2 = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataset_edit_entry_property_name")));
			remove_blank_ends(str2);
			if(str2.empty()) str2 = _("Property");
			arg = ds->getArgumentDefinition(2);
			if(arg) {
				arg->setName(str2);
			}
			ds->setDefaultProperty(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataset_edit_entry_default_property"))));
			gchar *gstr = gtk_text_buffer_get_text(copyright_buffer, &c_iter_s, &c_iter_e, FALSE);
			ds->setCopyright(gstr);
			g_free(gstr);
			for(size_t i = 0; i < tmp_props.size();) {
				if(!tmp_props[i]) {
					if(tmp_props_orig[i]) ds->delProperty(tmp_props_orig[i]);
					i++;
				} else if(tmp_props[i]->isUserModified()) {
					if(tmp_props_orig[i]) {
						tmp_props_orig[i]->set(*tmp_props[i]);
						i++;
					} else {
						ds->addProperty(tmp_props[i]);
						tmp_props.erase(tmp_props.begin() + i);
					}
				} else {
					i++;
				}
			}
			set_edited_names(ds, str);
			if(add_func) {
				CALCULATOR->addDataSet(ds);
				ds->loadObjects();
				ds->setObjectsLoaded(true);
			}
			selected_dataset = ds;
		}
		update_fmenu();	
		function_inserted(ds);
		update_datasets_tree();
	}
	for(size_t i = 0; i < tmp_props.size(); i++) {
		if(tmp_props[i]) delete tmp_props[i];
	}
	tmp_props.clear();
	tmp_props_orig.clear();
	edited_dataset = NULL;
	editing_dataset = false;
	names_edited = false;
	gtk_widget_hide(dialog);
}

void import_csv_file(GtkWidget *win) {

	GtkWidget *dialog = get_csv_import_dialog();
	if(win) gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(win));

	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(csvimport_builder, "csv_import_entry_name")), "");
	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(csvimport_builder, "csv_import_entry_file")), "");	
	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(csvimport_builder, "csv_import_entry_desc")), "");
	
	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(csvimport_builder, "csv_import_entry_file")));

run_csv_import_dialog:
	if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) {
		//clicked "OK"
		string str = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(csvimport_builder, "csv_import_entry_file")));
		remove_blank_ends(str);
		if(str.empty()) {
			//no filename -- open dialog again
			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(csvimport_builder, "csv_import_entry_file")));
			show_message(_("No file name entered."), dialog);
			goto run_csv_import_dialog;
		}
		string name_str = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(csvimport_builder, "csv_import_entry_name")));
		remove_blank_ends(name_str);
		if(name_str.empty()) {
			//no name -- open dialog again
			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(csvimport_builder, "csv_import_entry_name")));
			show_message(_("Empty name field."), dialog);
			goto run_csv_import_dialog;
		}
		//variable with the same name exists -- overwrite or open dialog again
		if(CALCULATOR->variableNameTaken(name_str) && !ask_question(_("An unit or variable with the same name already exists.\nDo you want to overwrite it?"), dialog)) {
			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(csvimport_builder, "csv_import_entry_name")));
			goto run_csv_import_dialog;
		}
		string delimiter = "";
		switch(gtk_combo_box_get_active(GTK_COMBO_BOX(gtk_builder_get_object(csvimport_builder, "csv_import_combobox_delimiter")))) {
			case DELIMITER_COMMA: {
				delimiter = ",";
				break;
			}
			case DELIMITER_TABULATOR: {
				delimiter = "\t";
				break;
			}			
			case DELIMITER_SEMICOLON: {
				delimiter = ";";
				break;
			}		
			case DELIMITER_SPACE: {
				delimiter = " ";
				break;
			}				
			case DELIMITER_OTHER: {
				delimiter = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(csvimport_builder, "csv_import_entry_delimiter_other")));
				break;
			}			
		}
		if(delimiter.empty()) {
			//no filename -- open dialog again
			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(csvimport_builder, "csv_import_entry_delimiter_other")));
			show_message(_("No delimiter selected."), dialog);
			goto run_csv_import_dialog;
		}
		do_timeout = false;
		if(!CALCULATOR->importCSV(str.c_str(), gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_builder_get_object(csvimport_builder, "csv_import_spinbutton_first_row"))), gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(csvimport_builder, "csv_import_checkbutton_headers"))), delimiter, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(csvimport_builder, "csv_import_radiobutton_matrix"))), name_str, gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(csvimport_builder, "csv_import_entry_desc"))), gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(gtk_builder_get_object(csvimport_builder, "csv_import_combo_category"))))) {
			GtkWidget *edialog = gtk_message_dialog_new(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("Could not import from file \n%s"), str.c_str());
			gtk_dialog_run(GTK_DIALOG(edialog));
			gtk_widget_destroy(edialog);
		}
		display_errors(NULL, dialog);
		do_timeout = true;
		update_vmenu();
	}
	gtk_widget_hide(dialog);
}

void export_csv_file(KnownVariable *v, GtkWidget *win) {

	GtkWidget *dialog = get_csv_export_dialog();
	if(win) gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(win));

	if(v) {
		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(csvexport_builder, "csv_export_entry_file")), v->preferredDisplayName(false, false, false, false, &can_display_unicode_string_function, (void*) gtk_builder_get_object(csvexport_builder, "csv_export_entry_file")).name.c_str());
		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(csvexport_builder, "csv_export_entry_matrix")), v->preferredDisplayName(false, false, false, false, &can_display_unicode_string_function, (void*) gtk_builder_get_object(csvexport_builder, "csv_export_entry_matrix")).name.c_str());
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(csvexport_builder, "csv_export_radiobutton_matrix")), TRUE);
	} else {
		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(csvexport_builder, "csv_export_entry_file")), "");
		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(csvexport_builder, "csv_export_entry_matrix")), "");
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(csvexport_builder, "csv_export_radiobutton_current")), TRUE);
	}
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(csvexport_builder, "csv_export_radiobutton_matrix")), !v);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(csvexport_builder, "csv_export_radiobutton_current")), !v);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(csvexport_builder, "csv_export_entry_matrix")), FALSE);
	
	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(csvexport_builder, "csv_export_entry_file")));

run_csv_export_dialog:
	if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) {
		//clicked "OK"
		string str = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(csvexport_builder, "csv_export_entry_file")));
		remove_blank_ends(str);
		if(str.empty()) {
			//no filename -- open dialog again
			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(csvexport_builder, "csv_export_entry_file")));
			show_message(_("No file name entered."), dialog);
			goto run_csv_export_dialog;
		}
		string delimiter = "";
		switch(gtk_combo_box_get_active(GTK_COMBO_BOX(gtk_builder_get_object(csvexport_builder, "csv_export_combobox_delimiter")))) {
			case DELIMITER_COMMA: {
				delimiter = ",";
				break;
			}
			case DELIMITER_TABULATOR: {
				delimiter = "\t";
				break;
			}			
			case DELIMITER_SEMICOLON: {
				delimiter = ";";
				break;
			}		
			case DELIMITER_SPACE: {
				delimiter = " ";
				break;
			}				
			case DELIMITER_OTHER: {
				delimiter = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(csvexport_builder, "csv_export_entry_delimiter_other")));
				break;
			}			
		}
		if(delimiter.empty()) {
			//no delimiter -- open dialog again
			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(csvexport_builder, "csv_export_entry_delimiter_other")));
			show_message(_("No delimiter selected."), dialog);
			goto run_csv_export_dialog;
		}
		MathStructure *matrix_struct;
		if(v) {
			matrix_struct = (MathStructure*) &v->get();
		} else if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(csvexport_builder, "csv_export_radiobutton_current")))) {
			matrix_struct = mstruct;
		} else {
			string str2 = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(csvexport_builder, "csv_export_entry_matrix")));
			remove_blank_ends(str2);
			if(str2.empty()) {
				gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(csvexport_builder, "csv_export_entry_matrix")));
				show_message(_("No variable name entered."), dialog);
				goto run_csv_export_dialog;
			}
			Variable *var = CALCULATOR->getActiveVariable(str2);
			if(!var || !var->isKnown()) {
				var = CALCULATOR->getVariable(str2);
				while(var && !var->isKnown()) {
					var = CALCULATOR->getVariable(str2);
				}
			}
			if(!var || !var->isKnown()) {
				gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(csvexport_builder, "csv_export_entry_matrix")));
				show_message(_("No known variable with entered name found."), dialog);
				goto run_csv_export_dialog;
			}
			matrix_struct = (MathStructure*) &((KnownVariable*) var)->get();
		}
		CALCULATOR->startControl(600000);
		if(!CALCULATOR->exportCSV(*matrix_struct, str.c_str(), delimiter) && CALCULATOR->aborted()) {
			GtkWidget *edialog = gtk_message_dialog_new(
				GTK_WINDOW(
					gtk_builder_get_object(main_builder, "main_window")
				),
				GTK_DIALOG_DESTROY_WITH_PARENT,
				GTK_MESSAGE_ERROR,
				GTK_BUTTONS_CLOSE,
				_("Could not export to file \n%s"),
				str.c_str()
			);
			gtk_dialog_run(GTK_DIALOG(edialog));
			gtk_widget_destroy(edialog);
		}
		CALCULATOR->stopControl();
	}
	gtk_widget_hide(dialog);
	
}

void edit_names(ExpressionItem *item, const gchar *namestr, GtkWidget *win, bool is_dp, DataProperty *dp) {

	GtkWidget *dialog = get_names_edit_dialog();
	if(win) gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(win));
	
	GtkTreeIter iter;
	
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(namesedit_builder, "names_edit_editbox1")), !(item && item->isBuiltin() && !(item->type() == TYPE_FUNCTION && item->subtype() == SUBTYPE_DATA_SET)));
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(namesedit_builder, "names_edit_editbox2")), !(item && item->isBuiltin() && !(item->type() == TYPE_FUNCTION && item->subtype() == SUBTYPE_DATA_SET)));
	
	if(!names_edited) {
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(namesedit_builder, "names_edit_button_modify")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(namesedit_builder, "names_edit_button_remove")), FALSE);
	
		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(namesedit_builder, "names_edit_entry_name")), "");
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_reference")), FALSE);
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_abbreviation")), FALSE);
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_plural")), FALSE);
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_suffix")), FALSE);
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_avoid_input")), FALSE);
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_case_sensitive")), FALSE);
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_unicode")), FALSE);
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_completion_only")), FALSE);
		
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_abbreviation")), !is_dp);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_plural")), !is_dp);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_suffix")), !is_dp);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_avoid_input")), !is_dp);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_case_sensitive")), !is_dp);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_unicode")), !is_dp);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_completion_only")), !is_dp);

		gtk_list_store_clear(tNames_store);
		
		if(!is_dp && item && item->countNames() > 0) {
			for(size_t i = 1; i <= item->countNames(); i++) {
				const ExpressionName *ename = &item->getName(i);
				gtk_list_store_append(tNames_store, &iter);
				gtk_list_store_set(tNames_store, &iter, NAMES_NAME_COLUMN, ename->name.c_str(), NAMES_ABBREVIATION_STRING_COLUMN, b2yn(ename->abbreviation), NAMES_PLURAL_STRING_COLUMN, b2yn(ename->plural), NAMES_REFERENCE_STRING_COLUMN, b2yn(ename->reference), NAMES_ABBREVIATION_COLUMN, ename->abbreviation, NAMES_PLURAL_COLUMN, ename->plural, NAMES_UNICODE_COLUMN, ename->unicode, NAMES_REFERENCE_COLUMN, ename->reference, NAMES_SUFFIX_COLUMN, ename->suffix, NAMES_AVOID_INPUT_COLUMN, ename->avoid_input, NAMES_CASE_SENSITIVE_COLUMN, ename->case_sensitive, NAMES_COMPLETION_ONLY_COLUMN, ename->completion_only, -1);
				if(i == 1 && namestr && strlen(namestr) > 0) {
					gtk_list_store_set(tNames_store, &iter, NAMES_NAME_COLUMN, namestr, -1);
				}
			}
		} else if(is_dp && dp && dp->countNames() > 0) {
			for(size_t i = 1; i <= dp->countNames(); i++) {
				gtk_list_store_append(tNames_store, &iter);
				gtk_list_store_set(tNames_store, &iter, NAMES_NAME_COLUMN, dp->getName(i).c_str(), NAMES_ABBREVIATION_STRING_COLUMN, "-", NAMES_PLURAL_STRING_COLUMN, "-", NAMES_REFERENCE_STRING_COLUMN, b2yn(dp->nameIsReference(i)), NAMES_ABBREVIATION_COLUMN, FALSE, NAMES_PLURAL_COLUMN, FALSE, NAMES_UNICODE_COLUMN, FALSE, NAMES_REFERENCE_COLUMN, dp->nameIsReference(i), NAMES_SUFFIX_COLUMN, FALSE, NAMES_AVOID_INPUT_COLUMN, FALSE, NAMES_CASE_SENSITIVE_COLUMN, FALSE, NAMES_COMPLETION_ONLY_COLUMN, FALSE, -1);
				if(i == 1 && namestr && strlen(namestr) > 0) {
					gtk_list_store_set(tNames_store, &iter, NAMES_NAME_COLUMN, namestr, -1);
				}
			}
		} else if(namestr && strlen(namestr) > 0) {
			gtk_list_store_append(tNames_store, &iter);
			if(is_dp) {
				gtk_list_store_set(tNames_store, &iter, NAMES_NAME_COLUMN, namestr, NAMES_ABBREVIATION_STRING_COLUMN, "-", NAMES_PLURAL_STRING_COLUMN, "-", NAMES_REFERENCE_STRING_COLUMN, b2yn(true), NAMES_ABBREVIATION_COLUMN, FALSE, NAMES_PLURAL_COLUMN, FALSE, NAMES_UNICODE_COLUMN, FALSE, NAMES_REFERENCE_COLUMN, TRUE, NAMES_SUFFIX_COLUMN, FALSE, NAMES_AVOID_INPUT_COLUMN, FALSE, NAMES_CASE_SENSITIVE_COLUMN, FALSE, NAMES_COMPLETION_ONLY_COLUMN, FALSE, -1);
			} else {
				ExpressionName ename(namestr);	
				gtk_list_store_set(tNames_store, &iter, NAMES_NAME_COLUMN, ename.name.c_str(), NAMES_ABBREVIATION_STRING_COLUMN, b2yn(ename.abbreviation), NAMES_PLURAL_STRING_COLUMN, b2yn(ename.plural), NAMES_REFERENCE_STRING_COLUMN, b2yn(ename.reference), NAMES_ABBREVIATION_COLUMN, ename.abbreviation, NAMES_PLURAL_COLUMN, ename.plural, NAMES_UNICODE_COLUMN, ename.unicode, NAMES_REFERENCE_COLUMN, ename.reference, NAMES_SUFFIX_COLUMN, ename.suffix, NAMES_AVOID_INPUT_COLUMN, ename.avoid_input, NAMES_CASE_SENSITIVE_COLUMN, ename.case_sensitive, NAMES_COMPLETION_ONLY_COLUMN, ename.completion_only, -1);
			}
		}
	} else if(namestr && strlen(namestr) > 0) {
		if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tNames_store), &iter)) {
			gtk_list_store_set(tNames_store, &iter, NAMES_NAME_COLUMN, namestr, -1);
		}
		on_tNames_selection_changed(gtk_tree_view_get_selection(GTK_TREE_VIEW(tNames)), NULL);
	}
	
	gtk_dialog_run(GTK_DIALOG(dialog));
	names_edited = true;
	
	gtk_widget_hide(dialog);
}


/*
	add a new variable (from menu) with the value of result
*/
void add_as_variable()
{
	edit_variable(CALCULATOR->temporaryCategory().c_str(), NULL, mstruct, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")));
}

void new_unknown(GtkMenuItem*, gpointer)
{
	edit_unknown(_("My Variables"), NULL, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")));
}

/*
	add a new variable (from menu)
*/
void new_variable(GtkMenuItem*, gpointer)
{
	edit_variable(_("My Variables"), NULL, NULL, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")));
}

/*
	add a new matrix (from menu)
*/
void new_matrix(GtkMenuItem*, gpointer)
{
	edit_matrix(_("Matrices"), NULL, NULL, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")), FALSE);
}
/*
	add a new vector (from menu)
*/
void new_vector(GtkMenuItem*, gpointer)
{
	edit_matrix(_("Vectors"), NULL, NULL, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")), TRUE);
}

bool is_number(const gchar *expr) {
	string str = CALCULATOR->unlocalizeExpression(expr, evalops.parse_options);
	CALCULATOR->parseSigns(str);
	for(size_t i = 0; i < str.length(); i++) {
		if(is_not_in(NUMBER_ELEMENTS, str[i]) && (i > 0 || str.length() == 1 || is_not_in(MINUS PLUS, str[0]))) return false;
	}
	return true;
}
bool last_is_number(const gchar *expr) {
	string str = CALCULATOR->unlocalizeExpression(expr, evalops.parse_options);
	CALCULATOR->parseSigns(str);
	if(str.empty()) return false;
	return is_not_in(OPERATORS SPACES SEXADOT DOT LEFT_VECTOR_WRAP LEFT_PARENTHESIS COMMAS, str[str.length() - 1]);
}

/*
	insert function when button clicked
*/
void insertButtonFunction(MathFunction *f, bool save_to_recent = false, bool apply_to_stack = true) {
	if(!f) return;
	if(!CALCULATOR->stillHasFunction(f)) return;
	if(rpn_mode && apply_to_stack && (f->minargs() <= 1 || (int) CALCULATOR->RPNStackSize() >= f->minargs())) {
		calculateRPN(f);
		return;
	}
	
	if(f->minargs() > 2) return insert_function(f, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")), save_to_recent);

	bool b_bitrot = (f->referenceName() == "bitrot");
	
	const ExpressionName *ename = &f->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext);
	Argument *arg = f->getArgumentDefinition(1);
	Argument *arg2 = f->getArgumentDefinition(2);
	bool b_text = (arg && arg->type() == ARGUMENT_TYPE_TEXT);
	bool b_text2 = (arg2 && arg2->type() == ARGUMENT_TYPE_TEXT);
	GtkTextIter istart, iend, ipos;
	gtk_text_buffer_get_start_iter(expressionbuffer, &istart);
	gtk_text_buffer_get_end_iter(expressionbuffer, &iend);
	gchar *expr = gtk_text_buffer_get_text(expressionbuffer, &istart, &iend, FALSE);
	GtkTextMark *mpos = gtk_text_buffer_get_insert(expressionbuffer);
	gtk_text_buffer_get_iter_at_mark(expressionbuffer, &ipos, mpos);
	// special case: the user just entered a number, then select all, so that it gets executed
	if(!gtk_text_buffer_get_has_selection(expressionbuffer) && gtk_text_iter_is_end(&ipos) && last_is_number(expr)) {
		gtk_text_buffer_select_range(expressionbuffer, &istart, &iend);
	}
	string str2;
	int index = 2;
	if(b_bitrot || f == CALCULATOR->f_bitcmp) {
		Argument *arg3 = f->getArgumentDefinition(3);
		Argument *arg4 = NULL;
		if(b_bitrot) {
			arg4 = arg2;
			arg2 = arg3;
			arg3 = f->getArgumentDefinition(4);
		}
		if(!arg2 || !arg3 || (b_bitrot && !arg4)) return;
		gtk_text_buffer_get_selection_bounds(expressionbuffer, &istart, &iend);
		GtkWidget *dialog = gtk_dialog_new_with_buttons(f->title(true).c_str(), GTK_WINDOW(mainwindow), (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT), _("_OK"), GTK_RESPONSE_OK, _("_Cancel"), GTK_RESPONSE_CANCEL, NULL);
		gtk_container_set_border_width(GTK_CONTAINER(dialog), 5);
		GtkWidget *grid = gtk_grid_new();
		gtk_grid_set_row_homogeneous(GTK_GRID(grid), TRUE);
		gtk_grid_set_column_spacing(GTK_GRID(grid), 12);
		gtk_container_set_border_width(GTK_CONTAINER(grid), 12);
		gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), grid);
		GtkWidget *w3 = NULL;
		if(b_bitrot) {
			GtkWidget *label2 = gtk_label_new(arg4->name().c_str());
			gtk_widget_set_halign(label2, GTK_ALIGN_START);
			gtk_grid_attach(GTK_GRID(grid), label2, 0, 0, 1, 1);
			glong min = LONG_MIN, max = LONG_MAX;
			if(arg4->type() == ARGUMENT_TYPE_INTEGER) {
				IntegerArgument *iarg = (IntegerArgument*) arg4;
				if(iarg->min()) {
					min = iarg->min()->lintValue();
				}
				if(iarg->max()) {
					max = iarg->max()->lintValue();
				}
			}
			w3 = gtk_spin_button_new_with_range(min, max, 1);
			gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(w3), evalops.parse_options.base != BASE_DECIMAL);
			gtk_entry_set_alignment(GTK_ENTRY(w3), 1.0);
			g_signal_connect(GTK_SPIN_BUTTON(w3), "input", G_CALLBACK(on_function_int_input), NULL);
			if(!f->getDefaultValue(index).empty()) {
				gtk_spin_button_set_value(GTK_SPIN_BUTTON(w3), s2i(f->getDefaultValue(index)));
			} else if(!arg2->zeroForbidden() && min <= 0 && max >= 0) {
				gtk_spin_button_set_value(GTK_SPIN_BUTTON(w3), 0);
			} else {
				if(max < 0) {
					gtk_spin_button_set_value(GTK_SPIN_BUTTON(w3), max);
				} else if(min <= 1) {
					gtk_spin_button_set_value(GTK_SPIN_BUTTON(w3), 1);
				} else {
					gtk_spin_button_set_value(GTK_SPIN_BUTTON(w3), min);
				}
			}
			gtk_grid_attach(GTK_GRID(grid), w3, 1, 0, 1, 1);
		}
		GtkWidget *label = gtk_label_new(arg2->name().c_str());
		gtk_widget_set_halign(label, GTK_ALIGN_START);
		gtk_grid_attach(GTK_GRID(grid), label, 0, b_bitrot ? 1 : 0, 1, 1);
		GtkWidget *w1 = gtk_combo_box_text_new();
		gtk_widget_set_hexpand(w1, TRUE);
		gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(w1), "8");
		gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(w1), "16");
		gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(w1), "32");
		gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(w1), "64");
		gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(w1), "128");
		gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(w1), "256");
		gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(w1), "512");
		gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(w1), "1024");
		switch(default_bits) {
			case 8: {gtk_combo_box_set_active(GTK_COMBO_BOX(w1), 0); break;}
			case 16: {gtk_combo_box_set_active(GTK_COMBO_BOX(w1), 1); break;}
			case 64: {gtk_combo_box_set_active(GTK_COMBO_BOX(w1), 3); break;}
			case 128: {gtk_combo_box_set_active(GTK_COMBO_BOX(w1), 4); break;}
			case 256: {gtk_combo_box_set_active(GTK_COMBO_BOX(w1), 5); break;}
			case 512: {gtk_combo_box_set_active(GTK_COMBO_BOX(w1), 6); break;}
			case 1024: {gtk_combo_box_set_active(GTK_COMBO_BOX(w1), 7); break;}
			default: {gtk_combo_box_set_active(GTK_COMBO_BOX(w1), 2); break;}
		}
		gtk_grid_attach(GTK_GRID(grid), w1, 1, b_bitrot ? 1 : 0, 1, 1);
		GtkWidget *w2 = gtk_check_button_new_with_label(arg3->name().c_str());
		if(default_signed > 0 || (default_signed < 0 && b_bitrot)) {
			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w2), TRUE);
		} else {
			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w2), FALSE);
		}
		gtk_widget_set_halign(w2, GTK_ALIGN_END);
		gtk_widget_set_hexpand(w2, TRUE);
		gtk_grid_attach(GTK_GRID(grid), w2, 0, b_bitrot ? 2 : 1, 2, 1);
		gtk_widget_show_all(dialog);
		if(gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_OK) {
			g_free(expr);
			gtk_widget_destroy(dialog);
			gtk_text_buffer_select_range(expressionbuffer, &istart, &iend);
			return;
		}
		gtk_text_buffer_select_range(expressionbuffer, &istart, &iend);
		Number bits;
		switch(gtk_combo_box_get_active(GTK_COMBO_BOX(w1))) {
			case 0: {bits = 8; break;}
			case 1: {bits = 16; break;}
			case 3: {bits = 64; break;}
			case 4: {bits = 128; break;}
			case 5: {bits = 256; break;}
			case 6: {bits = 512; break;}
			case 7: {bits = 1024; break;}
			default: {bits = 32; break;}
		}
		if(b_bitrot) {
			if(evalops.parse_options.base != BASE_DECIMAL) {
				Number nr(gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(w3)), 1);
				str2 += print_with_evalops(nr);
			} else {
				str2 += gtk_entry_get_text(GTK_ENTRY(w3));
			}
			str2 += CALCULATOR->getComma();
			str2 += " ";
		}
		str2 += print_with_evalops(bits);
		str2 += CALCULATOR->getComma();
		str2 += " ";
		if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w2))) str2 += "1";
		else str2 += "0";
		default_bits = bits.intValue();
		default_signed = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w2));
		gtk_widget_destroy(dialog);
	} else if(f->minargs() > 1 && ((arg2 && (f == CALCULATOR->f_root || arg2->type() == ARGUMENT_TYPE_INTEGER)) xor (arg && arg->type() == ARGUMENT_TYPE_INTEGER))) {
		if(arg && arg->type() == ARGUMENT_TYPE_INTEGER) {
			arg2 = arg;
			index = 1;
		}
		gtk_text_buffer_get_selection_bounds(expressionbuffer, &istart, &iend);
		GtkWidget *dialog = gtk_dialog_new_with_buttons(f->title(true).c_str(), GTK_WINDOW(mainwindow), (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT), _("_OK"), GTK_RESPONSE_OK, _("_Cancel"), GTK_RESPONSE_CANCEL, NULL);
		gtk_container_set_border_width(GTK_CONTAINER(dialog), 5);
		GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 12);
		gtk_box_set_homogeneous(GTK_BOX(hbox), TRUE);
		gtk_container_set_border_width(GTK_CONTAINER(hbox), 12);
		gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), hbox);
		GtkWidget *label = gtk_label_new(arg2->name().c_str());
		gtk_widget_set_halign(label, GTK_ALIGN_START);
		gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 0);
		IntegerArgument *iarg = (IntegerArgument*) arg2;
		glong min = LONG_MIN, max = LONG_MAX;
		if(iarg->min()) {
			min = iarg->min()->lintValue();
		}
		if(iarg->max()) {
			max = iarg->max()->lintValue();
		}
		GtkWidget *entry = gtk_spin_button_new_with_range(min, max, 1);
		gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(entry), evalops.parse_options.base != BASE_DECIMAL);
		gtk_entry_set_alignment(GTK_ENTRY(entry), 1.0);
		g_signal_connect(GTK_SPIN_BUTTON(entry), "input", G_CALLBACK(on_function_int_input), NULL);
		if(!f->getDefaultValue(index).empty()) {
			gtk_spin_button_set_value(GTK_SPIN_BUTTON(entry), s2i(f->getDefaultValue(index)));
		} else if(!arg2->zeroForbidden() && min <= 0 && max >= 0) {
			gtk_spin_button_set_value(GTK_SPIN_BUTTON(entry), 0);
		} else {
			if(max < 0) {
				gtk_spin_button_set_value(GTK_SPIN_BUTTON(entry), max);
			} else if(min <= 1) {
				gtk_spin_button_set_value(GTK_SPIN_BUTTON(entry), 1);
			} else {
				gtk_spin_button_set_value(GTK_SPIN_BUTTON(entry), min);
			}
		}
		gtk_box_pack_end(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
		gtk_widget_show_all(dialog);
		if(gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_OK) {
			g_free(expr);
			gtk_widget_destroy(dialog);
			gtk_text_buffer_select_range(expressionbuffer, &istart, &iend);
			return;
		}
		gtk_text_buffer_select_range(expressionbuffer, &istart, &iend);
		if(evalops.parse_options.base != BASE_DECIMAL) {
			Number nr(gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(entry)), 1);
			str2 = print_with_evalops(nr);
		} else {
			str2 = gtk_entry_get_text(GTK_ENTRY(entry));
		}
		gtk_widget_destroy(dialog);
	}
	if(gtk_text_buffer_get_has_selection(expressionbuffer)) {
		gtk_text_buffer_get_selection_bounds(expressionbuffer, &istart, &iend);
		// execute expression, if the whole expression was selected, no need for additional enter
		bool do_exec = (!str2.empty() || f->minargs() < 2) && !rpn_mode && ((gtk_text_iter_is_start(&istart) && gtk_text_iter_is_end(&iend)) || (gtk_text_iter_is_start(&iend) && gtk_text_iter_is_end(&istart)));
		//set selection as argument
		gchar *gstr = gtk_text_buffer_get_text(expressionbuffer, &istart, &iend, FALSE);
		string str = gstr;
		remove_blank_ends(str);
		gchar *gstr2;
		if(b_text && str.length() > 0 && (str[0] == '\"' || str[0] == '\'')) b_text = false;
		if(f->minargs() > 1 || !str2.empty()) {
			if(b_text2) {
				if(index == 1) gstr2 = g_strdup_printf(b_text ? "%s(\"%s\"%s \"%s\")" : "%s(%s%s \"%s\")", ename->name.c_str(), str2.c_str(), CALCULATOR->getComma().c_str(), gstr);
				else gstr2 = g_strdup_printf(b_text ? "%s(\"%s\"%s \"%s\")" : "%s(%s%s \"%s\")", ename->name.c_str(), gstr, CALCULATOR->getComma().c_str(), str2.c_str());
			} else {
				if(index == 1) gstr2 = g_strdup_printf(b_text ? "%s(\"%s\"%s %s)" : "%s(%s%s %s)", ename->name.c_str(), str2.c_str(), CALCULATOR->getComma().c_str(), gstr);
				else gstr2 = g_strdup_printf(b_text ? "%s(\"%s\"%s %s)" : "%s(%s%s %s)", ename->name.c_str(), gstr, CALCULATOR->getComma().c_str(), str2.c_str());
			}
		} else {
			gstr2 = g_strdup_printf(b_text ? "%s(\"%s\")" : "%s(%s)", ename->name.c_str(), gstr);
		}
		insert_text(gstr2);
		if(f->minargs() > 1) {
			GtkTextIter iter;
			gtk_text_buffer_get_iter_at_mark(expressionbuffer, &iter, gtk_text_buffer_get_insert(expressionbuffer));
			gtk_text_iter_backward_chars(&iter, b_text2 ? 2 : 1);
			gtk_text_buffer_place_cursor(expressionbuffer, &iter);
		}
		if(do_exec) execute_expression();
		g_free(gstr);
		g_free(gstr2);
	} else {
		if(f->minargs() > 1 || !str2.empty()) {
			gchar *gstr2;
			if(index == 1) gstr2 = g_strdup_printf(b_text ? "%s(\"%s\"%s )" : "%s(%s%s )", ename->name.c_str(), str2.c_str(), CALCULATOR->getComma().c_str());
			else gstr2 = g_strdup_printf(b_text ? "%s(\"\"%s %s)" : "%s(%s %s)", ename->name.c_str(), CALCULATOR->getComma().c_str(), str2.c_str());
			insert_text(gstr2);
			GtkTextIter iter;
			gtk_text_buffer_get_iter_at_mark(expressionbuffer, &iter, gtk_text_buffer_get_insert(expressionbuffer));
			if(index == 2) {
				gtk_text_iter_backward_chars(&iter, g_utf8_strlen(str2.c_str(), -1) + (b_text ? 4 : 3));
			} else {
				gtk_text_iter_backward_chars(&iter, b_text ? 2 : 1);
			}
			gtk_text_buffer_place_cursor(expressionbuffer, &iter);
			g_free(gstr2);
		} else {
			gchar *gstr2;
			gstr2 = g_strdup_printf(b_text ? "%s(\"\")" : "%s()", ename->name.c_str());
			insert_text(gstr2);
			GtkTextIter iter;
			gtk_text_buffer_get_iter_at_mark(expressionbuffer, &iter, gtk_text_buffer_get_insert(expressionbuffer));
			gtk_text_iter_backward_chars(&iter, b_text ? 2 : 1);
			gtk_text_buffer_place_cursor(expressionbuffer, &iter);
			g_free(gstr2);
		}
	}
	g_free(expr);
	if(save_to_recent) function_inserted(f);
}
void insert_button_function(GtkMenuItem*, gpointer user_data) {
	insertButtonFunction((MathFunction*) user_data);
}
void insert_button_function_save(GtkMenuItem*, gpointer user_data) {
	insertButtonFunction((MathFunction*) user_data, true);
}
void insert_button_function_norpn(GtkMenuItem*, gpointer user_data) {
	insertButtonFunction((MathFunction*) user_data, true, false);
}
void insert_function_operator(MathFunction *f) {
	if(rpn_mode || evalops.parse_options.rpn || is_at_beginning_of_expression()) {
		insertButtonFunction(f);
	} else if(f == CALCULATOR->f_mod) {
		wrap_expression_selection();
		insert_text(" mod ");
	} else if(f == CALCULATOR->f_rem) {
		wrap_expression_selection();
		insert_text(" rem ");
	} else {
		insertButtonFunction(f);
	}
}
void insert_function_operator(GtkMenuItem*, gpointer user_data) {
	insert_function_operator((MathFunction*) user_data);
}

/*
	Button clicked -- insert text (1,2,3,... +,-,...)
*/
void button_pressed(GtkButton*, gpointer user_data) {
	insert_text((gchar*) user_data);
}


/*
	Update angle menu
*/
void set_angle_item() {
	GtkWidget *mi = NULL;
	switch(evalops.parse_options.angle_unit) {
		case ANGLE_UNIT_RADIANS: {
			mi = GTK_WIDGET(gtk_builder_get_object(main_builder, "menu_item_radians"));
			g_signal_handlers_block_matched((gpointer) mi, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_radians_activate, NULL);	
			if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(mi)))
				gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mi), TRUE);
			g_signal_handlers_unblock_matched((gpointer) mi, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_radians_activate, NULL);						
			break;
		}
		case ANGLE_UNIT_GRADIANS: {
			mi = GTK_WIDGET(gtk_builder_get_object(main_builder, "menu_item_gradians"));
			g_signal_handlers_block_matched((gpointer) mi, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_gradians_activate, NULL);	
			if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(mi)))
				gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mi), TRUE);
			g_signal_handlers_unblock_matched((gpointer) mi, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_gradians_activate, NULL);						
			break;
		}
		case ANGLE_UNIT_DEGREES: {
			mi = GTK_WIDGET(gtk_builder_get_object(main_builder, "menu_item_degrees"));
			g_signal_handlers_block_matched((gpointer) mi, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_degrees_activate, NULL);	
			if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(mi)))
				gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mi), TRUE);
			g_signal_handlers_unblock_matched((gpointer) mi, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_degrees_activate, NULL);
			break;
		}
		default: {
			mi = GTK_WIDGET(gtk_builder_get_object(main_builder, "menu_item_no_default_angle_unit"));
			g_signal_handlers_block_matched((gpointer) mi, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_no_default_angle_unit_activate, NULL);
			if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(mi)))
				gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mi), TRUE);
			g_signal_handlers_unblock_matched((gpointer) mi, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_no_default_angle_unit_activate, NULL);
		}
	}
}

/*
	variables, functions and units enabled/disabled from menu
*/
void set_clean_mode(GtkMenuItem *w, gpointer) {
	gboolean b = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
	evalops.parse_options.functions_enabled = !b;
	evalops.parse_options.variables_enabled = !b;
	evalops.parse_options.units_enabled = !b;
	expression_format_updated(true);
}

/*
	Open variable manager
*/
void manage_variables() {
	GtkWidget *dialog = get_variables_dialog();
	if(!gtk_widget_is_visible(dialog)) {
		gtk_widget_grab_focus(tVariables);
		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(variables_builder, "variables_entry_search")), "");
		gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")));
		gtk_widget_show(dialog);
	}
	gtk_window_present(GTK_WINDOW(dialog));
}

/*
	Open function manager
*/
void manage_functions() {
	GtkWidget *dialog = get_functions_dialog();
	if(!gtk_widget_is_visible(dialog)) {
		gtk_widget_grab_focus(tFunctions);
		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(functions_builder, "functions_entry_search")), "");
		gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")));
		gtk_widget_show(dialog);
	}
	gtk_window_present(GTK_WINDOW(dialog));	
}

/*
	Open unit manager
*/
void manage_units() {
	GtkWidget *dialog = get_units_dialog();
	if(!gtk_widget_is_visible(dialog)) {
		gtk_widget_grab_focus(tUnits);
		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(units_builder, "units_entry_search")), "");
		gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")));
		gtk_widget_show(dialog);
	}
	gtk_window_present(GTK_WINDOW(dialog));
}

/*
	do the conversion in unit manager
*/
void convert_in_wUnits(int toFrom) {
	//units
	Unit *uFrom = get_selected_unit();
	Unit *uTo = get_selected_to_unit();
	
	if(uFrom && uTo) {
		//values
		const gchar *fromValue = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(units_builder, "units_entry_from_val")));
		const gchar *toValue = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(units_builder, "units_entry_to_val")));
		old_fromValue = fromValue;
		old_toValue = toValue;
		//determine conversion direction
		bool b = false;
		if(toFrom > 0) {
			if(CALCULATOR->timedOutString() == toValue) return;
			if(uFrom == uTo) {
				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(units_builder, "units_entry_from_val")), toValue);
			} else {
				EvaluationOptions eo;
				eo.approximation = APPROXIMATION_APPROXIMATE;
				eo.parse_options.angle_unit = evalops.parse_options.angle_unit;
				PrintOptions po;
				po.is_approximate = &b;
				po.number_fraction_format = FRACTION_DECIMAL;
				po.interval_display = INTERVAL_DISPLAY_SIGNIFICANT_DIGITS;
				CALCULATOR->resetExchangeRatesUsed();
				do_timeout = false;
				MathStructure v_mstruct = CALCULATOR->convert(CALCULATOR->unlocalizeExpression(toValue, evalops.parse_options), uTo, uFrom, 1500, eo);
				if(!v_mstruct.isAborted() && check_exchange_rates(get_units_dialog())) v_mstruct = CALCULATOR->convert(CALCULATOR->unlocalizeExpression(toValue, evalops.parse_options), uTo, uFrom, 1500, eo);
				if(v_mstruct.isAborted()) {
					old_fromValue = CALCULATOR->timedOutString();
				} else {
					old_fromValue = CALCULATOR->print(v_mstruct, 300, po);
				}
				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(units_builder, "units_entry_from_val")), old_fromValue.c_str());
				b = b || v_mstruct.isApproximate();
				display_errors(NULL, GTK_WIDGET(gtk_builder_get_object(units_builder, "units_dialog")));
				do_timeout = true;
			}
		} else {
			if(CALCULATOR->timedOutString() == fromValue) return;
			if(uFrom == uTo) {
				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(units_builder, "units_entry_to_val")), fromValue);
			} else {
				EvaluationOptions eo;
				eo.approximation = APPROXIMATION_APPROXIMATE;
				eo.parse_options.angle_unit = evalops.parse_options.angle_unit;
				PrintOptions po;
				po.is_approximate = &b;
				po.number_fraction_format = FRACTION_DECIMAL;
				po.interval_display = INTERVAL_DISPLAY_SIGNIFICANT_DIGITS;
				CALCULATOR->resetExchangeRatesUsed();
				do_timeout = false;
				MathStructure v_mstruct = CALCULATOR->convert(CALCULATOR->unlocalizeExpression(fromValue, evalops.parse_options), uFrom, uTo, 1500, eo);
				if(!v_mstruct.isAborted() && check_exchange_rates(get_units_dialog())) v_mstruct = CALCULATOR->convert(CALCULATOR->unlocalizeExpression(fromValue, evalops.parse_options), uFrom, uTo, 1500, eo);
				if(v_mstruct.isAborted()) {
					old_toValue = CALCULATOR->timedOutString();
				} else {
					old_toValue = CALCULATOR->print(v_mstruct, 300, po);
				}
				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(units_builder, "units_entry_to_val")), old_toValue.c_str());
				b = b || v_mstruct.isApproximate();
				display_errors(NULL, GTK_WIDGET(gtk_builder_get_object(units_builder, "units_dialog")));
				do_timeout = true;
			}
		}
		if(b && printops.use_unicode_signs && can_display_unicode_string_function(SIGN_ALMOST_EQUAL, (void*) gtk_builder_get_object(units_builder, "units_label_equals"))) {
			gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(units_builder, "units_label_equals")), SIGN_ALMOST_EQUAL);
		} else {
			gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(units_builder, "units_label_equals")), "=");
		}
	}
}

/*
	save definitions to ~/.conf/qalculate/qalculate.cfg
	the hard work is done in the Calculator class
*/
void save_defs() {
	if(!CALCULATOR->saveDefinitions()) {
		GtkWidget *edialog = gtk_message_dialog_new(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("Couldn't write definitions"));
		gtk_dialog_run(GTK_DIALOG(edialog));
		gtk_widget_destroy(edialog);
	}
}

/*
	save mode to file
*/
void save_mode() {
	save_preferences(true);
}

/*
	remember current mode
*/
void set_saved_mode() {
	modes[1].precision = CALCULATOR->getPrecision();
	modes[1].interval = CALCULATOR->usesIntervalArithmetic();
	modes[1].adaptive_interval_display = adaptive_interval_display;
	modes[1].variable_units_enabled = CALCULATOR->variableUnitsEnabled();
	modes[1].po = printops;
	modes[1].po.allow_factorization = (evalops.structuring == STRUCTURING_FACTORIZE);
	modes[1].eo = evalops;
	modes[1].at = CALCULATOR->defaultAssumptions()->type();
	modes[1].as = CALCULATOR->defaultAssumptions()->sign();
	modes[1].rpn_mode = rpn_mode;
	modes[1].autocalc = auto_calculate;
	modes[1].keypad = visible_keypad;
	modes[1].custom_output_base = CALCULATOR->customOutputBase();
	modes[1].custom_input_base = CALCULATOR->customInputBase();
	modes[1].complex_angle_form = complex_angle_form;
}

size_t save_mode_as(string name, bool *new_mode = NULL) {
	remove_blank_ends(name);
	size_t index = 0;
	for(; index < modes.size(); index++) {
		if(modes[index].name == name) {
			if(new_mode) *new_mode = false;
			break;
		}
	}
	if(index >= modes.size()) {
		modes.resize(modes.size() + 1);
		index = modes.size() - 1;
		if(new_mode) *new_mode = true;
	}
	modes[index].po = printops;
	modes[index].po.allow_factorization = (evalops.structuring == STRUCTURING_FACTORIZE);
	modes[index].eo = evalops;
	modes[index].precision = CALCULATOR->getPrecision();
	modes[index].interval = CALCULATOR->usesIntervalArithmetic();
	modes[index].adaptive_interval_display = adaptive_interval_display;
	modes[index].variable_units_enabled = CALCULATOR->variableUnitsEnabled();
	modes[index].at = CALCULATOR->defaultAssumptions()->type();
	modes[index].as = CALCULATOR->defaultAssumptions()->sign();
	modes[index].name = name;
	modes[index].rpn_mode = rpn_mode;
	modes[index].autocalc = auto_calculate;
	modes[index].keypad = visible_keypad;
	modes[index].custom_output_base = CALCULATOR->customOutputBase();
	modes[index].custom_input_base = CALCULATOR->customInputBase();
	modes[index].complex_angle_form = complex_angle_form;
	return index;
}

void load_mode(const mode_struct &mode) {
	block_result_update = true;
	block_expression_execution = true;
	block_display_parse = true;
	if(mode.keypad == 1) {
		programming_inbase = 0;
		programming_outbase = 0;
	}
	CALCULATOR->setCustomOutputBase(mode.custom_output_base);
	CALCULATOR->setCustomInputBase(mode.custom_input_base);
	set_mode_items(mode.po, mode.eo, mode.at, mode.as, mode.rpn_mode, mode.precision, mode.interval, mode.variable_units_enabled, mode.adaptive_interval_display, mode.keypad, mode.autocalc, mode.complex_angle_form, false);
	evalops.approximation = mode.eo.approximation;
	block_result_update = false;
	block_expression_execution = false;
	block_display_parse = false;
	printops.allow_factorization = (evalops.structuring == STRUCTURING_FACTORIZE);
	auto_calculate = mode.autocalc;
	complex_angle_form = mode.complex_angle_form;
	set_rpn_mode(mode.rpn_mode);
	GtkTextIter istart, iend;
	gtk_text_buffer_get_start_iter(expressionbuffer, &istart);
	gtk_text_buffer_get_end_iter(expressionbuffer, &iend);
	gchar *gtext = gtk_text_buffer_get_text(expressionbuffer, &istart, &iend, FALSE);
	string str = gtext;
	g_free(gtext);
	if(auto_calculate && !rpn_mode) {
		do_auto_calc();
	} else if(rpn_mode || expression_has_changed || str.find_first_not_of(SPACES) == string::npos) {
		setResult(NULL, true, false, false);
	} else {
		execute_expression(false);
	}
	expression_has_changed2 = true;
	display_parse_status();
}
void load_mode(string name) {
	for(size_t i = 0; i < modes.size(); i++) {
		if(modes[i].name == name) {
			load_mode(modes[i]);
			return;
		}
	}
}
void load_mode(size_t index) {
	if(index < modes.size()) {
		load_mode(modes[index]);
	}
}

void on_popup_menu_item_completion_level_toggled(GtkCheckMenuItem *w, gpointer p) {
	if(!gtk_check_menu_item_get_active(w)) return;
	int completion_level = GPOINTER_TO_INT(p);
	enable_completion = completion_level > 0;
	enable_completion2 = completion_level > 2;
	if(completion_level > 1) completion_min = 1;
	else completion_min = 2;
	if(completion_level > 3) completion_min2 = 1;
	else completion_min2 = 2;
}
void on_popup_menu_item_read_precision_activate(GtkMenuItem *w, gpointer) {
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_read_precision")), gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)));
}
void on_popup_menu_item_limit_implicit_multiplication_activate(GtkMenuItem *w, gpointer) {
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_limit_implicit_multiplication")), gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)));
}
void on_popup_menu_item_adaptive_parsing_activate(GtkMenuItem *w, gpointer) {
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_adaptive_parsing")), gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)));
}
void on_popup_menu_item_ignore_whitespace_activate(GtkMenuItem *w, gpointer) {
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_ignore_whitespace")), gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)));
}
void on_popup_menu_item_no_special_implicit_multiplication_activate(GtkMenuItem *w, gpointer) {
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_no_special_implicit_multiplication")), gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)));
}
void on_popup_menu_item_rpn_syntax_activate(GtkMenuItem *w, gpointer) {
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_rpn_syntax")), gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)));
}
void on_popup_menu_item_rpn_mode_activate(GtkMenuItem *w, gpointer) {
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_rpn_mode")), gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)));
}
void expression_set_from_undo_buffer() {
	if(undo_index < expression_undo_buffer.size()) {
		string str_old = get_expression_text();
		string str_new = expression_undo_buffer[undo_index];
		if(str_old == str_new) return;
		size_t i;
		add_to_undo = false;
		GtkTextIter istart, iend;
		if(str_old.length() > str_new.length()) {
			if((i = str_old.find(str_new)) != string::npos) {
				if(i != 0) {
					gtk_text_buffer_get_iter_at_offset(expressionbuffer, &iend, g_utf8_strlen(str_old.c_str(), i));
					gtk_text_buffer_get_start_iter(expressionbuffer, &istart);
					gtk_text_buffer_delete(expressionbuffer, &istart, &iend);
				}
				if(i + str_new.length() < str_old.length()) {
					gtk_text_buffer_get_iter_at_offset(expressionbuffer, &istart, g_utf8_strlen(str_new.c_str(), -1));
					gtk_text_buffer_get_end_iter(expressionbuffer, &iend);
					gtk_text_buffer_delete(expressionbuffer, &istart, &iend);
				}
				add_to_undo = true;
				return;
			}
			for(i = 0; i < str_new.length(); i++) {
				if(str_new[i] != str_old[i]) {
					if(i == 0) break;
					string str_test = str_old.substr(0, i);
					str_test += str_old.substr(i + str_old.length() - str_new.length());
					if(str_test == str_new) {
						gtk_text_buffer_get_iter_at_offset(expressionbuffer, &istart, g_utf8_strlen(str_old.c_str(), i));
						gtk_text_buffer_get_iter_at_offset(expressionbuffer, &iend, g_utf8_strlen(str_old.c_str(), i + str_old.length() - str_new.length()));
						gtk_text_buffer_delete(expressionbuffer, &istart, &iend);
						add_to_undo = true;
						return;
					}
					if(str_new.length() + 1 == str_old.length()) break;
					str_test = str_old.substr(0, i);
					str_test += str_old.substr(i + str_old.length() - str_new.length() - 1);
					size_t i2 = i;
					while((i2 = str_test.find(')', i2 + 1)) != string::npos) {
						string str_test2 = str_test;
						str_test2.erase(str_test2.begin() + i2);
						if(str_test2 == str_new) {
							gtk_text_buffer_get_iter_at_offset(expressionbuffer, &istart, g_utf8_strlen(str_old.c_str(), i));
							gtk_text_buffer_get_iter_at_offset(expressionbuffer, &iend, g_utf8_strlen(str_old.c_str(), i + str_old.length() - str_new.length() - 1));
							gtk_text_buffer_delete(expressionbuffer, &istart, &iend);
							gtk_text_buffer_get_iter_at_offset(expressionbuffer, &istart, g_utf8_strlen(str_old.c_str(), i2));
							iend = istart;
							gtk_text_iter_forward_char(&iend);
							gtk_text_buffer_delete(expressionbuffer, &istart, &iend);
							add_to_undo = true;
							return;
						}
					}
					break;
				}
			}
		} else if(str_new.length() > str_old.length()) {
			if((i = str_new.find(str_old)) != string::npos) {
				if(i + str_old.length() < str_new.length()) {
					gtk_text_buffer_get_end_iter(expressionbuffer, &iend);
					gtk_text_buffer_insert(expressionbuffer, &iend, str_new.substr(i + str_old.length(), str_new.length() - (i + str_old.length())).c_str(), -1);
				}
				if(i > 0) {
					gtk_text_buffer_get_start_iter(expressionbuffer, &istart);
					gtk_text_buffer_insert(expressionbuffer, &istart, str_new.substr(0, i).c_str(), -1);
				}
				add_to_undo = true;
				return;
			}
			for(i = 0; i < str_old.length(); i++) {
				if(str_old[i] != str_new[i]) {
					if(i == 0) break;
					string str_test = str_new.substr(0, i);
					str_test += str_new.substr(i + str_new.length() - str_old.length());
					if(str_test == str_old) {
						gtk_text_buffer_get_iter_at_offset(expressionbuffer, &istart, g_utf8_strlen(str_new.c_str(), i));
						gtk_text_buffer_insert(expressionbuffer, &istart, str_new.substr(i, str_new.length() - str_old.length()).c_str(), -1);
						add_to_undo = true;
						return;
					}
					if(str_old.length() + 1 == str_new.length()) break;
					str_test = str_new.substr(0, i);
					str_test += str_new.substr(i + str_new.length() - str_old.length() - 1);
					size_t i2 = i;
					while((i2 = str_test.find(')', i2 + 1)) != string::npos) {
						string str_test2 = str_test;
						str_test2.erase(str_test2.begin() + i2);
						if(str_test2 == str_old) {
							gtk_text_buffer_get_iter_at_offset(expressionbuffer, &istart, g_utf8_strlen(str_new.c_str(), i));
							gtk_text_buffer_insert(expressionbuffer, &istart, str_new.substr(i, str_new.length() - str_old.length() - 1).c_str(), -1);
							gtk_text_buffer_get_iter_at_offset(expressionbuffer, &istart, g_utf8_strlen(str_new.c_str(), i2 + str_new.length() - str_old.length() - 1));
							gtk_text_buffer_insert(expressionbuffer, &istart, ")", -1);
							add_to_undo = true;
							return;
						}
					}
					break;
				}
			}
		}
		gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(expressiontext), FALSE);
		gtk_text_buffer_set_text(expressionbuffer, str_new.c_str(), -1);
		gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(expressiontext), TRUE);
		add_to_undo = true;
	}
}
void expression_undo() {
	if(undo_index == 0) return;
	undo_index--;
	expression_set_from_undo_buffer();
}
void expression_redo() {
	if(undo_index >= expression_undo_buffer.size() - 1) return;
	undo_index++;
	expression_set_from_undo_buffer();
}

bool block_popup_input_base = false;
void on_popup_menu_item_input_base(GtkMenuItem *w, gpointer data) {
	if(block_popup_input_base) return;
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	if(GPOINTER_TO_INT(data) == BASE_CUSTOM) {
		GtkWidget *dialog = get_set_base_dialog();
		gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")));
		gtk_widget_show(dialog);
		gtk_window_present(GTK_WINDOW(dialog));
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_other")), TRUE);
		gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(setbase_builder, "set_base_entry_input_other")));
	} else {
		evalops.parse_options.base = GPOINTER_TO_INT(data);
		input_base_updated_from_menu();
		update_keypad_bases();
		expression_format_updated(false);
		on_historyview_selection_changed(NULL, NULL);
	}
}
void on_expressiontext_populate_popup(GtkTextView*, GtkMenu *menu, gpointer) {
	popup_menu_expressiontext = menu;
	GtkWidget *item, *sub, *sub2;
	GSList *group = NULL;
	gchar *gstr;
	sub = GTK_WIDGET(menu);
	MENU_ITEM(_("Clear"), on_popup_menu_item_clear_activate)
	if(expression_is_empty()) gtk_widget_set_sensitive(item, FALSE);
	MENU_SEPARATOR
	if(b_busy) {
		MENU_ITEM(_("Abort"), on_popup_menu_item_abort_activate)
		return;
	}
	MENU_ITEM(_("Undo"), expression_undo)
	if(undo_index == 0) gtk_widget_set_sensitive(item, FALSE);
	MENU_ITEM(_("Redo"), expression_redo)
	if(undo_index >= expression_undo_buffer.size() - 1) gtk_widget_set_sensitive(item, FALSE);
	MENU_SEPARATOR
	sub2 = sub;
	SUBMENU_ITEM(_("Completion Mode"), sub2);
	int completion_level = 0;
	if(enable_completion) {
		if(enable_completion2) {
			if(completion_min2 > 1) completion_level = 3;
			else completion_level = 4;
		} else {
			if(completion_min > 1) completion_level = 1;
			else completion_level = 2;
		}
	}
	for(gint i = 0; i < 5; i++) {
		switch(i) {
			case 1: {item = gtk_radio_menu_item_new_with_label(group, _("Limited strict completion")); break;}
			case 2: {item = gtk_radio_menu_item_new_with_label(group, _("Strict completion")); break;}
			case 3: {item = gtk_radio_menu_item_new_with_label(group, _("Limited full completion")); break;}
			case 4: {item = gtk_radio_menu_item_new_with_label(group, _("Full completion")); break;}
			default: {item = gtk_radio_menu_item_new_with_label(group, _("No completion"));}
		}
		group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(item));
		gtk_widget_show(item);
		if(i == completion_level) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), TRUE);
		g_signal_connect(G_OBJECT(item), "toggled", G_CALLBACK(on_popup_menu_item_completion_level_toggled), GINT_TO_POINTER(i));
		gtk_menu_shell_append(GTK_MENU_SHELL(sub), item);
	}
	group = NULL;
	SUBMENU_ITEM(_("Parsing Mode"), sub2);
	POPUP_RADIO_MENU_ITEM(on_popup_menu_item_adaptive_parsing_activate, gtk_builder_get_object(main_builder, "menu_item_adaptive_parsing"))
	POPUP_RADIO_MENU_ITEM(on_popup_menu_item_ignore_whitespace_activate, gtk_builder_get_object(main_builder, "menu_item_ignore_whitespace"))
	POPUP_RADIO_MENU_ITEM(on_popup_menu_item_no_special_implicit_multiplication_activate, gtk_builder_get_object(main_builder, "menu_item_no_special_implicit_multiplication"))
	MENU_SEPARATOR
	POPUP_CHECK_MENU_ITEM(on_popup_menu_item_limit_implicit_multiplication_activate, gtk_builder_get_object(main_builder, "menu_item_limit_implicit_multiplication"))
	POPUP_CHECK_MENU_ITEM(on_popup_menu_item_read_precision_activate, gtk_builder_get_object(main_builder, "menu_item_read_precision"))
	POPUP_CHECK_MENU_ITEM(on_popup_menu_item_rpn_syntax_activate, gtk_builder_get_object(main_builder, "menu_item_rpn_syntax"))
	POPUP_CHECK_MENU_ITEM(on_popup_menu_item_rpn_mode_activate, gtk_builder_get_object(main_builder, "menu_item_rpn_mode"))
	SUBMENU_ITEM(_("Number Base"), sub2);
	group = NULL;
	block_popup_input_base = true;
	RADIO_MENU_ITEM_WITH_INT(_("Binary"), on_popup_menu_item_input_base, evalops.parse_options.base == 2, 2)
	RADIO_MENU_ITEM_WITH_INT(_("Octal"), on_popup_menu_item_input_base, evalops.parse_options.base == 8, 8)
	RADIO_MENU_ITEM_WITH_INT(_("Decimal"), on_popup_menu_item_input_base, evalops.parse_options.base == 10, 10)
	RADIO_MENU_ITEM_WITH_INT(_("Duodecimal"), on_popup_menu_item_input_base, evalops.parse_options.base == 12, 12)
	RADIO_MENU_ITEM_WITH_INT(_("Hexadecimal"), on_popup_menu_item_input_base, evalops.parse_options.base == 16, 16)
	RADIO_MENU_ITEM_WITH_INT(_("Roman Numerals"), on_popup_menu_item_input_base, evalops.parse_options.base == BASE_ROMAN_NUMERALS, BASE_ROMAN_NUMERALS)
	RADIO_MENU_ITEM_WITH_INT(_("Other…"), on_popup_menu_item_input_base, evalops.parse_options.base != 2 && evalops.parse_options.base != 8 && evalops.parse_options.base != 10 && evalops.parse_options.base != 12 && evalops.parse_options.base != 16 && evalops.parse_options.base != BASE_ROMAN_NUMERALS, BASE_CUSTOM)
	block_popup_input_base = false;
	SUBMENU_ITEM(_("Meta Modes"), sub2)
	popup_expression_mode_items.clear();
	for(size_t i = 0; i < modes.size(); i++) {
		item = gtk_menu_item_new_with_label(modes[i].name.c_str()); 
		gtk_widget_show(item); 
		g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(on_menu_item_meta_mode_activate), (gpointer) modes[i].name.c_str());
		g_signal_connect(G_OBJECT(item), "button-press-event", G_CALLBACK(on_menu_item_meta_mode_button_press), (gpointer) modes[i].name.c_str());
		g_signal_connect(G_OBJECT(item), "popup-menu", G_CALLBACK(on_menu_item_meta_mode_popup_menu), (gpointer) modes[i].name.c_str());
		popup_expression_mode_items.push_back(item);
		gtk_menu_shell_insert(GTK_MENU_SHELL(sub), item, (gint) i);
	}
	MENU_SEPARATOR
	MENU_ITEM(_("Save Mode…"), on_menu_item_meta_mode_save_activate)
	sub = sub2;
	MENU_SEPARATOR
	MENU_ITEM(_("Insert Date…"), on_menu_item_insert_date_activate)
	MENU_ITEM(_("Insert Matrix…"), on_menu_item_insert_matrix_activate)
	MENU_ITEM(_("Insert Vector…"), on_menu_item_insert_vector_activate)
}

void on_combobox_base_changed(GtkComboBox *w, gpointer) {
	switch(gtk_combo_box_get_active(w)) {
		case 0: {
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_binary")), TRUE);
			break;
		}
		case 1: {
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_octal")), TRUE);
			break;
		}
		case 2: {
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_decimal")), TRUE);
			break;
		}
		case 3: {
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_duodecimal")), TRUE);
			break;
		}
		case 4: {
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_hexadecimal")), TRUE);
			break;
		}
		case 5: {
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_sexagesimal")), TRUE);
			break;
		}
		case 6: {
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_time_format")), TRUE);
			break;
		}
		case 7: {
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_roman")), TRUE);
			break;
		}
		case 8: {
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_custom_base")), TRUE);
			break;
		}
	}
}
void on_combobox_numerical_display_changed(GtkComboBox *w, gpointer) {
	switch(gtk_combo_box_get_active(w)) {
		case 0: {
			printops.negative_exponents = false;
			printops.sort_options.minus_last = true;
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_display_normal")), TRUE);
			break;
		}
		case 1: {
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_display_engineering")), TRUE);
			break;
		}
		case 2: {
			printops.negative_exponents = true;
			printops.sort_options.minus_last = false;
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_display_scientific")), TRUE);
			break;
		}
		case 3: {
			printops.negative_exponents = true;
			printops.sort_options.minus_last = false;
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_display_purely_scientific")), TRUE);
			break;
		}
		case 4: {
			printops.negative_exponents = false;
			printops.sort_options.minus_last = true;
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_display_non_scientific")), TRUE);
			break;
		}
	}
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_negative_exponents"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_negative_exponents_activate, NULL);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_sort_minus_last"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_sort_minus_last_activate, NULL);
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_negative_exponents")), printops.negative_exponents);
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_sort_minus_last")), printops.sort_options.minus_last);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_negative_exponents"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_negative_exponents_activate, NULL);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_sort_minus_last"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_sort_minus_last_activate, NULL);
}

void on_button_exact_toggled(GtkToggleButton *w, gpointer) {
	if(gtk_toggle_button_get_active(w)) {
		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_always_exact")), TRUE);
	} else {
		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_try_exact")), TRUE);
	}

}

void on_combobox_fraction_mode_changed(GtkComboBox *w, gpointer) {
	switch(gtk_combo_box_get_active(w)) {
		case 0: {
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_fraction_decimal")), TRUE);
			break;
		}
		case 2: {
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_fraction_fraction")), TRUE);
			break;
		}
		case 1: {
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_fraction_decimal_exact")), TRUE);
			break;
		}
		case 3: {
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_fraction_combined")), TRUE);
			break;
		}
	}
}

void show_tabs(bool do_show) {
	if(do_show == gtk_widget_get_visible(tabs)) return;
	gint w, h;
	gtk_window_get_size(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), &w, &h);
	if(gtk_widget_get_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "buttons")))) h -= gtk_widget_get_allocated_height(GTK_WIDGET(gtk_builder_get_object(main_builder, "buttons"))) + 6;
	if(do_show) {		
		gtk_widget_show(tabs);
		gint a_h = gtk_widget_get_allocated_height(tabs);
		if(a_h > 10) h += a_h + 6;
		else h += history_height + 6;
		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "buttons")));
		gtk_window_resize(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), w, h);
	} else {
		h -= gtk_widget_get_allocated_height(tabs) + 6;
		gtk_widget_hide(tabs);
		set_result_size_request();
		set_expression_size_request();
		gtk_window_resize(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), w, h);
	}
	gtk_widget_set_vexpand(resultview, !gtk_widget_get_visible(tabs) && !gtk_widget_get_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "buttons"))));
}
void show_keypad_widget(bool do_show) {
	if(do_show == gtk_widget_get_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "buttons")))) return;
	gint w, h;
	gtk_window_get_size(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), &w, &h);
	if(gtk_widget_get_visible(tabs)) h -= gtk_widget_get_allocated_height(tabs) + 6;
	if(do_show) {
		gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(main_builder, "buttons")));
		gint a_h = gtk_widget_get_allocated_height(GTK_WIDGET(gtk_builder_get_object(main_builder, "buttons")));
		if(a_h > 10) h += a_h + 6;
		else h += keypad_height + 6;
		gtk_widget_hide(tabs);
		gtk_window_resize(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), w, h);
	} else {
		h -= gtk_widget_get_allocated_height(GTK_WIDGET(gtk_builder_get_object(main_builder, "buttons"))) + 6;
		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "buttons")));
		set_result_size_request();
		set_expression_size_request();
		gtk_window_resize(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), w, h);
	}
	gtk_widget_set_vexpand(resultview, !gtk_widget_get_visible(tabs) && !gtk_widget_get_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "buttons"))));
}

void on_expander_keypad_expanded(GObject *o, GParamSpec*, gpointer) {	
	if(gtk_expander_get_expanded(GTK_EXPANDER(o))) {
		show_keypad_widget(true);
		if(gtk_expander_get_expanded(GTK_EXPANDER(expander_history))) {
			gtk_expander_set_expanded(GTK_EXPANDER(expander_history), FALSE);
		} else if(gtk_expander_get_expanded(GTK_EXPANDER(expander_stack))) {
			gtk_expander_set_expanded(GTK_EXPANDER(expander_stack), FALSE);
		} else if(gtk_expander_get_expanded(GTK_EXPANDER(expander_convert))) {
			gtk_expander_set_expanded(GTK_EXPANDER(expander_convert), FALSE);
		}		
	} else {
		show_keypad_widget(false);		
	}
}
void on_expander_history_expanded(GObject *o, GParamSpec*, gpointer) {
	if(gtk_expander_get_expanded(GTK_EXPANDER(o))) {
		bool history_was_realized = gtk_widget_get_realized(historyview);
		gtk_notebook_set_current_page(GTK_NOTEBOOK(tabs), 0);
		show_tabs(true);
		while(!history_was_realized && gtk_events_pending()) gtk_main_iteration();
		if(!history_was_realized && nr_of_new_expressions > 0) {
			GtkTreePath *path = gtk_tree_path_new_from_indices(0, -1);
			gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(historyview), path, history_index_column, FALSE, 0, 0);
			gtk_tree_view_scroll_to_point(GTK_TREE_VIEW(historyview), 0, 0);
			gtk_tree_path_free(path);
		}
		if(gtk_expander_get_expanded(GTK_EXPANDER(expander_keypad))) {
			gtk_expander_set_expanded(GTK_EXPANDER(expander_keypad), FALSE);
		} else if(gtk_expander_get_expanded(GTK_EXPANDER(expander_stack))) {
			gtk_expander_set_expanded(GTK_EXPANDER(expander_stack), FALSE);
		} else if(gtk_expander_get_expanded(GTK_EXPANDER(expander_convert))) {
			gtk_expander_set_expanded(GTK_EXPANDER(expander_convert), FALSE);
		}
	} else if(!gtk_expander_get_expanded(GTK_EXPANDER(expander_stack)) && !gtk_expander_get_expanded(GTK_EXPANDER(expander_convert))) {
		show_tabs(false);
	}
}
void on_expander_stack_expanded(GObject *o, GParamSpec*, gpointer) {
	if(gtk_expander_get_expanded(GTK_EXPANDER(o))) {
		gtk_notebook_set_current_page(GTK_NOTEBOOK(tabs), 1);
		show_tabs(true);
		if(gtk_expander_get_expanded(GTK_EXPANDER(expander_keypad))) {
			gtk_expander_set_expanded(GTK_EXPANDER(expander_keypad), FALSE);
		} else if(gtk_expander_get_expanded(GTK_EXPANDER(expander_history))) {
			gtk_expander_set_expanded(GTK_EXPANDER(expander_history), FALSE);
		} else if(gtk_expander_get_expanded(GTK_EXPANDER(expander_convert))) {
			gtk_expander_set_expanded(GTK_EXPANDER(expander_convert), FALSE);
		}		
	} else if(!gtk_expander_get_expanded(GTK_EXPANDER(expander_history)) && !gtk_expander_get_expanded(GTK_EXPANDER(expander_convert))) {
		show_tabs(false);
	}
}
void on_expander_convert_expanded(GObject *o, GParamSpec*, gpointer) {
	if(gtk_expander_get_expanded(GTK_EXPANDER(o))) {
		gtk_notebook_set_current_page(GTK_NOTEBOOK(tabs), 2);
		show_tabs(true);
		if(gtk_expander_get_expanded(GTK_EXPANDER(expander_keypad))) {
			gtk_expander_set_expanded(GTK_EXPANDER(expander_keypad), FALSE);
		} else if(gtk_expander_get_expanded(GTK_EXPANDER(expander_history))) {
			gtk_expander_set_expanded(GTK_EXPANDER(expander_history), FALSE);
		} else if(gtk_expander_get_expanded(GTK_EXPANDER(expander_stack))) {
			gtk_expander_set_expanded(GTK_EXPANDER(expander_stack), FALSE);
		}		
	} else if(!gtk_expander_get_expanded(GTK_EXPANDER(expander_history)) && !gtk_expander_get_expanded(GTK_EXPANDER(expander_stack))) {
		show_tabs(false);
	}
}

int mode_menu_i = 0;

void on_popup_menu_mode_update_activate(GtkMenuItem*, gpointer data) {
	save_mode_as((const char*) data);
	if(mode_menu_i == 1) {
		gtk_menu_popdown(GTK_MENU(gtk_builder_get_object(main_builder, "mode_menu_menu")));
		gtk_menu_shell_deselect(GTK_MENU_SHELL(gtk_builder_get_object(main_builder, "menubar")));
	} else if(mode_menu_i == 2) {
		gtk_menu_popdown(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_resultview")));
	} else if(mode_menu_i == 3) {
		gtk_menu_popdown(popup_menu_expressiontext);
	}
	focus_keeping_selection();
}
void on_popup_menu_mode_delete_activate(GtkMenuItem*, gpointer data) {
	size_t index = 2;
	const char *name = (const char*) data;
	for(; index < modes.size(); index++) {
		if(modes[index].name == name) break;
	}
	if(index >= modes.size()) return;
	gtk_widget_destroy(mode_items[index]);
	gtk_widget_destroy(popup_result_mode_items[index]);
	modes.erase(modes.begin() + index);
	mode_items.erase(mode_items.begin() + index);
	popup_result_mode_items.erase(popup_result_mode_items.begin() + index);
	if(modes.size() < 3) gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "menu_item_meta_mode_delete")), FALSE);
	if(mode_menu_i == 1) {
		gtk_menu_popdown(GTK_MENU(gtk_builder_get_object(main_builder, "mode_menu_menu")));
		gtk_menu_shell_deselect(GTK_MENU_SHELL(gtk_builder_get_object(main_builder, "menubar")));
	} else if(mode_menu_i == 2) {
		gtk_menu_popdown(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_resultview")));
	} else if(mode_menu_i == 3) {
		gtk_menu_popdown(popup_menu_expressiontext);
	}
	focus_keeping_selection();
}

gulong on_popup_menu_mode_update_activate_handler = 0, on_popup_menu_mode_delete_activate_handler = 0;

gboolean on_menu_item_meta_mode_popup_menu(GtkWidget *w, gpointer data) {
	size_t index = 0;
	const char *name = (const char*) data;
	for(; index < modes.size(); index++) {
		if(modes[index].name == name) break;
	}
	if(index >= modes.size()) return TRUE;
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_mode_update")), index > 0);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_mode_delete")), index > 1);
	if(on_popup_menu_mode_update_activate_handler != 0) g_signal_handler_disconnect(gtk_builder_get_object(main_builder, "popup_menu_mode_update"), on_popup_menu_mode_update_activate_handler);
	if(on_popup_menu_mode_delete_activate_handler != 0) g_signal_handler_disconnect(gtk_builder_get_object(main_builder, "popup_menu_mode_delete"), on_popup_menu_mode_delete_activate_handler);
	on_popup_menu_mode_update_activate_handler = g_signal_connect(gtk_builder_get_object(main_builder, "popup_menu_mode_update"), "activate", G_CALLBACK(on_popup_menu_mode_update_activate), data);
	on_popup_menu_mode_delete_activate_handler = g_signal_connect(gtk_builder_get_object(main_builder, "popup_menu_mode_delete"), "activate", G_CALLBACK(on_popup_menu_mode_delete_activate), data);
	mode_menu_i = 0;
	for(size_t i = 0; i < mode_items.size(); i++) {
		if(mode_items[i] == w) {mode_menu_i = 1; break;}
	}
	if(mode_menu_i == 0) {
		for(size_t i = 0; i < popup_result_mode_items.size(); i++) {
			if(popup_result_mode_items[i] == w) {mode_menu_i = 2; break;}
		}
	}
	if(mode_menu_i == 0) {
		for(size_t i = 0; i < popup_expression_mode_items.size(); i++) {
			if(popup_expression_mode_items[i] == w) {mode_menu_i = 3; break;}
		}
	}
#if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 22
	gtk_menu_popup_at_pointer(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_mode")), NULL);
#else
	gtk_menu_popup(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_mode")), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time());
#endif
	return TRUE;
}

gboolean on_menu_item_meta_mode_button_press(GtkWidget *widget, GdkEventButton *event, gpointer data) {
	/* Ignore double-clicks and triple-clicks */
	if(gdk_event_triggers_context_menu((GdkEvent *) event) && event->type == GDK_BUTTON_PRESS) {
		on_menu_item_meta_mode_popup_menu(widget, data);
		return TRUE;
	}
	return FALSE;
}

void on_menu_item_meta_mode_activate(GtkMenuItem*, gpointer user_data) {
	const char *name = (const char*) user_data;
	load_mode(name);
}
void on_menu_item_meta_mode_save_activate(GtkMenuItem*, gpointer) {
	GtkWidget *dialog = gtk_dialog_new_with_buttons(_("Save Mode"), GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT), _("_Save"), GTK_RESPONSE_ACCEPT, _("_Cancel"), GTK_RESPONSE_REJECT, NULL);
	gtk_container_set_border_width(GTK_CONTAINER(dialog), 5);
	GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 12);
	gtk_box_set_homogeneous(GTK_BOX(hbox), TRUE);
	gtk_container_set_border_width(GTK_CONTAINER(hbox), 12);
	gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), hbox);
	gtk_widget_show(hbox);
	GtkWidget *label = gtk_label_new(_("Name"));
	gtk_widget_set_halign(label, GTK_ALIGN_START);
	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 0);
	gtk_widget_show(label);
	GtkWidget *entry = gtk_combo_box_text_new_with_entry();
	for(size_t i = 2; i < modes.size(); i++) {
		gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(entry), modes[i].name.c_str());
	}
	gtk_box_pack_end(GTK_BOX(hbox), entry, FALSE, TRUE, 0);
	gtk_widget_show(entry);
run_meta_mode_save_dialog:
	gint response = gtk_dialog_run(GTK_DIALOG(dialog));
	if(response == GTK_RESPONSE_ACCEPT) {
		bool new_mode = true;
		string name = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(entry));
		remove_blank_ends(name);
		if(name.empty()) {
			show_message(_("Empty name field."), dialog);
			goto run_meta_mode_save_dialog;
		}
		if(name == modes[0].name) {
			show_message(_("Preset mode cannot be overwritten."), dialog);
			goto run_meta_mode_save_dialog;
		}
		size_t index = save_mode_as(name, &new_mode);
		if(new_mode) {
			GtkWidget *item = gtk_menu_item_new_with_label(modes[index].name.c_str()); 
			gtk_widget_show(item); 
			g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(on_menu_item_meta_mode_activate), (gpointer) modes[index].name.c_str());
			g_signal_connect(G_OBJECT(item), "button-press-event", G_CALLBACK(on_menu_item_meta_mode_button_press), (gpointer) modes[index].name.c_str());
			g_signal_connect(G_OBJECT(item), "popup-menu", G_CALLBACK(on_menu_item_meta_mode_popup_menu), (gpointer) modes[index].name.c_str());
			gtk_menu_shell_insert(GTK_MENU_SHELL(gtk_builder_get_object(main_builder, "menu_meta_modes")), item, (gint) index);
			mode_items.push_back(item);
			item = gtk_menu_item_new_with_label(modes[index].name.c_str()); 
			gtk_widget_show(item); 
			g_signal_connect(G_OBJECT(item), "button-press-event", G_CALLBACK(on_menu_item_meta_mode_button_press), (gpointer) modes[index].name.c_str());
			g_signal_connect(G_OBJECT(item), "popup-menu", G_CALLBACK(on_menu_item_meta_mode_popup_menu), (gpointer) modes[index].name.c_str());
			g_signal_connect(G_OBJECT(item), "popup-menu", G_CALLBACK(on_menu_item_meta_mode_popup_menu), (gpointer) modes[index].name.c_str());
			gtk_menu_shell_insert(GTK_MENU_SHELL(gtk_builder_get_object(main_builder, "menu_result_popup_meta_modes")), item, (gint) index);
			popup_result_mode_items.push_back(item);
			if(modes.size() == 3) gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "menu_item_meta_mode_delete")), TRUE);
		}
	}
	gtk_widget_destroy(dialog);
}

void on_menu_item_meta_mode_delete_activate(GtkMenuItem*, gpointer) {
	GtkWidget *dialog = gtk_dialog_new_with_buttons(_("Delete Mode"), GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT), _("_Delete"), GTK_RESPONSE_ACCEPT, _("_Cancel"), GTK_RESPONSE_REJECT, NULL);
	gtk_container_set_border_width(GTK_CONTAINER(dialog), 5);
	GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 12);
	gtk_box_set_homogeneous(GTK_BOX(hbox), TRUE);
	gtk_container_set_border_width(GTK_CONTAINER(hbox), 12);
	gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), hbox);
	gtk_widget_show(hbox);
	GtkWidget *label = gtk_label_new(_("Mode"));
	gtk_widget_set_halign(label, GTK_ALIGN_START);
	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 0);
	gtk_widget_show(label);
	GtkWidget *menu = gtk_combo_box_text_new();
	for(size_t i = 2; i < modes.size(); i++) {
		gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(menu), modes[i].name.c_str());
	}
	gtk_combo_box_set_active(GTK_COMBO_BOX(menu), 0);
	gtk_box_pack_end(GTK_BOX(hbox), menu, FALSE, TRUE, 0);
	gtk_widget_show(menu);
	gint response = gtk_dialog_run(GTK_DIALOG(dialog));
	if(response == GTK_RESPONSE_ACCEPT && gtk_combo_box_get_active(GTK_COMBO_BOX(menu)) >= 0) {
		size_t index = gtk_combo_box_get_active(GTK_COMBO_BOX(menu)) + 2;
		gtk_widget_destroy(mode_items[index]);
		gtk_widget_destroy(popup_result_mode_items[index]);
		modes.erase(modes.begin() + index);
		mode_items.erase(mode_items.begin() + index);
		popup_result_mode_items.erase(popup_result_mode_items.begin() + index);
		if(modes.size() < 3) gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "menu_item_meta_mode_delete")), FALSE);
	}
	gtk_widget_destroy(dialog);
}

/*
	load preferences from ~/.conf/qalculate/qalculate-gtk.cfg
*/
void load_preferences() {

	default_plot_legend_placement = PLOT_LEGEND_TOP_RIGHT;
	default_plot_display_grid = true;
	default_plot_full_border = false;
	default_plot_min = "0";
	default_plot_max = "10";
	default_plot_step = "1";
	default_plot_sampling_rate = 1001;
	default_plot_linewidth = 2;
	default_plot_rows = false;
	default_plot_type = 0;
	default_plot_style = PLOT_STYLE_LINES;
	default_plot_smoothing = PLOT_SMOOTHING_NONE;
	default_plot_variable = "x";
	default_plot_color = true;
	default_plot_use_sampling_rate = true;

	printops.multiplication_sign = MULTIPLICATION_SIGN_X;
	printops.division_sign = DIVISION_SIGN_DIVISION_SLASH;
	printops.is_approximate = new bool(false);
	printops.prefix = NULL;
	printops.use_min_decimals = false;
	printops.use_denominator_prefix = true;
	printops.min_decimals = 0;
	printops.use_max_decimals = false;
	printops.max_decimals = 2;
	printops.base = 10;
	printops.min_exp = EXP_PRECISION;
	printops.negative_exponents = false;
	printops.sort_options.minus_last = true;
	printops.indicate_infinite_series = false;
	printops.show_ending_zeroes = true;
	printops.round_halfway_to_even = false;
	printops.number_fraction_format = FRACTION_DECIMAL;
	printops.restrict_fraction_length = false;
	printops.abbreviate_names = true;
	printops.use_unicode_signs = true;
	printops.digit_grouping = DIGIT_GROUPING_STANDARD;
	printops.use_unit_prefixes = true;
	printops.use_prefixes_for_currencies = false;
	printops.use_prefixes_for_all_units = false;
	printops.spacious = true;
	printops.short_multiplication = true;
	printops.place_units_separately = true;
	printops.use_all_prefixes = false;
	printops.excessive_parenthesis = false;
	printops.allow_non_usable = false;
	printops.lower_case_numbers = false;
	printops.lower_case_e = false;
	printops.base_display = BASE_DISPLAY_NORMAL;
	printops.twos_complement = true;
	printops.hexadecimal_twos_complement = false;
	printops.limit_implicit_multiplication = false;
	printops.can_display_unicode_string_function = &can_display_unicode_string_function;
	printops.allow_factorization = false;
	printops.spell_out_logical_operators = true;
	printops.exp_to_root = true;
	printops.interval_display = INTERVAL_DISPLAY_SIGNIFICANT_DIGITS;
	
	evalops.approximation = APPROXIMATION_TRY_EXACT;
	evalops.sync_units = true;
	evalops.structuring = STRUCTURING_SIMPLIFY;
	evalops.parse_options.unknowns_enabled = false;
	evalops.parse_options.read_precision = DONT_READ_PRECISION;
	evalops.parse_options.base = BASE_DECIMAL;
	evalops.allow_complex = true;
	evalops.allow_infinite = true;
	evalops.auto_post_conversion = POST_CONVERSION_OPTIMAL;
	evalops.assume_denominators_nonzero = true;
	evalops.warn_about_denominators_assumed_nonzero = true;
	evalops.parse_options.limit_implicit_multiplication = false;
	evalops.parse_options.parsing_mode = PARSING_MODE_ADAPTIVE;
	evalops.parse_options.angle_unit = ANGLE_UNIT_RADIANS;
	evalops.parse_options.dot_as_separator = CALCULATOR->default_dot_as_separator;
	evalops.parse_options.comma_as_separator = false;
	evalops.mixed_units_conversion = MIXED_UNITS_CONVERSION_DEFAULT;
	evalops.complex_number_form = COMPLEX_NUMBER_FORM_RECTANGULAR;
	complex_angle_form = false;
	evalops.local_currency_conversion = true;
	evalops.interval_calculation = INTERVAL_CALCULATION_VARIANCE_FORMULA;
	b_decimal_comma = -1;
	
	auto_calculate = false;
	
	default_signed = -1;
	default_bits = -1;
	
	programming_inbase = 0;
	programming_outbase = 0;
	
	visible_keypad = 0;
	
	caret_as_xor = false;
	
	ignore_locale = false;
	
	automatic_fraction = false;
	
	keep_function_dialog_open = false;
	
	copy_separator = true;
	
	use_e_notation = false;
	
	adaptive_interval_display = true;
	
	CALCULATOR->useIntervalArithmetic(true);
	
	CALCULATOR->useBinaryPrefixes(0);
	
	rpn_mode = false;
	rpn_keys = true;
	
	save_mode_as(_("Preset"));
	save_mode_as(_("Default"));
	size_t mode_index = 1;

	win_width = -1;
	win_height = -1;
	variables_width = -1;
	variables_height = -1;
	variables_position = -1;
	units_width = -1;
	units_height = -1;
	units_position = -1;
	functions_width = -1;
	functions_height = -1;
	functions_hposition = -1;
	functions_vposition = -1;
	datasets_width = -1;
	datasets_height = -1;
	datasets_hposition = -1;
	datasets_vposition1 = -1;
	datasets_vposition2 = -1;
	keypad_height = 0;
	history_height = 0;
	save_mode_on_exit = true;
	save_defs_on_exit = true;
	hyp_is_on = false;
	inv_is_on = false;
	use_custom_result_font = false;
	use_custom_expression_font = false;
	use_custom_status_font = false;
	custom_result_font = "";
	custom_expression_font = "";
	custom_status_font = "";
	status_error_color = "#FF0000";
	status_warning_color = "#0000FF";
	status_error_color_set = false;
	status_warning_color_set = false;
	show_keypad = true;
	show_history = false;
	show_stack = true;
	show_convert = false;
	continuous_conversion = true;
	set_missing_prefixes = false;
	load_global_defs = true;
	fetch_exchange_rates_at_startup = false;
	auto_update_exchange_rates = -1;
	display_expression_status = true;
	enable_completion = true;
	enable_completion2 = true;
	completion_min = 1;
	completion_min2 = 1;
	completion_delay = 0;
	first_time = false;
	first_error = true;
	expression_history.clear();
	expression_history_index = -1;
	hexadecimal_twos_complement_in = false;
	twos_complement_in = false;
	
#ifdef _WIN32
	last_version_check_date.setToCurrentDate();
#endif
	
	latest_button_unit = NULL;
	latest_button_currency = NULL;

	FILE *file = NULL;
	gchar *gstr_oldfile = NULL;
	gchar *gstr_file = g_build_filename(getLocalDir().c_str(), "qalculate-gtk.cfg", NULL);
	file = fopen(gstr_file, "r");
	if(!file) {
#ifndef _WIN32
		gstr_oldfile = g_build_filename(getOldLocalDir().c_str(), "qalculate-gtk.cfg", NULL);
		file = fopen(gstr_oldfile, "r");
		if(!file) {
			g_free(gstr_oldfile);
#endif
			g_free(gstr_file);
			first_time = true;
			update_message_print_options();
			displayed_printops = printops;
			displayed_caf = complex_angle_form;
			return;
#ifndef _WIN32
		}
#endif
	}

	int version_numbers[] = {3, 5, 0};
	bool old_history_format = false;
			
	if(file) {
		char line[1000000L];
		string stmp, svalue, svar;
		size_t i;
		int v;
		while(true) {
			if(fgets(line, 1000000L, file) == NULL) break;
			stmp = line;
			remove_blank_ends(stmp);
			if((i = stmp.find_first_of("=")) != string::npos) {
				svar = stmp.substr(0, i);
				remove_blank_ends(svar);
				svalue = stmp.substr(i + 1);
				remove_blank_ends(svalue);
				v = s2i(svalue);
				if(svar == "version") {
					parse_qalculate_version(svalue, version_numbers);
					old_history_format = (version_numbers[0] == 0 && (version_numbers[1] < 9 || (version_numbers[1] == 9 && version_numbers[2] <= 4)));
				} else if(svar == "allow_multiple_instances") {
					if(v == 0 && version_numbers[0] < 3) v = -1;
					allow_multiple_instances = v;
				} else if(svar == "width") {
					win_width = v;
				/*} else if(svar == "height") {
					win_height = v;*/
				} else if(svar == "variables_width") {
					variables_width = v;
				} else if(svar == "variables_height") {
					variables_height = v;
				} else if(svar == "variables_panel_position") {
					variables_position = v;
				} else if(svar == "units_width") {
					units_width = v;
				} else if(svar == "units_height") {
					units_height = v;
				} else if(svar == "units_panel_position") {
					units_position = v;
				} else if(svar == "functions_width") {
					functions_width = v;
				} else if(svar == "functions_height") {
					functions_height = v;
				} else if(svar == "functions_hpanel_position") {
					functions_hposition = v;
				} else if(svar == "functions_vpanel_position") {
					functions_vposition = v;
				} else if(svar == "datasets_width") {
					datasets_width = v;
				} else if(svar == "datasets_height") {
					datasets_height = v;
				} else if(svar == "datasets_hpanel_position") {
					datasets_hposition = v;
				} else if(svar == "datasets_vpanel1_position") {
					datasets_vposition1 = v;
				} else if(svar == "datasets_vpanel2_position") {
					datasets_vposition2 = v;
				} else if(svar == "keep_function_dialog_open") {
					keep_function_dialog_open = v;
				} else if(svar == "error_info_shown") {
					first_error = !v;
				} else if(svar == "save_mode_on_exit") {
					save_mode_on_exit = v;
				} else if(svar == "save_definitions_on_exit") {
					save_defs_on_exit = v;
				} else if(svar == "ignore_locale") {
					ignore_locale = v;
				} else if(svar == "fetch_exchange_rates_at_startup") {
					if(auto_update_exchange_rates < 0 && v) auto_update_exchange_rates = 1;
					//fetch_exchange_rates_at_startup = v;
				} else if(svar == "auto_update_exchange_rates") {
					auto_update_exchange_rates = v;
#ifdef _WIN32
				} else if(svar == "last_version_check") {
					last_version_check_date.set(svalue);
				} else if(svar == "last_found_version") {
					last_found_version = svalue;
#endif
				} else if(svar == "show_keypad") {
					show_keypad = v;
				/*} else if(svar == "keypad_height") {
					keypad_height = v;*/
				} else if(svar == "show_history") {
					show_history = v;
				} else if(svar == "history_height") {
					history_height = v;
				} else if(svar == "show_stack") {
					show_stack = v;
				} else if(svar == "show_convert") {
					show_convert = v;
				} else if(svar == "continuous_conversion") {
					continuous_conversion = v;
				} else if(svar == "set_missing_prefixes") {
					set_missing_prefixes = v;
				} else if(svar == "display_expression_status") {
					display_expression_status = v;
				} else if(svar == "enable_completion") {
					enable_completion = v;
				} else if(svar == "enable_completion2") {
					enable_completion2 = v;
				} else if(svar == "completion_min") {
					if(v < 1) v = 1;
					completion_min = v;
				} else if(svar == "completion_min2") {
					if(v < 1) v = 1;
					completion_min2 = v;
				} else if(svar == "completion_delay") {
					if(v < 0) v = 0;
					completion_delay = v;
				} else if(svar == "programming_outbase") {
					programming_outbase = v;
				} else if(svar == "programming_inbase") {
					programming_inbase = v;
				} else if(svar == "general_exact") {
					versatile_exact = v;
				} else if(svar == "bit_width") {
					default_bits = v;
				} else if(svar == "signed_integer") {
					default_signed = v;
				} else if(svar == "min_deci") {
					if(mode_index == 1) printops.min_decimals = v;
					else modes[mode_index].po.min_decimals = v;
				} else if(svar == "use_min_deci") {
					if(mode_index == 1) printops.use_min_decimals = v;
					else modes[mode_index].po.use_min_decimals = v;
				} else if(svar == "max_deci") {
					if(mode_index == 1) printops.max_decimals = v;
					else modes[mode_index].po.max_decimals = v;
				} else if(svar == "use_max_deci") {
					if(mode_index == 1) printops.use_max_decimals = v;
					else modes[mode_index].po.use_max_decimals = v;
				} else if(svar == "precision") {
					if(mode_index == 1) CALCULATOR->setPrecision(v);
					else modes[mode_index].precision = v;
				} else if(svar == "min_exp") {
					if(mode_index == 1) printops.min_exp = v;
					else modes[mode_index].po.min_exp = v;
				} else if(svar == "interval_arithmetic") {
					if(version_numbers[0] >= 3) {
						if(mode_index == 1) CALCULATOR->useIntervalArithmetic(v);
						else modes[mode_index].interval = v;
					} else {
						modes[mode_index].interval = true;
					}
				} else if(svar == "interval_display") {
					if(v == 0) {
						if(mode_index == 1) {printops.interval_display = INTERVAL_DISPLAY_SIGNIFICANT_DIGITS; adaptive_interval_display = true;}
						else {modes[mode_index].po.interval_display = INTERVAL_DISPLAY_SIGNIFICANT_DIGITS; modes[mode_index].adaptive_interval_display = true;}
					} else {
						v--;
						if(v >= INTERVAL_DISPLAY_SIGNIFICANT_DIGITS && v <= INTERVAL_DISPLAY_UPPER) {
							if(mode_index == 1) {printops.interval_display = (IntervalDisplay) v; adaptive_interval_display = false;}
							else {modes[mode_index].po.interval_display = (IntervalDisplay) v; modes[mode_index].adaptive_interval_display = false;}
						}
					}
				} else if(svar == "negative_exponents") {
					if(mode_index == 1) printops.negative_exponents = v;
					else modes[mode_index].po.negative_exponents = v;
				} else if(svar == "sort_minus_last") {
					if(mode_index == 1) printops.sort_options.minus_last = v;
					else modes[mode_index].po.sort_options.minus_last = v;
				} else if(svar == "place_units_separately") {
					if(mode_index == 1) printops.place_units_separately = v;
					else modes[mode_index].po.place_units_separately = v;
				} else if(svar == "display_mode") {	//obsolete
					switch(v) {
						case 1: {
							if(mode_index == 1) {
								printops.min_exp = EXP_PRECISION;
								printops.negative_exponents = false;
								printops.sort_options.minus_last = true;
							} else {
								modes[mode_index].po.min_exp = EXP_PRECISION;
								modes[mode_index].po.negative_exponents = false;
								modes[mode_index].po.sort_options.minus_last = true;
							}
							break;
						}
						case 2: {
							if(mode_index == 1) {
								printops.min_exp = EXP_SCIENTIFIC;
								printops.negative_exponents = true;
								printops.sort_options.minus_last = false;
							} else {
								modes[mode_index].po.min_exp = EXP_SCIENTIFIC;
								modes[mode_index].po.negative_exponents = true;
								modes[mode_index].po.sort_options.minus_last = false;
							}
							break;
						}
						case 3: {
							if(mode_index == 1) {
								printops.min_exp = EXP_PURE;
								printops.negative_exponents = true;
								printops.sort_options.minus_last = false;
							} else {
								modes[mode_index].po.min_exp = EXP_PURE;
								modes[mode_index].po.negative_exponents = true;
								modes[mode_index].po.sort_options.minus_last = false;
							}
							break;
						}
						case 4: {
							if(mode_index == 1) {
								printops.min_exp = EXP_NONE;
								printops.negative_exponents = false;
								printops.sort_options.minus_last = true;
							} else {
								modes[mode_index].po.min_exp = EXP_NONE;
								modes[mode_index].po.negative_exponents = false;
								modes[mode_index].po.sort_options.minus_last = true;
							}
							break;
						}
					}
				} else if(svar == "use_prefixes") {
					if(mode_index == 1) printops.use_unit_prefixes = v;
					else modes[mode_index].po.use_unit_prefixes = v;
				} else if(svar == "use_prefixes_for_all_units") {
					if(mode_index == 1) printops.use_prefixes_for_all_units = v;
					else modes[mode_index].po.use_prefixes_for_all_units = v;
				} else if(svar == "use_prefixes_for_currencies") {
					if(mode_index == 1) printops.use_prefixes_for_currencies = v;
					else modes[mode_index].po.use_prefixes_for_currencies = v;
				} else if(svar == "fractional_mode") {	//obsolete
					switch(v) {
						case 1: {
							if(mode_index == 1) printops.number_fraction_format = FRACTION_DECIMAL;
							else modes[mode_index].po.number_fraction_format = FRACTION_DECIMAL;
							break;
						}
						case 2: {
							if(mode_index == 1) printops.number_fraction_format = FRACTION_COMBINED;
							else modes[mode_index].po.number_fraction_format = FRACTION_COMBINED;
							break;
						}
						case 3: {
							if(mode_index == 1) printops.number_fraction_format = FRACTION_FRACTIONAL;
							else modes[mode_index].po.number_fraction_format = FRACTION_FRACTIONAL;
							break;
						}
					}
					if(mode_index == 1) printops.restrict_fraction_length = (printops.number_fraction_format == FRACTION_FRACTIONAL);
					else modes[mode_index].po.restrict_fraction_length = (modes[mode_index].po.number_fraction_format == FRACTION_FRACTIONAL);
				} else if(svar == "number_fraction_format") {
					if(v >= FRACTION_DECIMAL && v <= FRACTION_COMBINED) {
						if(mode_index == 1) printops.number_fraction_format = (NumberFractionFormat) v;
						else modes[mode_index].po.number_fraction_format = (NumberFractionFormat) v;
					}
					if(mode_index == 1) printops.restrict_fraction_length = (printops.number_fraction_format == FRACTION_FRACTIONAL);
					else modes[mode_index].po.restrict_fraction_length = (modes[mode_index].po.number_fraction_format == FRACTION_FRACTIONAL);
				} else if(svar == "automatic_number_fraction_format") {
					automatic_fraction = v;
				} else if(svar == "complex_number_form") {
					if(v == COMPLEX_NUMBER_FORM_CIS + 1) {
						if(mode_index == 1) {
							evalops.complex_number_form = COMPLEX_NUMBER_FORM_CIS;
							complex_angle_form = true;
						} else {
							modes[mode_index].eo.complex_number_form = COMPLEX_NUMBER_FORM_CIS;
							modes[mode_index].complex_angle_form = true;
						}
					} else if(v >= COMPLEX_NUMBER_FORM_RECTANGULAR && v <= COMPLEX_NUMBER_FORM_CIS) {
						if(mode_index == 1) {
							evalops.complex_number_form = (ComplexNumberForm) v;
							complex_angle_form = false;
						} else {
							modes[mode_index].eo.complex_number_form = (ComplexNumberForm) v;
							modes[mode_index].complex_angle_form = false;
						}
					}
				} else if(svar == "number_base") {
					if(mode_index == 1) printops.base = v;
					else modes[mode_index].po.base = v;
				} else if(svar == "custom_number_base") {
					CALCULATOR->beginTemporaryStopMessages();
					MathStructure m;
					CALCULATOR->calculate(&m, svalue, 500);
					CALCULATOR->endTemporaryStopMessages();
					if(mode_index == 1) CALCULATOR->setCustomOutputBase(m.number());
					else modes[mode_index].custom_output_base = m.number();
				} else if(svar == "number_base_expression") {
					if(mode_index == 1) evalops.parse_options.base = v;
					else modes[mode_index].eo.parse_options.base = v;
				} else if(svar == "custom_number_base_expression") {
					CALCULATOR->beginTemporaryStopMessages();
					MathStructure m;
					CALCULATOR->calculate(&m, svalue, 500);
					CALCULATOR->endTemporaryStopMessages();
					if(mode_index == 1) CALCULATOR->setCustomInputBase(m.number());
					else modes[mode_index].custom_input_base = m.number();
				} else if(svar == "read_precision") {
					if(v >= DONT_READ_PRECISION && v <= READ_PRECISION_WHEN_DECIMALS) {
						if(mode_index == 1) evalops.parse_options.read_precision = (ReadPrecisionMode) v;
						else modes[mode_index].eo.parse_options.read_precision = (ReadPrecisionMode) v;
					}
				} else if(svar == "assume_denominators_nonzero") {
					if(version_numbers[0] == 0 && (version_numbers[1] < 9 || (version_numbers[1] == 9 && version_numbers[2] == 0))) {
						v = true;
					}
					if(mode_index == 1) evalops.assume_denominators_nonzero = v;
					else modes[mode_index].eo.assume_denominators_nonzero = v;
				} else if(svar == "warn_about_denominators_assumed_nonzero") {
					if(mode_index == 1) evalops.warn_about_denominators_assumed_nonzero = v;
					else modes[mode_index].eo.warn_about_denominators_assumed_nonzero = v;
				} else if(svar == "structuring") {
					if(v >= STRUCTURING_NONE && v <= STRUCTURING_FACTORIZE) {
						if((v == STRUCTURING_NONE) && version_numbers[0] == 0 && (version_numbers[1] < 9 || (version_numbers[1] == 9 && version_numbers[2] <= 12))) {
							v = STRUCTURING_SIMPLIFY;
						}
						if(mode_index == 1) {
							evalops.structuring = (StructuringMode) v;
							printops.allow_factorization = (evalops.structuring == STRUCTURING_FACTORIZE);
						} else {
							modes[mode_index].eo.structuring = (StructuringMode) v;
							modes[mode_index].po.allow_factorization = (modes[mode_index].eo.structuring == STRUCTURING_FACTORIZE);
						}
					}
				} else if(svar == "angle_unit") {
					if(version_numbers[0] == 0 && (version_numbers[1] < 7 || (version_numbers[1] == 7 && version_numbers[2] == 0))) {
						v++;
					}
					if(v >= ANGLE_UNIT_NONE && v <= ANGLE_UNIT_GRADIANS) {
						if(mode_index == 1) evalops.parse_options.angle_unit = (AngleUnit) v;
						else modes[mode_index].eo.parse_options.angle_unit = (AngleUnit) v;
					}
				} else if(svar == "functions_enabled") {
					if(mode_index == 1) evalops.parse_options.functions_enabled = v;
					else modes[mode_index].eo.parse_options.functions_enabled = v;
				} else if(svar == "variables_enabled") {
					if(mode_index == 1) evalops.parse_options.variables_enabled = v;
					else modes[mode_index].eo.parse_options.variables_enabled = v;
				} else if(svar == "donot_calculate_variables") {
					if(mode_index == 1) evalops.calculate_variables = !v;
					else modes[mode_index].eo.calculate_variables = !v;
				} else if(svar == "calculate_variables") {
					if(mode_index == 1) evalops.calculate_variables = v;
					else modes[mode_index].eo.calculate_variables = v;
				} else if(svar == "variable_units_enabled") {
					if(mode_index == 1) CALCULATOR->setVariableUnitsEnabled(v);
					else modes[mode_index].variable_units_enabled = v;
				} else if(svar == "calculate_functions") {
					if(mode_index == 1) evalops.calculate_functions = v;
					else modes[mode_index].eo.calculate_functions = v;
				} else if(svar == "sync_units") {
					if(mode_index == 1) evalops.sync_units = v;
					else modes[mode_index].eo.sync_units = v;
				} else if(svar == "unknownvariables_enabled") {
					if(mode_index == 1) evalops.parse_options.unknowns_enabled = v;
					else modes[mode_index].eo.parse_options.unknowns_enabled = v;
				} else if(svar == "units_enabled") {
					if(mode_index == 1) evalops.parse_options.units_enabled = v;
					else modes[mode_index].eo.parse_options.units_enabled = v;
				} else if(svar == "allow_complex") {
					if(mode_index == 1) evalops.allow_complex = v;
					else modes[mode_index].eo.allow_complex = v;
				} else if(svar == "allow_infinite") {
					if(mode_index == 1) evalops.allow_infinite = v;
					else modes[mode_index].eo.allow_infinite = v;
				} else if(svar == "use_short_units") {
					if(mode_index == 1) printops.abbreviate_names = v;
					else modes[mode_index].po.abbreviate_names = v;
				} else if(svar == "abbreviate_names") {
					if(mode_index == 1) printops.abbreviate_names = v;
					else modes[mode_index].po.abbreviate_names = v;
				} else if(svar == "all_prefixes_enabled") {
					if(mode_index == 1) printops.use_all_prefixes = v;
					else modes[mode_index].po.use_all_prefixes = v;
				} else if(svar == "denominator_prefix_enabled") {
					if(mode_index == 1) printops.use_denominator_prefix = v;
					else modes[mode_index].po.use_denominator_prefix = v;
				} else if(svar == "auto_post_conversion") {
					if(v >= POST_CONVERSION_NONE && v <= POST_CONVERSION_OPTIMAL) {
						if(v == POST_CONVERSION_NONE && version_numbers[0] == 0 && (version_numbers[1] < 9 || (version_numbers[1] == 9 && version_numbers[2] <= 12))) {
							v = POST_CONVERSION_OPTIMAL;
						}
						if(mode_index == 1) evalops.auto_post_conversion = (AutoPostConversion) v;
						else modes[mode_index].eo.auto_post_conversion = (AutoPostConversion) v;
					}
				} else if(svar == "mixed_units_conversion") {
					if(v >= MIXED_UNITS_CONVERSION_NONE || v <= MIXED_UNITS_CONVERSION_FORCE_ALL) {
						if(mode_index == 1) evalops.mixed_units_conversion = (MixedUnitsConversion) v;
						else modes[mode_index].eo.mixed_units_conversion = (MixedUnitsConversion) v;
					}
				} else if(svar == "local_currency_conversion") {
					evalops.local_currency_conversion = v;
				} else if(svar == "use_binary_prefixes") {
					CALCULATOR->useBinaryPrefixes(v);
				} else if(svar == "indicate_infinite_series") {
					if(mode_index == 1) printops.indicate_infinite_series = v;
					else modes[mode_index].po.indicate_infinite_series = v;
				} else if(svar == "show_ending_zeroes") {
					if(version_numbers[0] > 2 || (version_numbers[0] == 2 && version_numbers[1] >= 9)) {
						if(mode_index == 1) printops.show_ending_zeroes = v;
						else modes[mode_index].po.show_ending_zeroes = v;
					}
				} else if(svar == "digit_grouping") {
					if(v >= DIGIT_GROUPING_NONE && v <= DIGIT_GROUPING_LOCALE) {
						printops.digit_grouping = (DigitGrouping) v;
					}
				} else if(svar == "round_halfway_to_even") {
					if(mode_index == 1) printops.round_halfway_to_even = v;	
					else modes[mode_index].po.round_halfway_to_even = v;	
				} else if(svar == "always_exact") {		//obsolete
					if(mode_index == 1) {
						evalops.approximation = APPROXIMATION_EXACT;
					} else {
						modes[mode_index].eo.approximation = APPROXIMATION_EXACT;
						modes[mode_index].interval = false;
					}
				} else if(svar == "approximation") {
					if(v >= APPROXIMATION_EXACT && v <= APPROXIMATION_APPROXIMATE) {
						if(mode_index == 1) {
							evalops.approximation = (ApproximationMode) v;
						} else {
							modes[mode_index].eo.approximation = (ApproximationMode) v;
						}
					}
				} else if(svar == "interval_calculation") {
					if(v >= INTERVAL_CALCULATION_NONE && v <= INTERVAL_CALCULATION_SIMPLE_INTERVAL_ARITHMETIC) {
						if(mode_index == 1) evalops.interval_calculation = (IntervalCalculation) v;
						else modes[mode_index].eo.interval_calculation = (IntervalCalculation) v;
					}
				} else if(svar == "calculate_as_you_type") {
					if(mode_index == 1) auto_calculate = v;
					else modes[mode_index].autocalc = v;
				} else if(svar == "in_rpn_mode") {
					if(mode_index == 1) rpn_mode = v;
					else modes[mode_index].rpn_mode = v;
				} else if(svar == "rpn_keys") {
					rpn_keys = v;
				} else if(svar == "rpn_syntax") {
					if(mode_index == 1) evalops.parse_options.rpn = v;
					else modes[mode_index].eo.parse_options.rpn = v;
				} else if(svar == "limit_implicit_multiplication") {
					if(mode_index == 1) {
						evalops.parse_options.limit_implicit_multiplication = v;
						printops.limit_implicit_multiplication = v;
					} else {
						modes[mode_index].eo.parse_options.limit_implicit_multiplication = v;
						modes[mode_index].po.limit_implicit_multiplication = v;
					}
				} else if(svar == "parsing_mode") {
					if(v >= PARSING_MODE_ADAPTIVE && v <= PARSING_MODE_CONVENTIONAL) {
						if(mode_index == 1) {
							evalops.parse_options.parsing_mode = (ParsingMode) v;
						} else {
							modes[mode_index].eo.parse_options.parsing_mode = (ParsingMode) v;
						}
					}
				} else if(svar == "default_assumption_type") {
					if(v >= ASSUMPTION_TYPE_NONE && v <= ASSUMPTION_TYPE_INTEGER) {
						if(v < ASSUMPTION_TYPE_NUMBER && version_numbers[0] < 1) v = ASSUMPTION_TYPE_NUMBER;
						if(v == ASSUMPTION_TYPE_COMPLEX && version_numbers[0] < 2) v = ASSUMPTION_TYPE_NUMBER;
						if(mode_index == 1) CALCULATOR->defaultAssumptions()->setType((AssumptionType) v);
						else modes[mode_index].at = (AssumptionType) v;
					}
				} else if(svar == "default_assumption_sign") {
					if(v >= ASSUMPTION_SIGN_UNKNOWN && v <= ASSUMPTION_SIGN_NONZERO) {
						if(v == ASSUMPTION_SIGN_NONZERO && version_numbers[0] == 0 && (version_numbers[1] < 9 || (version_numbers[1] == 9 && version_numbers[2] == 0))) {
							v = ASSUMPTION_SIGN_UNKNOWN;
						}
						if(mode_index == 1) CALCULATOR->defaultAssumptions()->setSign((AssumptionSign) v);
						else modes[mode_index].as = (AssumptionSign) v;
					}
				} else if(svar == "spacious") {
					if(mode_index == 1) printops.spacious = v;
					else modes[mode_index].po.spacious = v;
				} else if(svar == "excessive_parenthesis") {
					if(mode_index == 1) printops.excessive_parenthesis = v;
					else modes[mode_index].po.excessive_parenthesis = v;
				} else if(svar == "short_multiplication") {
					if(mode_index == 1) printops.short_multiplication = v;
					else modes[mode_index].po.short_multiplication = v;
				} else if(svar == "visible_keypad") {
					if(mode_index == 1) visible_keypad = v;
					else modes[mode_index].keypad = v;
				} else if(svar == "use_unicode_signs" && (version_numbers[0] > 0 || version_numbers[1] > 7 || (version_numbers[1] == 7 && version_numbers[2] > 0))) {
					printops.use_unicode_signs = v;
				} else if(svar == "lower_case_numbers") {
					printops.lower_case_numbers = v;	
				} else if(svar == "lower_case_e") {
					printops.lower_case_e = v;	
				} else if(svar == "e_notation") {
					use_e_notation = v;
				} else if(svar == "imaginary_j") {
					do_imaginary_j = v;
				} else if(svar == "base_display") {
					if(v >= BASE_DISPLAY_NONE && v <= BASE_DISPLAY_ALTERNATIVE) printops.base_display = (BaseDisplay) v;
				} else if(svar == "twos_complement") {
					printops.twos_complement = v;
				} else if(svar == "hexadecimal_twos_complement") {
					printops.hexadecimal_twos_complement = v;
				} else if(svar == "twos_complement_input") {
					twos_complement_in = v;
				} else if(svar == "hexadecimal_twos_complement_input") {
					hexadecimal_twos_complement_in = v;
				} else if(svar == "spell_out_logical_operators") {
					printops.spell_out_logical_operators = v;
				} else if(svar == "caret_as_xor") {
					caret_as_xor = v;
				} else if(svar == "copy_separator") {
					copy_separator = v;
				} else if(svar == "decimal_comma") {
					b_decimal_comma = v;
					if(v == 0) CALCULATOR->useDecimalPoint(evalops.parse_options.comma_as_separator);
					else if(v > 0) CALCULATOR->useDecimalComma();
				} else if(svar == "dot_as_separator") {
					evalops.parse_options.dot_as_separator = v;
				} else if(svar == "comma_as_separator") {
					evalops.parse_options.comma_as_separator = v;
					if(CALCULATOR->getDecimalPoint() != COMMA) {
						CALCULATOR->useDecimalPoint(evalops.parse_options.comma_as_separator);
					}
				} else if(svar == "use_custom_result_font") {
					use_custom_result_font = v;
				} else if(svar == "use_custom_expression_font") {
					use_custom_expression_font = v;
				} else if(svar == "use_custom_status_font") {
					use_custom_status_font = v;
				} else if(svar == "custom_result_font") {
					custom_result_font = svalue;
					save_custom_result_font = true;
				} else if(svar == "custom_expression_font") {
					custom_expression_font = svalue;
					save_custom_expression_font = true;
				} else if(svar == "custom_status_font") {
					custom_status_font = svalue;
					save_custom_status_font = true;
				} else if(svar == "status_error_color") {
					status_error_color = svalue;
					status_error_color_set = true;
				} else if(svar == "status_warning_color") {
					status_warning_color = svalue;
					status_warning_color_set = true;
				} else if(svar == "multiplication_sign") {
					if(svalue == "*") {
						printops.multiplication_sign = MULTIPLICATION_SIGN_ASTERISK;
					} else if(svalue == SIGN_MULTIDOT) {
						printops.multiplication_sign = MULTIPLICATION_SIGN_DOT;
					} else if(svalue == SIGN_MIDDLEDOT) {
						printops.multiplication_sign = MULTIPLICATION_SIGN_ALTDOT;
					} else if(svalue == SIGN_MULTIPLICATION) {
						printops.multiplication_sign = MULTIPLICATION_SIGN_X;
					} else if(v >= MULTIPLICATION_SIGN_ASTERISK && v <= MULTIPLICATION_SIGN_ALTDOT) {
						printops.multiplication_sign = (MultiplicationSign) v;
					}
					if(printops.multiplication_sign == MULTIPLICATION_SIGN_DOT && version_numbers[0] < 2) {
						printops.multiplication_sign = MULTIPLICATION_SIGN_X;
					}
				} else if(svar == "division_sign") {
					if(v >= DIVISION_SIGN_SLASH && v <= DIVISION_SIGN_DIVISION) printops.division_sign = (DivisionSign) v;
				} else if(svar == "recent_functions") {
					size_t v_i = 0;
					while(true) {
						v_i = svalue.find(',');
						if(v_i == string::npos) {
							svar = svalue.substr(0, svalue.length());
							remove_blank_ends(svar);
							if(!svar.empty()) {
								recent_functions_pre.push_back(svar);	
							}
							break;
						} else {
							svar = svalue.substr(0, v_i);
							svalue = svalue.substr(v_i + 1, svalue.length() - (v_i + 1));
							remove_blank_ends(svar);
							if(!svar.empty()) {
								recent_functions_pre.push_back(svar);	
							}
						}
					}
				} else if(svar == "recent_variables") {
					size_t v_i = 0;
					while(true) {
						v_i = svalue.find(',');
						if(v_i == string::npos) {
							svar = svalue.substr(0, svalue.length());
							remove_blank_ends(svar);
							if(!svar.empty()) {
								recent_variables_pre.push_back(svar);	
							}
							break;
						} else {
							svar = svalue.substr(0, v_i);
							svalue = svalue.substr(v_i + 1, svalue.length() - (v_i + 1));
							remove_blank_ends(svar);
							if(!svar.empty()) {
								recent_variables_pre.push_back(svar);	
							}
						}
					}
				} else if(svar == "recent_units") {
					size_t v_i = 0;
					while(true) {
						v_i = svalue.find(',');
						if(v_i == string::npos) {
							svar = svalue.substr(0, svalue.length());
							remove_blank_ends(svar);
							if(!svar.empty()) {
								recent_units_pre.push_back(svar);	
							}
							break;
						} else {
							svar = svalue.substr(0, v_i);
							svalue = svalue.substr(v_i + 1, svalue.length() - (v_i + 1));
							remove_blank_ends(svar);
							if(!svar.empty()) {
								recent_units_pre.push_back(svar);	
							}
						}
					}
				} else if(svar == "latest_button_unit") {
					latest_button_unit_pre = svalue;
				} else if(svar == "latest_button_currency") {
					latest_button_currency_pre = svalue;
				} else if(svar == "plot_legend_placement") {
					if(v >= PLOT_LEGEND_NONE && v <= PLOT_LEGEND_OUTSIDE) default_plot_legend_placement = (PlotLegendPlacement) v;
				} else if(svar == "plot_style") {
					if(v >= PLOT_STYLE_LINES && v <= PLOT_STYLE_DOTS) default_plot_style = (PlotStyle) v;
				} else if(svar == "plot_smoothing") {
					if(v >= PLOT_SMOOTHING_NONE && v <= PLOT_SMOOTHING_SBEZIER) default_plot_smoothing = (PlotSmoothing) v;		
				} else if(svar == "plot_display_grid") {
					default_plot_display_grid = v;
				} else if(svar == "plot_full_border") {
					default_plot_full_border = v;
				} else if(svar == "plot_min") {
					default_plot_min = svalue;	
				} else if(svar == "plot_max") {
					default_plot_max = svalue;
				} else if(svar == "plot_step") {
					default_plot_step = svalue;
				} else if(svar == "plot_sampling_rate") {
					default_plot_sampling_rate = v;	
				} else if(svar == "plot_use_sampling_rate") {
					default_plot_use_sampling_rate = v;		
				} else if(svar == "plot_variable") {
					default_plot_variable = svalue;
				} else if(svar == "plot_rows") {
					default_plot_rows = v;	
				} else if(svar == "plot_type") {
					default_plot_type = v;	
				} else if(svar == "plot_color") {
					if(version_numbers[0] > 2 || (version_numbers[0] == 2 && (version_numbers[1] > 2 || (version_numbers[1] == 2 && version_numbers[2] > 1)))) {
						default_plot_color = v;
					}
				} else if(svar == "plot_linewidth") {
					default_plot_linewidth = v;
				} else if(svar == "expression_history") {
					expression_history.push_back(svalue);		
				} else if(svar == "history") {
					inhistory.push_front(svalue);
					inhistory_type.push_front(QALCULATE_HISTORY_OLD);
					inhistory_protected.push_front(false);
					inhistory_value.push_front(0);
				} else if(svar == "history_old") {
					inhistory.push_front(svalue);
					inhistory_type.push_front(QALCULATE_HISTORY_OLD);
					inhistory_protected.push_front(false);
					inhistory_value.push_front(0);
				} else if(svar == "history_expression") {
					inhistory.push_front(svalue);
					inhistory_type.push_front(QALCULATE_HISTORY_EXPRESSION);
					inhistory_protected.push_front(false);
					inhistory_value.push_front(0);
				} else if(svar == "history_expression*") {
					inhistory.push_front(svalue);
					inhistory_type.push_front(QALCULATE_HISTORY_EXPRESSION);
					inhistory_protected.push_front(true);
					inhistory_value.push_front(0);
				} else if(svar == "history_transformation") {
					inhistory.push_front(svalue);
					inhistory_type.push_front(QALCULATE_HISTORY_TRANSFORMATION);
					inhistory_protected.push_front(false);
					inhistory_value.push_front(0);
				} else if(svar == "history_result") {
					inhistory.push_front(svalue);
					inhistory_type.push_front(QALCULATE_HISTORY_RESULT);
					inhistory_protected.push_front(false);
					inhistory_value.push_front(0);
				} else if(svar == "history_result_approximate") {
					inhistory.push_front(svalue);
					inhistory_type.push_front(QALCULATE_HISTORY_RESULT_APPROXIMATE);
					inhistory_protected.push_front(false);
					inhistory_value.push_front(0);
				} else if(svar == "history_parse") {
					inhistory.push_front(svalue);
					if(old_history_format) inhistory_type.push_front(QALCULATE_HISTORY_PARSE_WITHEQUALS);
					else inhistory_type.push_front(QALCULATE_HISTORY_PARSE);
					inhistory_protected.push_front(false);
					inhistory_value.push_front(0);
				} else if(svar == "history_parse_withequals") {
					inhistory.push_front(svalue);
					inhistory_type.push_front(QALCULATE_HISTORY_PARSE_WITHEQUALS);
					inhistory_protected.push_front(false);
					inhistory_value.push_front(0);
				} else if(svar == "history_parse_approximate") {
					inhistory.push_front(svalue);
					inhistory_type.push_front(QALCULATE_HISTORY_PARSE_APPROXIMATE);
					inhistory_protected.push_front(false);
					inhistory_value.push_front(0);
				} else if(svar == "history_register_moved") {
					inhistory.push_front(svalue);
					inhistory_type.push_front(QALCULATE_HISTORY_REGISTER_MOVED);
					inhistory_protected.push_front(false);
					inhistory_value.push_front(0);
				} else if(svar == "history_rpn_operation") {
					inhistory.push_front(svalue);
					inhistory_type.push_front(QALCULATE_HISTORY_RPN_OPERATION);
					inhistory_protected.push_front(false);
					inhistory_value.push_front(0);
				} else if(svar == "history_register_moved*") {
					inhistory.push_front(svalue);
					inhistory_type.push_front(QALCULATE_HISTORY_REGISTER_MOVED);
					inhistory_protected.push_front(true);
					inhistory_value.push_front(0);
				} else if(svar == "history_rpn_operation*") {
					inhistory.push_front(svalue);
					inhistory_type.push_front(QALCULATE_HISTORY_RPN_OPERATION);
					inhistory_protected.push_front(true);
					inhistory_value.push_front(0);
				} else if(svar == "history_warning") {
					inhistory.push_front(svalue);
					inhistory_type.push_front(QALCULATE_HISTORY_WARNING);
					inhistory_protected.push_front(false);
					inhistory_value.push_front(0);
				} else if(svar == "history_error") {
					inhistory.push_front(svalue);
					inhistory_type.push_front(QALCULATE_HISTORY_ERROR);
					inhistory_protected.push_front(false);
					inhistory_value.push_front(0);
				} else if(svar == "history_bookmark") {
					inhistory.push_front(svalue);
					inhistory_type.push_front(QALCULATE_HISTORY_BOOKMARK);
					inhistory_protected.push_front(false);
					inhistory_value.push_front(0);
					bool b = false;
					for(vector<string>::iterator it = history_bookmarks.begin(); it != history_bookmarks.end(); ++it) {
						if(string_is_less(svalue, *it)) {
							history_bookmarks.insert(it, svalue);
							b = true;
							break;
						}
					}
					if(!b) history_bookmarks.push_back(svalue);
				} else if(svar == "history_continued") {
					if(inhistory.size() > 0) {
						inhistory[0] += "\n";
						inhistory[0] += svalue;
					}
				}
			} else if(stmp.length() > 2 && stmp[0] == '[' && stmp[stmp.length() - 1] == ']') {
				stmp = stmp.substr(1, stmp.length() - 2);
				remove_blank_ends(stmp);
				if(stmp == "Mode") {
					mode_index = 1;
				} else if(stmp.length() > 5 && stmp.substr(0, 4) == "Mode") {
					mode_index = save_mode_as(stmp.substr(5, stmp.length() - 5));
				}
			}
		}
		fclose(file);
		if(gstr_oldfile) {
			recursiveMakeDir(getLocalDir());
			move_file(gstr_oldfile, gstr_file);
			g_free(gstr_oldfile);
		}
	} else {
		first_time = true;
	}
	update_message_print_options();
	displayed_printops = printops;
	displayed_caf = complex_angle_form;
	initial_inhistory_index = inhistory.size() - 1;
	g_free(gstr_file);
	show_history = show_history && !show_keypad;
	show_convert = show_convert && !show_history && !show_keypad;
	set_saved_mode();

}

/*
	save preferences to ~/.config/qalculate/qalculate-gtk.cfg
	set mode to true to save current calculator mode
*/

void save_preferences(bool mode) {
	FILE *file = NULL;
	string homedir = getLocalDir();
	recursiveMakeDir(homedir);
	gchar *gstr2 = g_build_filename(homedir.c_str(), "qalculate-gtk.cfg", NULL);
	file = fopen(gstr2, "w+");
	if(file == NULL) {
		GtkWidget *edialog = gtk_message_dialog_new(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("Couldn't write preferences to\n%s"), gstr2);
		gtk_dialog_run(GTK_DIALOG(edialog));
		gtk_widget_destroy(edialog);
		g_free(gstr2);
		return;
	}
	g_free(gstr2);
	gint w, h;
	if(variables_builder) {
		gtk_window_get_size(GTK_WINDOW(gtk_builder_get_object(variables_builder, "variables_dialog")), &w, &h);
		variables_width = w;
		variables_height = h;
		variables_position = gtk_paned_get_position(GTK_PANED(gtk_builder_get_object(variables_builder, "variables_hpaned")));
	}
	if(units_builder) {
		gtk_window_get_size(GTK_WINDOW(gtk_builder_get_object(units_builder, "units_dialog")), &w, &h);
		units_width = w;
		units_height = h;
		units_position = gtk_paned_get_position(GTK_PANED(gtk_builder_get_object(units_builder, "units_hpaned")));
	}
	if(functions_builder) {
		gtk_window_get_size(GTK_WINDOW(gtk_builder_get_object(functions_builder, "functions_dialog")), &w, &h);
		functions_width = w;
		functions_height = h;
		functions_hposition = gtk_paned_get_position(GTK_PANED(gtk_builder_get_object(functions_builder, "functions_hpaned")));
		functions_vposition = gtk_paned_get_position(GTK_PANED(gtk_builder_get_object(functions_builder, "functions_vpaned")));
	}
	if(datasets_builder) {
		gtk_window_get_size(GTK_WINDOW(gtk_builder_get_object(datasets_builder, "datasets_dialog")), &w, &h);
		datasets_width = w;
		datasets_height = h;
		datasets_hposition = gtk_paned_get_position(GTK_PANED(gtk_builder_get_object(datasets_builder, "datasets_hpaned")));
		datasets_vposition1 = gtk_paned_get_position(GTK_PANED(gtk_builder_get_object(datasets_builder, "datasets_vpaned1")));
		datasets_vposition2 = gtk_paned_get_position(GTK_PANED(gtk_builder_get_object(datasets_builder, "datasets_vpaned2")));
	}
	fprintf(file, "\n[General]\n");
	fprintf(file, "version=%s\n", VERSION);
	fprintf(file, "allow_multiple_instances=%i\n", allow_multiple_instances);
	gtk_window_get_size(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), &w, &h);
	fprintf(file, "width=%i\n", w);
	//fprintf(file, "height=%i\n", h);
	if(variables_width > -1) fprintf(file, "variables_width=%i\n", variables_width);
	if(variables_height > -1) fprintf(file, "variables_height=%i\n", variables_height);
	if(variables_position > -1) fprintf(file, "variables_panel_position=%i\n", variables_position);
	if(units_width > -1) fprintf(file, "units_width=%i\n", units_width);
	if(units_height > -1) fprintf(file, "units_height=%i\n", units_height);
	if(units_position > -1) fprintf(file, "units_panel_position=%i\n", units_position);
	if(functions_width > -1) fprintf(file, "functions_width=%i\n", functions_width);
	if(functions_height > -1) fprintf(file, "functions_height=%i\n", functions_height);
	if(functions_hposition > -1) fprintf(file, "functions_hpanel_position=%i\n", functions_hposition);
	if(functions_vposition > -1) fprintf(file, "functions_vpanel_position=%i\n", functions_vposition);
	if(datasets_width > -1) fprintf(file, "datasets_width=%i\n", datasets_width);
	if(datasets_height > -1) fprintf(file, "datasets_height=%i\n", datasets_height);
	if(datasets_hposition > -1) fprintf(file, "datasets_hpanel_position=%i\n", datasets_hposition);
	if(datasets_vposition1 > -1) fprintf(file, "datasets_vpanel1_position=%i\n", datasets_vposition1);
	if(datasets_vposition2 > -1) fprintf(file, "datasets_vpanel2_position=%i\n", datasets_vposition2);
	fprintf(file, "keep_function_dialog_open=%i\n", keep_function_dialog_open);
	fprintf(file, "error_info_shown=%i\n", !first_error);
	fprintf(file, "save_mode_on_exit=%i\n", save_mode_on_exit);
	fprintf(file, "save_definitions_on_exit=%i\n", save_defs_on_exit);
	fprintf(file, "ignore_locale=%i\n", ignore_locale);
	fprintf(file, "load_global_definitions=%i\n", load_global_defs);
	//fprintf(file, "fetch_exchange_rates_at_startup=%i\n", fetch_exchange_rates_at_startup);
	fprintf(file, "auto_update_exchange_rates=%i\n", auto_update_exchange_rates);
	fprintf(file, "local_currency_conversion=%i\n", evalops.local_currency_conversion);
	fprintf(file, "use_binary_prefixes=%i\n", CALCULATOR->usesBinaryPrefixes());
#ifdef _WIN32
	fprintf(file, "last_version_check=%s\n", last_version_check_date.toISOString().c_str());
	if(!last_found_version.empty()) fprintf(file, "last_found_version=%s\n", last_found_version.c_str());
#endif
	fprintf(file, "show_keypad=%i\n", (rpn_mode && show_keypad && gtk_expander_get_expanded(GTK_EXPANDER(expander_stack))) || gtk_expander_get_expanded(GTK_EXPANDER(expander_keypad)));
	//h = gtk_widget_get_allocated_height(GTK_WIDGET(gtk_builder_get_object(main_builder, "buttons")));
	//fprintf(file, "keypad_height=%i\n", h > 10 ? h : keypad_height);
	fprintf(file, "show_history=%i\n", (rpn_mode && show_history && gtk_expander_get_expanded(GTK_EXPANDER(expander_stack))) || gtk_expander_get_expanded(GTK_EXPANDER(expander_history)));
	h = gtk_widget_get_allocated_height(tabs);
	fprintf(file, "history_height=%i\n", h > 10 ? h : history_height);
	fprintf(file, "show_stack=%i\n", rpn_mode ? gtk_expander_get_expanded(GTK_EXPANDER(expander_stack)) : show_stack);
	fprintf(file, "show_convert=%i\n", (rpn_mode && show_convert && gtk_expander_get_expanded(GTK_EXPANDER(expander_stack))) || gtk_expander_get_expanded(GTK_EXPANDER(expander_convert)));
	fprintf(file, "continuous_conversion=%i\n", gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "convert_button_continuous_conversion"))));
	fprintf(file, "set_missing_prefixes=%i\n", gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "convert_button_set_missing_prefixes"))));
	fprintf(file, "rpn_keys=%i\n", rpn_keys);
	fprintf(file, "display_expression_status=%i\n", display_expression_status);
	fprintf(file, "enable_completion=%i\n", enable_completion);
	fprintf(file, "enable_completion2=%i\n", enable_completion2);
	fprintf(file, "completion_min=%i\n", completion_min);
	fprintf(file, "completion_min2=%i\n", completion_min2);
	fprintf(file, "completion_delay=%i\n", completion_delay);
	fprintf(file, "use_unicode_signs=%i\n", printops.use_unicode_signs);
	fprintf(file, "lower_case_numbers=%i\n", printops.lower_case_numbers);
	fprintf(file, "lower_case_e=%i\n", printops.lower_case_e);
	fprintf(file, "e_notation=%i\n", use_e_notation);
	fprintf(file, "imaginary_j=%i\n", CALCULATOR->v_i->hasName("j") > 0);
	fprintf(file, "base_display=%i\n", printops.base_display);
	fprintf(file, "twos_complement=%i\n", printops.twos_complement);
	fprintf(file, "hexadecimal_twos_complement=%i\n", printops.hexadecimal_twos_complement);
	fprintf(file, "twos_complement_input=%i\n", twos_complement_in);
	fprintf(file, "hexadecimal_twos_complement_input=%i\n", hexadecimal_twos_complement_in);
	if(visible_keypad != 1 && programming_outbase != 0 && programming_inbase != 0) {
		fprintf(file, "programming_outbase=%i\n", programming_outbase);
		fprintf(file, "programming_inbase=%i\n", programming_inbase);
	}
	if(visible_keypad == 1 && versatile_exact) {
		fprintf(file, "general_exact=%i\n", versatile_exact);
	}
	if(default_bits >= 0) fprintf(file, "bit_width=%i\n", default_bits);
	if(default_signed >= 0) fprintf(file, "signed_integer=%i\n", default_signed);
	fprintf(file, "spell_out_logical_operators=%i\n", printops.spell_out_logical_operators);
	fprintf(file, "caret_as_xor=%i\n", caret_as_xor);
	fprintf(file, "digit_grouping=%i\n", printops.digit_grouping);
	fprintf(file, "copy_separator=%i\n", copy_separator);
	fprintf(file, "decimal_comma=%i\n", b_decimal_comma);
	fprintf(file, "dot_as_separator=%i\n", evalops.parse_options.dot_as_separator);
	fprintf(file, "comma_as_separator=%i\n", evalops.parse_options.comma_as_separator);
	fprintf(file, "use_custom_result_font=%i\n", use_custom_result_font);	
	fprintf(file, "use_custom_expression_font=%i\n", use_custom_expression_font);
	fprintf(file, "use_custom_status_font=%i\n", use_custom_status_font);
	if(use_custom_result_font || save_custom_result_font) fprintf(file, "custom_result_font=%s\n", custom_result_font.c_str());	
	if(use_custom_expression_font || save_custom_expression_font) fprintf(file, "custom_expression_font=%s\n", custom_expression_font.c_str());
	if(use_custom_status_font || save_custom_status_font) fprintf(file, "custom_status_font=%s\n", custom_status_font.c_str());
	if(status_error_color_set) fprintf(file, "status_error_color=%s\n", status_error_color.c_str());
	if(status_warning_color_set) fprintf(file, "status_warning_color=%s\n", status_warning_color.c_str());
	fprintf(file, "multiplication_sign=%i\n", printops.multiplication_sign);
	fprintf(file, "division_sign=%i\n", printops.division_sign);
	if(automatic_fraction) fprintf(file, "automatic_number_fraction_format=%i\n", automatic_fraction);
	for(size_t i = 0; i < expression_history.size(); i++) {
		fprintf(file, "expression_history=%s\n", expression_history[i].c_str()); 
	}	
	int lines = 300;
	bool end_after_result = false, end_before_expression = false;
	bool is_protected = false;
	bool doend = false;
	size_t hi = inhistory.size();
	while(!doend && hi > 0) {
		hi--;
		switch(inhistory_type[hi]) {
			case QALCULATE_HISTORY_EXPRESSION: {
				if(end_before_expression) {
					doend = true;
				} else {
					if(inhistory_protected[hi]) fprintf(file, "history_expression*=");
					else fprintf(file, "history_expression=");
					is_protected = inhistory_protected[hi];
				}
				break;
			}
			case QALCULATE_HISTORY_TRANSFORMATION: {
				fprintf(file, "history_transformation=");
				break;
			}
			case QALCULATE_HISTORY_RESULT: {
				fprintf(file, "history_result=");
				lines--;
				if(end_after_result) doend = true;
				break;
			}
			case QALCULATE_HISTORY_RESULT_APPROXIMATE: {
				fprintf(file, "history_result_approximate=");
				lines--;
				if(end_after_result) doend = true;
				break;
			}
			case QALCULATE_HISTORY_PARSE: {}
			case QALCULATE_HISTORY_PARSE_WITHEQUALS: {}
			case QALCULATE_HISTORY_PARSE_APPROXIMATE: {
				if(inhistory_type[hi] == QALCULATE_HISTORY_PARSE) fprintf(file, "history_parse=");
				else if(inhistory_type[hi] == QALCULATE_HISTORY_PARSE_WITHEQUALS) fprintf(file, "history_parse_withequals=");
				else fprintf(file, "history_parse_approximate=");
				lines--;
				if(lines < 0) {
					if(hi + 1 < inhistory_protected.size() && inhistory_protected[hi + 1]) {
						end_before_expression = true;
					} else if(hi + 2 < inhistory_type.size() && inhistory_type[hi + 2] == QALCULATE_HISTORY_BOOKMARK) {
						end_before_expression = true;
					}
					if(!end_before_expression) end_after_result = true;
				}
				break;
			}
			case QALCULATE_HISTORY_REGISTER_MOVED: {
				if(end_before_expression) {
					doend = true;
				} else {
					if(inhistory_protected[hi]) fprintf(file, "history_register_moved*=");
					else fprintf(file, "history_register_moved=");
					is_protected = inhistory_protected[hi];
				}
				break;
			}
			case QALCULATE_HISTORY_RPN_OPERATION: {
				if(end_before_expression) {
					doend = true;
				} else {
					if(inhistory_protected[hi]) fprintf(file, "history_rpn_operation*=");
					else fprintf(file, "history_rpn_operation=");
					is_protected = inhistory_protected[hi];
				}
				break;
			}
			case QALCULATE_HISTORY_WARNING: {
				fprintf(file, "history_warning=");
				lines--;
				break;
			}
			case QALCULATE_HISTORY_ERROR: {
				fprintf(file, "history_error=");
				lines--;
				break;
			}
			case QALCULATE_HISTORY_BOOKMARK: {
				if(end_before_expression && hi > 0 && (inhistory_type[hi - 1] == QALCULATE_HISTORY_EXPRESSION || inhistory_type[hi - 1] == QALCULATE_HISTORY_REGISTER_MOVED || inhistory_type[hi - 1] == QALCULATE_HISTORY_RPN_OPERATION)) {
					doend = true;
				} else {
					fprintf(file, "history_bookmark=");
					lines--;
					break;
				}
			}
			case QALCULATE_HISTORY_OLD: {
				fprintf(file, "history_old=");
				lines--;
				if(lines < 0) doend = true;
				break;
			}
		}
		if(doend && end_before_expression) break;
		size_t i3 = inhistory[hi].find('\n');
		if(i3 == string::npos) {
			if(!is_protected && inhistory[hi].length() > 50000) {
				int index = 50;
				while(index >= 0 && inhistory[hi][index] < 0) index--;
				fprintf(file, "%s …\n", inhistory[hi].substr(0, index + 1).c_str());
			} else {
				fprintf(file, "%s\n", inhistory[hi].c_str());
				if(inhistory[hi].length() > 300) {
					if(inhistory[hi].length() > 9000) lines -= 30;
					else lines -= inhistory[hi].length() / 300;
				}
			}
		} else {
			fprintf(file, "%s\n", inhistory[hi].substr(0, i3).c_str());
			i3++;
			size_t i2 = inhistory[hi].find('\n', i3);
			while(i2 != string::npos) {
				fprintf(file, "history_continued=%s\n", inhistory[hi].substr(i3, i2 - i3).c_str());
				lines--;
				i3 = i2 + 1;
				i2 = inhistory[hi].find('\n', i3);
			}
			fprintf(file, "history_continued=%s\n", inhistory[hi].substr(i3, inhistory[hi].length() - i3).c_str());
			lines--;
		}
	}
	while(hi >= 0 && inhistory.size() > 0) {
		if(inhistory_protected[hi] || (inhistory_type[hi] == QALCULATE_HISTORY_BOOKMARK && hi != 0 && inhistory_type[hi - 1] != QALCULATE_HISTORY_OLD)) {
			bool b_first = true;
			while(hi >= 0) {
				bool do_end = false;
				switch(inhistory_type[hi]) {
					case QALCULATE_HISTORY_EXPRESSION: {
						if(!b_first) {
							do_end = true;
						} else {
							if(inhistory_protected[hi]) fprintf(file, "history_expression*=");
							else fprintf(file, "history_expression=");
							b_first = false;
						}
						break;
					}
					case QALCULATE_HISTORY_TRANSFORMATION: {
						fprintf(file, "history_transformation=");
						break;
					}
					case QALCULATE_HISTORY_RESULT: {
						fprintf(file, "history_result=");
						break;
					}
					case QALCULATE_HISTORY_RESULT_APPROXIMATE: {
						fprintf(file, "history_result_approximate=");
						break;
					}
					case QALCULATE_HISTORY_PARSE: {
						fprintf(file, "history_parse=");
						break;
					}
					case QALCULATE_HISTORY_PARSE_WITHEQUALS: {
						fprintf(file, "history_parse_withequals=");
						break;
					}
					case QALCULATE_HISTORY_PARSE_APPROXIMATE: {
						fprintf(file, "history_parse_approximate=");
						break;
					}
					case QALCULATE_HISTORY_REGISTER_MOVED: {
						if(!b_first) {
							do_end = true;
						} else {
							if(inhistory_protected[hi]) fprintf(file, "history_register_moved*=");
							else fprintf(file, "history_register_moved=");
							b_first = false;
						}
						break;
					}
					case QALCULATE_HISTORY_RPN_OPERATION: {
						if(!b_first) {
							do_end = true;
						} else {
							if(inhistory_protected[hi]) fprintf(file, "history_rpn_operation*=");
							else fprintf(file, "history_rpn_operation=");
							b_first = false;
						}
						break;
					}
					case QALCULATE_HISTORY_WARNING: {
						fprintf(file, "history_warning=");
						break;
					}
					case QALCULATE_HISTORY_ERROR: {
						fprintf(file, "history_error=");
						break;
					}
					case QALCULATE_HISTORY_BOOKMARK: {
						if(!b_first) {
							do_end = true;
							break;
						}
						fprintf(file, "history_bookmark=");
						break;
					}
					case QALCULATE_HISTORY_OLD: {
						do_end = true;
						break;
					}
				}
				if(do_end) {
					hi++;
					break;
				}
				size_t i3 = inhistory[hi].find('\n');
				if(i3 == string::npos) {
					fprintf(file, "%s\n", inhistory[hi].c_str());
				} else {
					fprintf(file, "%s\n", inhistory[hi].substr(0, i3).c_str());
					i3++;
					size_t i2 = inhistory[hi].find('\n', i3);
					while(i2 != string::npos) {
						fprintf(file, "history_continued=%s\n", inhistory[hi].substr(i3, i2 - i3).c_str());
						i3 = i2 + 1;
						i2 = inhistory[hi].find('\n', i3);
					}
					fprintf(file, "history_continued=%s\n", inhistory[hi].substr(i3, inhistory[hi].length() - i3).c_str());
				}
				if(hi == 0) break;
				hi--;
			}
			if(hi > inhistory_type.size()) break;
		}
		if(hi == 0) break;
		hi--;
	}
	
	fprintf(file, "recent_functions="); 
	for(int i = (int) (recent_functions.size()) - 1; i >= 0; i--) {
		fprintf(file, "%s", recent_functions[i]->referenceName().c_str()); 
		if(i != 0) fprintf(file, ","); 
	}
	fprintf(file, "\n");
	fprintf(file, "recent_variables="); 
	for(int i = (int) (recent_variables.size()) - 1; i >= 0; i--) {
		fprintf(file, "%s", recent_variables[i]->referenceName().c_str()); 
		if(i != 0) fprintf(file, ","); 
	}
	fprintf(file, "\n"); 	
	fprintf(file, "recent_units="); 
	for(int i = (int) (recent_units.size()) - 1; i >= 0; i--) {
		fprintf(file, "%s", recent_units[i]->referenceName().c_str()); 
		if(i != 0) fprintf(file, ","); 
	}
	fprintf(file, "\n"); 
	if(latest_button_unit) fprintf(file, "latest_button_unit=%s\n", latest_button_unit->referenceName().c_str());
	if(latest_button_currency) fprintf(file, "latest_button_currency=%s\n", latest_button_currency->referenceName().c_str());
	if(mode) set_saved_mode();
	for(size_t i = 1; i < modes.size(); i++) {
		if(i == 1) {
			fprintf(file, "\n[Mode]\n");
		} else {
			fprintf(file, "\n[Mode %s]\n", modes[i].name.c_str());
		}
		fprintf(file, "min_deci=%i\n", modes[i].po.min_decimals);
		fprintf(file, "use_min_deci=%i\n", modes[i].po.use_min_decimals);
		fprintf(file, "max_deci=%i\n", modes[i].po.max_decimals);
		fprintf(file, "use_max_deci=%i\n", modes[i].po.use_max_decimals);
		fprintf(file, "precision=%i\n", modes[i].precision);
		fprintf(file, "interval_arithmetic=%i\n", modes[i].interval);
		fprintf(file, "interval_display=%i\n", modes[i].adaptive_interval_display ? 0 : modes[i].po.interval_display + 1);
		fprintf(file, "min_exp=%i\n", modes[i].po.min_exp);
		fprintf(file, "negative_exponents=%i\n", modes[i].po.negative_exponents);
		fprintf(file, "sort_minus_last=%i\n", modes[i].po.sort_options.minus_last);
		fprintf(file, "number_fraction_format=%i\n", modes[i].po.number_fraction_format);
		fprintf(file, "complex_number_form=%i\n", (modes[i].complex_angle_form && modes[i].eo.complex_number_form == COMPLEX_NUMBER_FORM_CIS) ? modes[i].eo.complex_number_form + 1 : modes[i].eo.complex_number_form);
		fprintf(file, "use_prefixes=%i\n", modes[i].po.use_unit_prefixes);
		fprintf(file, "use_prefixes_for_all_units=%i\n", modes[i].po.use_prefixes_for_all_units);
		fprintf(file, "use_prefixes_for_currencies=%i\n", modes[i].po.use_prefixes_for_currencies);
		fprintf(file, "abbreviate_names=%i\n", modes[i].po.abbreviate_names);
		fprintf(file, "all_prefixes_enabled=%i\n", modes[i].po.use_all_prefixes);
		fprintf(file, "denominator_prefix_enabled=%i\n", modes[i].po.use_denominator_prefix);
		fprintf(file, "place_units_separately=%i\n", modes[i].po.place_units_separately);
		fprintf(file, "auto_post_conversion=%i\n", modes[i].eo.auto_post_conversion);
		fprintf(file, "mixed_units_conversion=%i\n", modes[i].eo.mixed_units_conversion);
		fprintf(file, "number_base=%i\n", modes[i].po.base);
		if(!modes[i].custom_output_base.isZero()) fprintf(file, "custom_number_base=%s\n", modes[i].custom_output_base.print(CALCULATOR->save_printoptions).c_str());
		fprintf(file, "number_base_expression=%i\n", modes[i].eo.parse_options.base);
		if(!modes[i].custom_input_base.isZero()) fprintf(file, "custom_number_base_expression=%s\n", modes[i].custom_input_base.print(CALCULATOR->save_printoptions).c_str());
		fprintf(file, "read_precision=%i\n", modes[i].eo.parse_options.read_precision);
		fprintf(file, "assume_denominators_nonzero=%i\n", modes[i].eo.assume_denominators_nonzero);
		fprintf(file, "warn_about_denominators_assumed_nonzero=%i\n", modes[i].eo.warn_about_denominators_assumed_nonzero);
		fprintf(file, "structuring=%i\n", modes[i].eo.structuring);
		fprintf(file, "angle_unit=%i\n", modes[i].eo.parse_options.angle_unit);
		fprintf(file, "functions_enabled=%i\n", modes[i].eo.parse_options.functions_enabled);
		fprintf(file, "variables_enabled=%i\n", modes[i].eo.parse_options.variables_enabled);
		fprintf(file, "calculate_functions=%i\n", modes[i].eo.calculate_functions);
		fprintf(file, "calculate_variables=%i\n", modes[i].eo.calculate_variables);
		fprintf(file, "variable_units_enabled=%i\n", modes[i].variable_units_enabled);
		fprintf(file, "sync_units=%i\n", modes[i].eo.sync_units);
		fprintf(file, "unknownvariables_enabled=%i\n", modes[i].eo.parse_options.unknowns_enabled);
		fprintf(file, "units_enabled=%i\n", modes[i].eo.parse_options.units_enabled);
		fprintf(file, "allow_complex=%i\n", modes[i].eo.allow_complex);
		fprintf(file, "allow_infinite=%i\n", modes[i].eo.allow_infinite);
		fprintf(file, "indicate_infinite_series=%i\n", modes[i].po.indicate_infinite_series);
		fprintf(file, "show_ending_zeroes=%i\n", modes[i].po.show_ending_zeroes);
		fprintf(file, "round_halfway_to_even=%i\n", modes[i].po.round_halfway_to_even);
		fprintf(file, "approximation=%i\n", modes[i].eo.approximation);
		fprintf(file, "interval_calculation=%i\n", modes[i].eo.interval_calculation);
		fprintf(file, "calculate_as_you_type=%i\n", modes[i].autocalc);
		fprintf(file, "in_rpn_mode=%i\n", modes[i].rpn_mode);
		fprintf(file, "rpn_syntax=%i\n", modes[i].eo.parse_options.rpn);
		fprintf(file, "limit_implicit_multiplication=%i\n", modes[i].eo.parse_options.limit_implicit_multiplication);
		fprintf(file, "parsing_mode=%i\n", modes[i].eo.parse_options.parsing_mode);
		fprintf(file, "spacious=%i\n", modes[i].po.spacious);
		fprintf(file, "excessive_parenthesis=%i\n", modes[i].po.excessive_parenthesis);
		fprintf(file, "visible_keypad=%i\n", modes[i].keypad);
		fprintf(file, "short_multiplication=%i\n", modes[i].po.short_multiplication);
		fprintf(file, "default_assumption_type=%i\n", modes[i].at);
		fprintf(file, "default_assumption_sign=%i\n", modes[i].as);
	}
	fprintf(file, "\n[Plotting]\n");
	fprintf(file, "plot_legend_placement=%i\n", default_plot_legend_placement);
	fprintf(file, "plot_style=%i\n", default_plot_style);
	fprintf(file, "plot_smoothing=%i\n", default_plot_smoothing);
	fprintf(file, "plot_display_grid=%i\n", default_plot_display_grid);
	fprintf(file, "plot_full_border=%i\n", default_plot_full_border);
	fprintf(file, "plot_min=%s\n", default_plot_min.c_str());
	fprintf(file, "plot_max=%s\n", default_plot_max.c_str());
	fprintf(file, "plot_step=%s\n", default_plot_step.c_str());
	fprintf(file, "plot_sampling_rate=%i\n", default_plot_sampling_rate);
	fprintf(file, "plot_use_sampling_rate=%i\n", default_plot_use_sampling_rate);
	fprintf(file, "plot_variable=%s\n", default_plot_variable.c_str());
	fprintf(file, "plot_rows=%i\n", default_plot_rows);
	fprintf(file, "plot_type=%i\n", default_plot_type);
	fprintf(file, "plot_color=%i\n", default_plot_color);
	fprintf(file, "plot_linewidth=%i\n", default_plot_linewidth);

	fclose(file);
	
}

/*
	tree text sort function
*/
gint string_sort_func(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data) {
	gint cid = GPOINTER_TO_INT(user_data);
	gchar *gstr1, *gstr2;
	gint retval;
	gtk_tree_model_get(model, a, cid, &gstr1, -1);
	gtk_tree_model_get(model, b, cid, &gstr2, -1);
	retval = g_ascii_strcasecmp(gstr1, gstr2);
	g_free(gstr1);
	g_free(gstr2);
	return retval;
}

/*
	completion sort function
*/
gint completion_sort_func(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data) {
	gint i1 = 0, i2 = 0;
	gtk_tree_model_get(model, a, 4, &i1, -1);
	gtk_tree_model_get(model, b, 4, &i2, -1);
	if(i1 < i2) return -1;
	if(i1 > i2) return 1;
	gchar *gstr1, *gstr2;
	gint retval;
	gint cid = GPOINTER_TO_INT(user_data);
	gtk_tree_model_get(model, a, cid, &gstr1, -1);
	gtk_tree_model_get(model, b, cid, &gstr2, -1);
	retval = g_ascii_strcasecmp(gstr1, gstr2);
	g_free(gstr1);
	g_free(gstr2);
	return retval;
}

/*
	tree sort function for number strings
*/
gint int_string_sort_func(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data) {
	gint cid = GPOINTER_TO_INT(user_data);
	gchar *gstr1, *gstr2;
	bool b1 = false, b2 = false;
	gint retval;
	gtk_tree_model_get(model, a, cid, &gstr1, -1);
	gtk_tree_model_get(model, b, cid, &gstr2, -1);
	if(gstr1[0] == '-') {
		b1 = true;
	}
	if(gstr2[0] == '-') {
		b2 = true;
	}
	if(b1 == b2)
		retval = g_ascii_strcasecmp(gstr1, gstr2);
	else if(b1)
		retval = -1;
	else
		retval = 1;
	g_free(gstr1);
	g_free(gstr2);
	return retval;
}
/*
	display preferences dialog
*/
void edit_preferences() {
	GtkWidget *dialog = get_preferences_dialog();
	gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")));
	gtk_widget_show(dialog);
	//save_preferences();
}

gchar *font_name_to_css(const char *font_name) {
	gchar *gstr = NULL;
	PangoFontDescription *font_desc = pango_font_description_from_string(font_name);
	gint size = pango_font_description_get_size(font_desc) / PANGO_SCALE;
	switch(pango_font_description_get_style(font_desc)) {
		case PANGO_STYLE_NORMAL: {
			gstr = g_strdup_printf("* {font-family: %s; font-weight: %i; font-size: %ipt;}", pango_font_description_get_family(font_desc), pango_font_description_get_weight(font_desc), size);
			break;
		}
		case PANGO_STYLE_OBLIQUE: {
			gstr = g_strdup_printf("* {font-family: %s; font-weight: %i; font-size: %ipt; font-style: oblique;}", pango_font_description_get_family(font_desc), pango_font_description_get_weight(font_desc), size);
			break;
		}
		case PANGO_STYLE_ITALIC: {
			gstr = g_strdup_printf("* {font-family: %s; font-weight: %i; font-size: %ipt; font-style: italic;}", pango_font_description_get_family(font_desc), pango_font_description_get_weight(font_desc), size);
			break;
		}
	}
	pango_font_description_free(font_desc);
	return gstr;
}

#ifdef __cplusplus
extern "C" {
#endif

void on_button_bin_toggled(GtkToggleButton *w, gpointer);
void on_button_oct_toggled(GtkToggleButton *w, gpointer);
void on_button_dec_toggled(GtkToggleButton *w, gpointer);
void on_button_hex_toggled(GtkToggleButton *w, gpointer);

void on_button_twos_out_toggled(GtkToggleButton *w, gpointer) {
	if(printops.base == 16) printops.hexadecimal_twos_complement = gtk_toggle_button_get_active(w);
	else if(printops.base == 2) printops.twos_complement = gtk_toggle_button_get_active(w);
	result_format_updated();
	focus_keeping_selection();
}
void on_button_twos_in_toggled(GtkToggleButton *w, gpointer) {
	if(evalops.parse_options.base == 16) {
		hexadecimal_twos_complement_in = gtk_toggle_button_get_active(w);
		evalops.parse_options.hexadecimal_twos_complement = hexadecimal_twos_complement_in;
	} else if(evalops.parse_options.base == 2) {
		twos_complement_in = gtk_toggle_button_get_active(w);
		evalops.parse_options.twos_complement = twos_complement_in;
	}
	expression_format_updated(true);
	focus_keeping_selection();
}

void update_keypad_bases() {
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "button_bin"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_button_bin_toggled, NULL);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "button_oct"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_button_oct_toggled, NULL);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "button_dec"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_button_dec_toggled, NULL);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "button_hex"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_button_hex_toggled, NULL);
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "button_bin")), printops.base == 2 && evalops.parse_options.base == 2);
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "button_oct")), printops.base == 8 && evalops.parse_options.base == 8);
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "button_dec")), printops.base == 10 && evalops.parse_options.base == 10);
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "button_hex")), printops.base == 16 && evalops.parse_options.base == 16);
	gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "button_bin")), (printops.base == 2) != (evalops.parse_options.base == 2));
	gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "button_oct")), (printops.base == 8) != (evalops.parse_options.base == 8));
	gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "button_dec")), (printops.base == 10) != (evalops.parse_options.base == 10));
	gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "button_hex")), (printops.base == 16) != (evalops.parse_options.base == 16));
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "button_bin"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_button_bin_toggled, NULL);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "button_oct"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_button_oct_toggled, NULL);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "button_dec"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_button_dec_toggled, NULL);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "button_hex"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_button_hex_toggled, NULL);
	
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "button_twos_out"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_button_twos_out_toggled, NULL);
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "button_twos_out")), (printops.base == 16 && printops.hexadecimal_twos_complement) || (printops.base == 2 && printops.twos_complement));
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "button_twos_out"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_button_twos_out_toggled, NULL);
	
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "button_twos_in"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_button_twos_in_toggled, NULL);
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "button_twos_in")), (evalops.parse_options.base == 16 && hexadecimal_twos_complement_in) || (evalops.parse_options.base == 2 && twos_complement_in));
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "button_twos_in"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_button_twos_in_toggled, NULL);
	
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_a")), evalops.parse_options.base >= 13 || evalops.parse_options.base == 11);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_b")), evalops.parse_options.base >= 13);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_c")), evalops.parse_options.base >= 13);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_d")), evalops.parse_options.base >= 14);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_e")), evalops.parse_options.base >= 15);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_f")), evalops.parse_options.base >= 16);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_twos_out")), printops.base == 2 || printops.base == 16);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_twos_in")), evalops.parse_options.base == 2 || evalops.parse_options.base == 16);
	
	evalops.parse_options.hexadecimal_twos_complement = hexadecimal_twos_complement_in && evalops.parse_options.base == 16;
	evalops.parse_options.twos_complement = twos_complement_in && evalops.parse_options.base == 2;

}

void update_menu_base() {
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_base"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_base_changed, NULL);
		switch(printops.base) {
			case 2: {
				g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_binary"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_binary_activate, NULL);
				gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_binary")), TRUE);
				g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_binary"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_binary_activate, NULL);
				gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_base")), 0);
				break;
			}
			case 8: {
				g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_octal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_octal_activate, NULL);
				gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_octal")), TRUE);
				g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_octal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_octal_activate, NULL);
				gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_base")), 1);
				break;
			}
			case 10: {
				g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_decimal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_decimal_activate, NULL);
				gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_decimal")), TRUE);
				g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_decimal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_decimal_activate, NULL);
				gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_base")), 2);
				break;
			}
			case 16: {
				g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_hexadecimal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_hexadecimal_activate, NULL);
				gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_hexadecimal")), TRUE);
				g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_hexadecimal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_hexadecimal_activate, NULL);
				gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_base")), 4);
				break;
			}
		}
		g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_base"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_base_changed, NULL);
}

void base_button_alternative(int base) {
	to_base = 0;
	if(printops.base != base) {
		printops.base = base;
	} else if(evalops.parse_options.base != base) {
		printops.base = evalops.parse_options.base;
	} else {
		printops.base = 10;
	}
	update_menu_base();
	output_base_updated_from_menu();
	update_keypad_bases();
	result_format_updated();
	focus_keeping_selection();
}

void on_button_bin_toggled(GtkToggleButton *w, gpointer) {
	if(!gtk_toggle_button_get_active(w)) {
		update_keypad_bases();
		return;
	}
	if(printops.base != 2) {
		to_base = 0;
		printops.base = 2;
		update_menu_base();
		output_base_updated_from_menu();
		if(evalops.parse_options.base == 2) {update_keypad_bases(); result_format_updated();}
	}
	if(evalops.parse_options.base != 2) {
		evalops.parse_options.base = 2;
		input_base_updated_from_menu();
		update_keypad_bases();
		expression_format_updated(false);
	}
	focus_keeping_selection();
}
void on_button_oct_toggled(GtkToggleButton *w, gpointer) {
	if(!gtk_toggle_button_get_active(w)) {
		update_keypad_bases();
		return;
	}
	if(printops.base != 8) {
		to_base = 0;
		printops.base = 8;
		update_menu_base();
		output_base_updated_from_menu();
		if(evalops.parse_options.base == 8) {update_keypad_bases(); result_format_updated();}
	}
	if(evalops.parse_options.base != 8) {
		evalops.parse_options.base = 8;
		input_base_updated_from_menu();
		update_keypad_bases();
		expression_format_updated(false);
	}
	focus_keeping_selection();
}
void on_button_dec_toggled(GtkToggleButton *w, gpointer) {
	if(!gtk_toggle_button_get_active(w)) {
		update_keypad_bases();
		return;
	}
	if(printops.base != 10) {
		to_base = 0;
		printops.base = 10;
		update_menu_base();
		output_base_updated_from_menu();
		if(evalops.parse_options.base == 10) {update_keypad_bases(); result_format_updated();}
	}
	if(evalops.parse_options.base != 10) {
		evalops.parse_options.base = 10;
		input_base_updated_from_menu();
		update_keypad_bases();
		expression_format_updated(false);
	}
	focus_keeping_selection();
}
void on_button_hex_toggled(GtkToggleButton *w, gpointer) {
	if(!gtk_toggle_button_get_active(w)) {
		update_keypad_bases();
		return;
	}
	if(printops.base != 16) {
		to_base = 0;
		printops.base = 16;
		update_menu_base();
		output_base_updated_from_menu();
		if(evalops.parse_options.base == 16) {update_keypad_bases(); result_format_updated();}
	}
	if(evalops.parse_options.base != 16) {
		evalops.parse_options.base = 16;
		input_base_updated_from_menu();
		update_keypad_bases();
		expression_format_updated(false);
	}
	focus_keeping_selection();
}

void on_convert_treeview_category_row_expanded(GtkTreeView *tree_view, GtkTreeIter*, GtkTreePath *path, gpointer) {
	if(gtk_tree_path_get_depth(path) != 2) return;
	GtkTreeModel *model = gtk_tree_view_get_model(tree_view);
	GtkTreeIter iter2, iter3;
	gtk_tree_model_get_iter_first(model, &iter3);
	if(gtk_tree_model_iter_children(model, &iter2, &iter3)) {
		do {
			GtkTreePath *path2 = gtk_tree_model_get_path(model, &iter2);
			if(gtk_tree_path_compare(path, path2) != 0) gtk_tree_view_collapse_row(GTK_TREE_VIEW(tUnitSelectorCategories), path2);
			gtk_tree_path_free(path2);
		} while(gtk_tree_model_iter_next(model, &iter2));
	}
	gtk_tree_view_scroll_to_cell(tree_view, path, NULL, FALSE, 0, 0);
}

void on_message_bar_response(GtkInfoBar *w, gint response_id, gpointer) {
	if(response_id == GTK_RESPONSE_CLOSE) {
		gint w, h, dur;
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "message_label")), "");
		gtk_window_get_size(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), &w, &h);
		h -= gtk_widget_get_allocated_height(GTK_WIDGET(gtk_builder_get_object(main_builder, "message_bar")));
		dur = gtk_revealer_get_transition_duration(GTK_REVEALER(gtk_builder_get_object(main_builder, "message_revealer")));
		gtk_revealer_set_transition_duration(GTK_REVEALER(gtk_builder_get_object(main_builder, "message_revealer")), 0);
		gtk_revealer_set_reveal_child(GTK_REVEALER(gtk_builder_get_object(main_builder, "message_revealer")), FALSE);
		gtk_window_resize(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), w, h);
		gtk_revealer_set_transition_duration(GTK_REVEALER(gtk_builder_get_object(main_builder, "message_revealer")), dur);
	}
}

void set_current_object() {
	if(!current_object_has_changed) return;
	while(gtk_events_pending()) gtk_main_iteration();
	GtkTextIter ipos, istart, iend;
	gint pos, pos2;
	g_object_get(expressionbuffer, "cursor-position", &pos, NULL);
	pos2 = pos;
	if(pos == 0) {
		current_object_start = -1;
		current_object_end = -1;
		editing_to_expression = false;
		return;
	}
	gtk_text_buffer_get_start_iter(expressionbuffer, &istart);
	gtk_text_buffer_get_iter_at_offset(expressionbuffer, &ipos, pos);
	gchar *gstr = gtk_text_buffer_get_text(expressionbuffer, &istart, &ipos, FALSE);
	gchar *p = gstr + strlen(gstr);
	editing_to_expression = CALCULATOR->hasToExpression(gstr, true, evalops);
	bool non_number_before = false;
	while(pos2 > 0) {
		pos2--;
		p = g_utf8_prev_char(p);
		if(!CALCULATOR->utf8_pos_is_valid_in_name(p)) {
			pos2++;
			break;
		} else if(is_in(NUMBERS, p[0])) {
			if(non_number_before) {
				pos2++;
				break;
			}
		} else {
			non_number_before = true;
		}
	}
	g_free(gstr);
	if(pos2 > pos) {
		current_object_start = -1;
		current_object_end = -1;
	} else {
		gtk_text_buffer_get_iter_at_offset(expressionbuffer, &ipos, pos);
		gtk_text_buffer_get_end_iter(expressionbuffer, &iend);
		gstr = gtk_text_buffer_get_text(expressionbuffer, &ipos, &iend, FALSE);
		p = gstr;
		while(p[0] != '\0') {
			if(!CALCULATOR->utf8_pos_is_valid_in_name(p)) {
				break;
			}
			pos++;
			p = g_utf8_next_char(p);
		}
		if(pos2 >= gtk_text_buffer_get_char_count(expressionbuffer)) {
			current_object_start = -1;
			current_object_end = -1;
		} else {
			current_object_start = pos2;
			current_object_end = pos;
		}
		g_free(gstr);
	}
	current_object_has_changed = false;
}
void on_units_convert_view_row_activated(GtkTreeView*, GtkTreePath *path, GtkTreeViewColumn*, gpointer) {
	GtkTreeIter iter;
	gtk_tree_model_get_iter(units_convert_filter, &iter, path);
	Unit *u = NULL;
	gtk_tree_model_get(units_convert_filter, &iter, UNITS_POINTER_COLUMN, &u, -1);
	if(u) {
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(units_builder, "units_label_to_unit")), u->print(true, printops.abbreviate_names, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) gtk_builder_get_object(units_builder, "units_label_to_unit")).c_str());
		selected_to_unit = u;
		convert_in_wUnits();
	}
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(units_builder, "units_convert_to_button")), FALSE);
	gtk_widget_hide(units_convert_window);
}

void on_completion_match_selected(GtkTreeView*, GtkTreePath *path, GtkTreeViewColumn*, gpointer) {
	set_current_object();
	GtkTreeIter iter;
	gtk_tree_model_get_iter(completion_sort, &iter, path);
	string str;
	ExpressionItem *item = NULL;
	Prefix *prefix = NULL;
	const ExpressionName *ename = NULL, *ename_r = NULL, *ename_r2;
	gint i_type = 0;
	guint i_match = 0;
	gtk_tree_model_get(completion_sort, &iter, 2, &item, 4, &i_type, 7, &i_match, 8, &prefix, -1);
	if(i_type == 3) return;
	GtkTextIter object_start, object_end;
	gtk_text_buffer_get_iter_at_offset(expressionbuffer, &object_start, current_object_start);
	gtk_text_buffer_get_iter_at_offset(expressionbuffer, &object_end, current_object_end);
	gchar *gstr_pre = gtk_text_buffer_get_text(expressionbuffer, &object_start, &object_end, FALSE);
	gchar *gstr_next = gstr_pre;
	while(i_match > 0) {
		gtk_text_iter_forward_char(&object_start);
		gstr_next = g_utf8_next_char(gstr_next);
		if(strlen(gstr_pre) - strlen(gstr_next) >= i_match) break;
	}
	if(item) {
		ename_r = &item->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext);
		if(i_type > 2) {
			ename = ename_r;
		} else {
			if(printops.abbreviate_names && ename_r->abbreviation) ename_r2 = &item->preferredInputName(false, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext);
			else ename_r2 = NULL;
			if(ename_r2 == ename_r) ename_r2 = NULL;
			gchar *gstr2 = gtk_text_buffer_get_text(expressionbuffer, &object_start, &object_end, FALSE);
			for(size_t name_i = 0; name_i <= (ename_r2 ? item->countNames() + 1 : item->countNames()) && !ename; name_i++) {
				if(name_i == 0) {
					ename = ename_r;
				} else if(name_i == 1 && ename_r2) {
					ename = ename_r2;
				} else {
					ename = &item->getName(ename_r2 ? name_i - 1 : name_i);
					if(!ename || ename == ename_r || ename == ename_r2 || ename->plural || (ename->unicode && (!printops.use_unicode_signs || !can_display_unicode_string_function(ename->name.c_str(), (void*) expressiontext)))) {
						ename = NULL;
					}
				}
				if(ename) {
					if(strlen(gstr2) <= ename->name.length()) {
						for(size_t i = 0; i < strlen(gstr2); i++) {
							if(ename->name[i] != gstr2[i]) {
								ename = NULL;
								break;
							}
						}
					} else {
						ename = NULL;
					}
				}
			}
			for(size_t name_i = 1; name_i <= item->countNames() && !ename; name_i++) {
				ename = &item->getName(name_i);
				if(!ename || ename == ename_r || ename == ename_r2 || (!ename->plural && !(ename->unicode && (!printops.use_unicode_signs || !can_display_unicode_string_function(ename->name.c_str(), (void*) expressiontext))))) {
					ename = NULL;
				}
				if(ename) {
					if(strlen(gstr2) <= ename->name.length()) {
						for(size_t i = 0; i < strlen(gstr2); i++) {
							if(ename->name[i] != gstr2[i]) {
								ename = NULL;
								break;
							}
						}
					} else {
						ename = NULL;
					}
				}
			}
			if(ename && ename->completion_only) {
				ename = &item->preferredInputName(ename->abbreviation, printops.use_unicode_signs, ename->plural, false, &can_display_unicode_string_function, (void*) expressiontext);
			}
			if(!ename) ename = ename_r;
			g_free(gstr2);
		}
		if(!ename) return;
		str = ename->name;
	} else if(prefix) {
		gchar *gstr2 = gtk_text_buffer_get_text(expressionbuffer, &object_start, &object_end, FALSE);
		for(size_t name_i = (printops.abbreviate_names ? 1 : 0); name_i < 3; name_i++) {
			const string *pname;
			if(name_i == 0) pname = &prefix->longName(false);
			else if(name_i == 1) pname = &prefix->shortName(false);
			else pname = &prefix->unicodeName(false);
			if(!pname->empty() && strlen(gstr2) <= pname->length()) {
				bool b = true;
				for(size_t i = 0; i < strlen(gstr2); i++) {
					if(gstr2[i] != (*pname)[i]) {
						b = false;
						break;
					}
				}
				if(b) {
					if(name_i == 1 && printops.use_unicode_signs) str = prefix->unicodeName();
					else str = *pname;
					break;
				}
			}
		}
		if(str.empty()) str = prefix->longName();
		g_free(gstr2);
	} else {
		gchar *gstr;
		gtk_tree_model_get(completion_sort, &iter, 0, &gstr, -1);
		str = gstr;
		size_t i = str.find("<i>", 2);
		if(i != string::npos) {str = str.substr(0, i - 1);}
		g_free(gstr);
	}
	block_completion();
	add_to_undo = false;
	gtk_text_buffer_delete(expressionbuffer, &object_start, &object_end);
	add_to_undo = true;
	GtkTextIter ipos = object_start;
	if(item && item->type() == TYPE_FUNCTION) {
		GtkTextIter ipos2 = ipos;
		gtk_text_iter_forward_char(&ipos2);
		gchar *gstr = gtk_text_buffer_get_text(expressionbuffer, &ipos, &ipos2, FALSE);
		if(strlen(gstr) > 0 && gstr[0] == '(') {
			gtk_text_buffer_insert(expressionbuffer, &ipos, str.c_str(), -1);
			gtk_text_buffer_place_cursor(expressionbuffer, &ipos);
		} else {
			str += "()";
			gtk_text_buffer_insert(expressionbuffer, &ipos, str.c_str(), -1);
			gtk_text_iter_backward_char(&ipos);
			gtk_text_buffer_place_cursor(expressionbuffer, &ipos);
		}
		g_free(gstr);
	} else {
		gtk_text_buffer_insert(expressionbuffer, &ipos, str.c_str(), -1);
		gtk_text_buffer_place_cursor(expressionbuffer, &ipos);
	}
	gtk_widget_hide(completion_window);
	unblock_completion();
}

void on_menu_item_quit_activate(GtkMenuItem*, gpointer user_data) {
	on_gcalc_exit(NULL, NULL, user_data);
}

/*
	change preferences
*/
void on_colorbutton_status_error_color_color_set(GtkColorButton *w, gpointer) {
	GdkRGBA c;
	gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(w), &c);
	gchar color_str[8];
	g_snprintf(color_str, 8, "#%02x%02x%02x", (int) (c.red * 255), (int) (c.green * 255), (int) (c.blue * 255));
	status_error_color = color_str;
	status_error_color_set = true;
	display_parse_status();
}
void on_colorbutton_status_warning_color_color_set(GtkColorButton *w, gpointer) {
	GdkRGBA c;
	gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(w), &c);
	gchar color_str[8];
	g_snprintf(color_str, 8, "#%02x%02x%02x", (int) (c.red * 255), (int) (c.green * 255), (int) (c.blue * 255));
	status_warning_color = color_str;
	status_warning_color_set = true;
	display_parse_status();
}
void on_preferences_update_exchange_rates_spin_button_value_changed(GtkSpinButton *spin, gpointer) {
	auto_update_exchange_rates = gtk_spin_button_get_value_as_int(spin);
}
gint on_preferences_update_exchange_rates_spin_button_input(GtkSpinButton *spin, gdouble *new_value, gpointer) {
	const gchar *text = gtk_entry_get_text(GTK_ENTRY(spin));
	if(g_strcmp0(text, _("never")) == 0) *new_value = 0.0;
	else if(g_strcmp0(text, _("ask")) == 0) *new_value = -1.0;
	else *new_value = g_strtod(text, NULL);
	return TRUE;
}
gboolean on_preferences_update_exchange_rates_spin_button_output(GtkSpinButton *spin, gpointer) {
	int value = gtk_spin_button_get_value_as_int(spin);
	if(value > 0) {
		gchar *text;
		text = g_strdup_printf(_("%i days"), value);
		gtk_entry_set_text(GTK_ENTRY(spin), text);
		g_free(text);
	} else if(value == 0) {
		gtk_entry_set_text(GTK_ENTRY(spin), _("never"));
	} else {
		gtk_entry_set_text(GTK_ENTRY(spin), _("ask"));
	}
	return TRUE;
}
void on_preferences_checkbutton_local_currency_conversion_toggled(GtkToggleButton *w, gpointer) {
	evalops.local_currency_conversion = gtk_toggle_button_get_active(w);
	expression_calculation_updated();
}
void on_preferences_checkbutton_binary_prefixes_toggled(GtkToggleButton *w, gpointer) {
	CALCULATOR->useBinaryPrefixes(gtk_toggle_button_get_active(w) ? 1 : 0);
	result_format_updated();
}
void on_preferences_checkbutton_ignore_locale_toggled(GtkToggleButton *w, gpointer) {
	ignore_locale = gtk_toggle_button_get_active(w);
}
void on_preferences_checkbutton_copy_separator_toggled(GtkToggleButton *w, gpointer) {
	copy_separator = gtk_toggle_button_get_active(w);
}
void on_preferences_checkbutton_lower_case_numbers_toggled(GtkToggleButton *w, gpointer) {
	printops.lower_case_numbers = gtk_toggle_button_get_active(w);
	result_format_updated();
}
void on_preferences_checkbutton_lower_case_e_toggled(GtkToggleButton *w, gpointer) {
	printops.lower_case_e = gtk_toggle_button_get_active(w);
	result_format_updated();
}
void on_preferences_checkbutton_imaginary_j_toggled(GtkToggleButton *w, gpointer) {
	if(gtk_toggle_button_get_active(w) != (CALCULATOR->v_i->hasName("j") > 0)) {
		if(gtk_toggle_button_get_active(w)) {
			ExpressionName ename = CALCULATOR->v_i->getName(1);
			ename.name = "j";
			ename.reference = false;
			CALCULATOR->v_i->addName(ename, 1, true);
			CALCULATOR->v_i->setChanged(false);
		} else {
			CALCULATOR->v_i->clearNonReferenceNames();
			CALCULATOR->v_i->setChanged(false);
		}
		gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "label_i")), (string("<i>") + CALCULATOR->v_i->preferredDisplayName(true, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) gtk_builder_get_object(main_builder, "label_i")).name + "</i>").c_str());
		expression_format_updated();
	}
}
void on_preferences_checkbutton_e_notation_toggled(GtkToggleButton *w, gpointer) {
	use_e_notation = gtk_toggle_button_get_active(w);
	result_format_updated();
}
void on_preferences_checkbutton_alternative_base_prefixes_toggled(GtkToggleButton *w, gpointer) {
	if(gtk_toggle_button_get_active(w)) printops.base_display = BASE_DISPLAY_ALTERNATIVE;
	else printops.base_display = BASE_DISPLAY_NORMAL;
	result_format_updated();
}
void on_preferences_checkbutton_twos_complement_toggled(GtkToggleButton *w, gpointer) {
	printops.twos_complement = gtk_toggle_button_get_active(w);
	result_format_updated();
}
void on_preferences_checkbutton_hexadecimal_twos_complement_toggled(GtkToggleButton *w, gpointer) {
	printops.hexadecimal_twos_complement = gtk_toggle_button_get_active(w);
	result_format_updated();
}
void on_preferences_checkbutton_spell_out_logical_operators_toggled(GtkToggleButton *w, gpointer) {
	printops.spell_out_logical_operators = gtk_toggle_button_get_active(w);
	result_display_updated();
}
void on_preferences_checkbutton_caret_as_xor_toggled(GtkToggleButton *w, gpointer) {
	caret_as_xor = gtk_toggle_button_get_active(w);
	if(!caret_as_xor) gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_xor")), (string(_("Bitwise Exclusive OR")) + " (Ctrl+^)").c_str());
	else gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_xor")), _("Bitwise Exclusive OR"));
}
void on_preferences_checkbutton_unicode_signs_toggled(GtkToggleButton *w, gpointer) {
	printops.use_unicode_signs = gtk_toggle_button_get_active(w);
	set_operator_symbols();
	set_unicode_buttons();
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_radiobutton_asterisk")), printops.use_unicode_signs);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_radiobutton_ex")), printops.use_unicode_signs);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_radiobutton_dot")), printops.use_unicode_signs);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_radiobutton_altdot")), printops.use_unicode_signs);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_radiobutton_slash")), printops.use_unicode_signs);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_radiobutton_division_slash")), printops.use_unicode_signs);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_radiobutton_division")), printops.use_unicode_signs);
	result_display_updated();
}

void on_preferences_checkbutton_save_defs_toggled(GtkToggleButton *w, gpointer) {
	save_defs_on_exit = gtk_toggle_button_get_active(w);
}
void on_preferences_checkbutton_save_mode_toggled(GtkToggleButton *w, gpointer) {
	save_mode_on_exit = gtk_toggle_button_get_active(w);
}
void on_preferences_checkbutton_allow_multiple_instances_toggled(GtkToggleButton *w, gpointer) {
	allow_multiple_instances = gtk_toggle_button_get_active(w);
	save_preferences(false);
}
void on_preferences_checkbutton_rpn_keys_toggled(GtkToggleButton *w, gpointer) {
	rpn_keys = gtk_toggle_button_get_active(w);
}
void on_preferences_checkbutton_decimal_comma_toggled(GtkToggleButton *w, gpointer) {
	b_decimal_comma = gtk_toggle_button_get_active(w);
	if(b_decimal_comma) {
		CALCULATOR->useDecimalComma();
		gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_checkbutton_dot_as_separator")));
		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_checkbutton_comma_as_separator")));
	} else {
		CALCULATOR->useDecimalPoint(evalops.parse_options.comma_as_separator);
		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_checkbutton_dot_as_separator")));
		gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_checkbutton_comma_as_separator")));
	}
	expression_format_updated(false);
	result_display_updated();
	set_unicode_buttons();
}
void on_preferences_checkbutton_dot_as_separator_toggled(GtkToggleButton *w, gpointer) {
	evalops.parse_options.dot_as_separator = gtk_toggle_button_get_active(w);
	expression_format_updated(false);
}
void on_preferences_checkbutton_comma_as_separator_toggled(GtkToggleButton *w, gpointer) {
	evalops.parse_options.comma_as_separator = gtk_toggle_button_get_active(w);
	CALCULATOR->useDecimalPoint(evalops.parse_options.comma_as_separator);
	set_unicode_buttons();
	expression_format_updated(false);
}
void on_preferences_checkbutton_load_defs_toggled(GtkToggleButton *w, gpointer) {
	load_global_defs = gtk_toggle_button_get_active(w);
}
void on_preferences_checkbutton_fetch_exchange_rates_toggled(GtkToggleButton *w, gpointer) {
	fetch_exchange_rates_at_startup = gtk_toggle_button_get_active(w);
}
void on_preferences_checkbutton_display_expression_status_toggled(GtkToggleButton *w, gpointer) {
	if(gtk_toggle_button_get_active(w)) {
		display_expression_status = true;
		display_parse_status();
	} else {
		display_expression_status = false;
		set_status_text("");
	}
}
void on_preferences_checkbutton_custom_result_font_toggled(GtkToggleButton *w, gpointer) {
	use_custom_result_font = gtk_toggle_button_get_active(w);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_button_result_font")), use_custom_result_font);
	gint h_old, h_new;
	gtk_widget_get_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "scrolled_result")), NULL, &h_old);
	if(use_custom_result_font) {
		gchar *gstr = font_name_to_css(custom_result_font.c_str());
		gtk_css_provider_load_from_data(resultview_provider, gstr, -1, NULL);
		g_free(gstr);
	} else {
		gtk_css_provider_load_from_data(resultview_provider, "* {font-size: larger;}", -1, NULL);
	}
	result_font_modified();
	gtk_widget_get_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "scrolled_result")), NULL, &h_new);
	gint winh, winw;
	gtk_window_get_size(GTK_WINDOW(mainwindow), &winw, &winh);
	winh += (h_new - h_old);
	gtk_window_resize(GTK_WINDOW(mainwindow), winw, winh);
}
void on_preferences_checkbutton_custom_expression_font_toggled(GtkToggleButton *w, gpointer) {
	use_custom_expression_font = gtk_toggle_button_get_active(w);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_button_expression_font")), use_custom_expression_font);
	gint h_old, h_new;
	gtk_widget_get_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "expressionscrolled")), NULL, &h_old);
	if(use_custom_expression_font) {
		gchar *gstr = font_name_to_css(custom_expression_font.c_str());
		gtk_css_provider_load_from_data(expression_provider, gstr, -1, NULL);
		g_free(gstr);
	} else {
		gtk_css_provider_load_from_data(expression_provider, "", -1, NULL);
	}
	expression_font_modified();
	gtk_widget_get_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "expressionscrolled")), NULL, &h_new);
	gint winh, winw;
	gtk_window_get_size(GTK_WINDOW(mainwindow), &winw, &winh);
	winh += (h_new - h_old);
	gtk_window_resize(GTK_WINDOW(mainwindow), winw, winh);
}
void on_preferences_checkbutton_custom_status_font_toggled(GtkToggleButton *w, gpointer) {
	use_custom_status_font = gtk_toggle_button_get_active(w);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_button_status_font")), use_custom_status_font);
	gint h_old = gtk_widget_get_allocated_height(GTK_WIDGET(gtk_builder_get_object(main_builder, "statusbox")));
	if(use_custom_status_font) {
		gchar *gstr = font_name_to_css(custom_status_font.c_str());
		gtk_css_provider_load_from_data(statuslabel_l_provider, gstr, -1, NULL);
		gtk_css_provider_load_from_data(statuslabel_r_provider, gstr, -1, NULL);
		g_free(gstr);
	} else {
		gtk_css_provider_load_from_data(statuslabel_l_provider, "* {font-size: smaller;}", -1, NULL);
		gtk_css_provider_load_from_data(statuslabel_r_provider, "* {font-size: smaller;}", -1, NULL);
	}
	set_operator_symbols();
	while(gtk_events_pending()) gtk_main_iteration();
	gint h_new = gtk_widget_get_allocated_height(GTK_WIDGET(gtk_builder_get_object(main_builder, "statusbox")));
	gint winh, winw;
	gtk_window_get_size(GTK_WINDOW(mainwindow), &winw, &winh);
	winh += (h_new - h_old);
	gtk_window_resize(GTK_WINDOW(mainwindow), winw, winh);
}
void on_preferences_radiobutton_dot_toggled(GtkToggleButton *w, gpointer) {
	if(gtk_toggle_button_get_active(w)) {
		printops.multiplication_sign = MULTIPLICATION_SIGN_DOT;
		result_display_updated();
	}
}
void on_preferences_radiobutton_altdot_toggled(GtkToggleButton *w, gpointer) {
	if(gtk_toggle_button_get_active(w)) {
		printops.multiplication_sign = MULTIPLICATION_SIGN_ALTDOT;
		result_display_updated();
	}
}
void on_preferences_radiobutton_ex_toggled(GtkToggleButton *w, gpointer) {
	if(gtk_toggle_button_get_active(w)) {
		printops.multiplication_sign = MULTIPLICATION_SIGN_X;
		result_display_updated();
	}
}
void on_preferences_radiobutton_asterisk_toggled(GtkToggleButton *w, gpointer) {
	if(gtk_toggle_button_get_active(w)) {
		printops.multiplication_sign = MULTIPLICATION_SIGN_ASTERISK;
		result_display_updated();
	}
}
void on_preferences_radiobutton_slash_toggled(GtkToggleButton *w, gpointer) {
	if(gtk_toggle_button_get_active(w)) {
		printops.division_sign = DIVISION_SIGN_SLASH;
		result_display_updated();
	}
}
void on_preferences_radiobutton_division_slash_toggled(GtkToggleButton *w, gpointer) {
	if(gtk_toggle_button_get_active(w)) {
		printops.division_sign = DIVISION_SIGN_DIVISION_SLASH;
		result_display_updated();
	}
}
void on_preferences_radiobutton_division_toggled(GtkToggleButton *w, gpointer) {
	if(gtk_toggle_button_get_active(w)) {
		printops.division_sign = DIVISION_SIGN_DIVISION;
		result_display_updated();
	}
}
void on_preferences_radiobutton_digit_grouping_none_toggled(GtkToggleButton *w, gpointer) {
	if(gtk_toggle_button_get_active(w)) {
		printops.digit_grouping = DIGIT_GROUPING_NONE;
		result_format_updated();
	}
}
void on_preferences_radiobutton_digit_grouping_standard_toggled(GtkToggleButton *w, gpointer) {
	if(gtk_toggle_button_get_active(w)) {
		printops.digit_grouping = DIGIT_GROUPING_STANDARD;
		result_format_updated();
	}
}
void on_preferences_radiobutton_digit_grouping_locale_toggled(GtkToggleButton *w, gpointer) {
	if(gtk_toggle_button_get_active(w)) {
		printops.digit_grouping = DIGIT_GROUPING_LOCALE;
		result_format_updated();
	}
}

void on_preferences_checkbutton_enable_completion_toggled(GtkToggleButton *w, gpointer) {
	enable_completion = gtk_toggle_button_get_active(w);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_label_completion_min")), enable_completion);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_spin_completion_min")), enable_completion);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_checkbutton_enable_completion2")), enable_completion);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_label_completion_min2")), enable_completion && enable_completion2);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_spin_completion_min2")), enable_completion && enable_completion2);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_label_completion_delay")), enable_completion);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_spin_completion_delay")), enable_completion);
}
void on_preferences_checkbutton_enable_completion2_toggled(GtkToggleButton *w, gpointer) {
	enable_completion2 = gtk_toggle_button_get_active(w);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_label_completion_min2")), enable_completion && enable_completion2);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_spin_completion_min2")), enable_completion && enable_completion2);
}
void on_preferences_spin_completion_min_value_changed(GtkSpinButton *spin, gpointer) {
	completion_min = gtk_spin_button_get_value_as_int(spin);
	if(completion_min2 < completion_min) {
		completion_min2 = completion_min;
		gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(preferences_builder, "preferences_spin_completion_min2")), (double) completion_min2);
	}
}
void on_preferences_spin_completion_min2_value_changed(GtkSpinButton *spin, gpointer) {
	completion_min2 = gtk_spin_button_get_value_as_int(spin);
	if(completion_min2 < completion_min) {
		completion_min = completion_min2;
		gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(preferences_builder, "preferences_spin_completion_min")), (double) completion_min);
	}
}
void on_preferences_spin_completion_delay_value_changed(GtkSpinButton *spin, gpointer) {
	completion_delay = gtk_spin_button_get_value_as_int(spin);
}

void on_preferences_button_result_font_font_set(GtkFontButton *w, gpointer) {
	save_custom_result_font = true;
	custom_result_font = gtk_font_chooser_get_font(GTK_FONT_CHOOSER(w));
	gint h_old, h_new;
	gtk_widget_get_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "scrolled_result")), NULL, &h_old);
	gchar *gstr = font_name_to_css(custom_result_font.c_str());
	gtk_css_provider_load_from_data(resultview_provider, gstr, -1, NULL);
	g_free(gstr);
	result_font_modified();
	gtk_widget_get_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "scrolled_result")), NULL, &h_new);
	gint winh, winw;
	gtk_window_get_size(GTK_WINDOW(mainwindow), &winw, &winh);
	winh += (h_new - h_old);
	gtk_window_resize(GTK_WINDOW(mainwindow), winw, winh);
}
void on_preferences_button_expression_font_font_set(GtkFontButton *w, gpointer) {
	save_custom_expression_font = true;
	custom_expression_font = gtk_font_chooser_get_font(GTK_FONT_CHOOSER(w));
	gint h_old, h_new;
	gtk_widget_get_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "expressionscrolled")), NULL, &h_old);
	gchar *gstr = font_name_to_css(custom_expression_font.c_str());
	gtk_css_provider_load_from_data(expression_provider, gstr, -1, NULL);
	g_free(gstr);
	expression_font_modified();
	gtk_widget_get_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "expressionscrolled")), NULL, &h_new);
	gint winh, winw;
	gtk_window_get_size(GTK_WINDOW(mainwindow), &winw, &winh);
	winh += (h_new - h_old);
	gtk_window_resize(GTK_WINDOW(mainwindow), winw, winh);
}
void on_preferences_button_status_font_font_set(GtkFontButton *w, gpointer) {
	save_custom_status_font = true;
	custom_status_font = gtk_font_chooser_get_font(GTK_FONT_CHOOSER(w));
	gint h_old = gtk_widget_get_allocated_height(GTK_WIDGET(gtk_builder_get_object(main_builder, "statusbox")));
	gchar *gstr = font_name_to_css(custom_status_font.c_str());
	gtk_css_provider_load_from_data(statuslabel_l_provider, gstr, -1, NULL);
	gtk_css_provider_load_from_data(statuslabel_r_provider, gstr, -1, NULL);
	g_free(gstr);
	set_operator_symbols();
	while(gtk_events_pending()) gtk_main_iteration();
	gint h_new = gtk_widget_get_allocated_height(GTK_WIDGET(gtk_builder_get_object(main_builder, "statusbox")));
	gint winh, winw;
	gtk_window_get_size(GTK_WINDOW(mainwindow), &winw, &winh);
	winh += (h_new - h_old);
	gtk_window_resize(GTK_WINDOW(mainwindow), winw, winh);
}

/*
	hide unit manager when "Close" clicked
*/
void on_units_button_close_clicked(GtkButton*, gpointer) {
	gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_dialog")));
}

/*
	change conversion direction in unit manager on user request
*/
void on_units_toggle_button_from_toggled(GtkToggleButton *togglebutton, gpointer) {
	if(gtk_toggle_button_get_active(togglebutton)) {
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(units_builder, "units_toggle_button_to")), FALSE);
		convert_in_wUnits();
	}
}

/*
	convert button clicked
*/
void on_units_button_convert_clicked(GtkButton*, gpointer) {
	convert_in_wUnits();
}

/*
	change conversion direction in unit manager on user request
*/
void on_units_toggle_button_to_toggled(GtkToggleButton *togglebutton, gpointer) {
	if(gtk_toggle_button_get_active(togglebutton)) {
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(units_builder, "units_toggle_button_from")), FALSE);
		convert_in_wUnits();
	}
}

/*
	enter in conversion field
*/
void on_units_entry_from_val_activate(GtkEntry*, gpointer) {
	convert_in_wUnits(0);
}
void on_units_entry_to_val_activate(GtkEntry*, gpointer) {
	convert_in_wUnits(1);
}

bool contains_polynomial_division(MathStructure &m) {
	if(m.isPower() && m[0].containsType(STRUCT_ADDITION) && m[1].representsNegative()) return true;
	for(size_t i = 0; i < m.size(); i++) {
		if(contains_polynomial_division(m[i])) return true;
	}
	return false;
}
bool contains_imaginary_number(MathStructure &m) {
	if(m.isNumber() && m.number().hasImaginaryPart()) return true;
	for(size_t i = 0; i < m.size(); i++) {
		if(contains_imaginary_number(m[i])) return true;
	}
	return false;
}
bool contains_rational_number(MathStructure &m) {
	if(m.isNumber() && ((m.number().realPartIsRational() && !m.number().realPart().isInteger()) || (m.number().hasImaginaryPart() && m.number().imaginaryPart().isRational() && !m.number().imaginaryPart().isInteger()))) return true;
	for(size_t i = 0; i < m.size(); i++) {
		if(contains_rational_number(m[i])) return true;
	}
	return false;
}

void find_match_unformat(MathStructure &m) {
	for(size_t i = 0; i < m.size(); i++) {
		find_match_unformat(m[i]);
	}
	switch(m.type()) {
		case STRUCT_INVERSE: {
			m.setToChild(1, true);
			if(m.isPower() && m[1].isNumber()) m[1].number().negate();
			else m.raise(nr_minus_one);
			break;
		}
		case STRUCT_NEGATE: {
			m.setToChild(1);
			if(m.type() != STRUCT_MULTIPLICATION) m.transform(STRUCT_MULTIPLICATION);
			m.insertChild(m_minus_one, 1);
			break;
		}
		case STRUCT_DIVISION: {
			m.setType(STRUCT_MULTIPLICATION);
			if(m[1].isPower() && m[1][1].isNumber()) m[1][1].number().negate();
			else m[1].raise(nr_minus_one);
			find_match_unformat(m);
			break;
		}
		case STRUCT_MULTIPLICATION: {
			for(size_t i = 0; i < m.size();) {
				if(m[i].isMultiplication()) {
					for(size_t i2 = 0; i2 < m[i].size(); i2++) {
						m[i][i2].ref();
						m.insertChild_nocopy(&m[i][i2], i + i2 + 2);
					}
					m.delChild(i + 1);
				} else {
					i++;
				}
			}
			break;
		}
		default: {}
	}
}

Unit *find_exact_matching_unit2(const MathStructure &m) {
	switch(m.type()) {
		case STRUCT_POWER: {
			if(m.base()->isUnit() && (!m.base()->prefix() || m.base()->prefix()->value().isOne()) && m.base()->unit()->subtype() != SUBTYPE_COMPOSITE_UNIT && m.exponent()->isNumber() && m.exponent()->number().isInteger() && m.exponent()->number() < 10 && m.exponent()->number() > -10) {
				Unit *u_base = m.base()->unit();
				int exp = m.exponent()->number().intValue();
				for(size_t i = 0; i < CALCULATOR->units.size(); i++) {
					
					if(CALCULATOR->units[i]->subtype() == SUBTYPE_ALIAS_UNIT) {
						AliasUnit *u = (AliasUnit*) CALCULATOR->units[i];
						if(u->firstBaseUnit() == u_base && u->firstBaseExponent() == exp) return u;
					}
				}
			}
			break;
		}
		case STRUCT_UNIT: {
			if(m.prefix() && !m.prefix()->value().isOne()) {
				for(size_t i = 0; i < CALCULATOR->units.size(); i++) {
					if(CALCULATOR->units[i]->subtype() == SUBTYPE_COMPOSITE_UNIT) {
						CompositeUnit *u = (CompositeUnit*) CALCULATOR->units[i];
						int exp = 0;
						Prefix *p = NULL;
						if(u->countUnits() == 1 && u->get(1, &exp, &p) == m.unit() && exp == 1 && p == m.prefix()) return u;
					}
				}
			}
			return m.unit();
		}
		case STRUCT_MULTIPLICATION: {
			if(m.size() == 2 && !m[0].containsType(STRUCT_UNIT, false)) {
				return find_exact_matching_unit2(m[1]);
			}
			CompositeUnit *cu = new CompositeUnit("", "temporary_find_matching_unit");
			for(size_t i = 1; i <= m.countChildren(); i++) {
				if(m.getChild(i)->isUnit()) {
					cu->add(m.getChild(i)->unit(), 1, m.getChild(i)->prefix() && !m.getChild(i)->prefix()->value().isOne() ? m.getChild(i)->prefix() : NULL);
				} else if(m.getChild(i)->isPower() && m.getChild(i)->base()->isUnit() && m.getChild(i)->exponent()->isNumber() && m.getChild(i)->exponent()->number().isInteger() && m.getChild(i)->exponent()->number() < 10 && m.getChild(i)->exponent()->number() > -10) {
					cu->add(m.getChild(i)->base()->unit(), m.getChild(i)->exponent()->number().intValue(), m.getChild(i)->base()->prefix() && !m.getChild(i)->base()->prefix()->value().isOne() ? m.getChild(i)->base()->prefix() : NULL);
				} else if(m.getChild(i)->containsType(STRUCT_UNIT, false)) {
					delete cu;
					return NULL;
				}
			}
			if(cu->countUnits() == 1) {
				int exp = 1;
				Prefix *p = NULL;
				Unit *u = cu->get(1, &exp, &p);
				MathStructure m2(u, p);
				if(exp != 1) m2.raise(exp);
				return find_exact_matching_unit2(m2);
			}
			for(size_t i = 0; i < CALCULATOR->units.size(); i++) {
				Unit *u = CALCULATOR->units[i];
				if(u->subtype() == SUBTYPE_COMPOSITE_UNIT) {
					if(((CompositeUnit*) u)->countUnits() == cu->countUnits()) {
						bool b = true;
						for(size_t i2 = 1; i2 <= cu->countUnits(); i2++) {
							int exp1 = 1, exp2 = 1;
							Prefix *p1 = NULL, *p2 = NULL;
							Unit *ui1 = cu->get(i2, &exp1, &p1);
							b = false;
							for(size_t i3 = 1; i3 <= cu->countUnits(); i3++) {
								Unit *ui2 = ((CompositeUnit*) u)->get(i3, &exp2, &p2);
								if(ui1 == ui2) {
									b = (exp1 == exp2 && p1 == p2);
									break;
								}
							}
							if(!b) break;
						}
						if(b) {
							delete cu;
							return u;
						}
					}
				}
			}
			delete cu;
			break;
		}
		default: {}
	}
	return NULL;
}


Unit *find_exact_matching_unit(const MathStructure &m) {
	MathStructure m2(m);
	find_match_unformat(m2);
	return find_exact_matching_unit2(m2);
}

bool contains_convertable_unit(MathStructure &m) {
	if(m.type() == STRUCT_UNIT) return true;
	for(size_t i = 0; i < m.size(); i++) {
		if(!m.isFunction() || !m.function()->getArgumentDefinition(i + 1) || m.function()->getArgumentDefinition(i + 1)->type() != ARGUMENT_TYPE_ANGLE) {
			if(contains_convertable_unit(m[i])) return true;
		}
	}
	return false;
}

void update_resultview_popup() {
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_octal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_octal_activate, NULL);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_decimal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_decimal_activate, NULL);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_duodecimal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_duodecimal_activate, NULL);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_hexadecimal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_hexadecimal_activate, NULL);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_binary"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_binary_activate, NULL);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_roman"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_roman_activate, NULL);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_sexagesimal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_sexagesimal_activate, NULL);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_time_format"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_time_format_activate, NULL);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_custom_base"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_custom_base_activate, NULL);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_display_normal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_display_normal_activate, NULL);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_display_engineering"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_display_engineering_activate, NULL);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_display_scientific"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_display_scientific_activate, NULL);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_display_purely_scientific"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_display_purely_scientific_activate, NULL);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_display_non_scientific"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_display_non_scientific_activate, NULL);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_display_no_prefixes"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_display_no_prefixes_activate, NULL);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_display_prefixes_for_selected_units"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_display_prefixes_for_selected_units_activate, NULL);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_display_prefixes_for_currencies"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_display_prefixes_for_currencies_activate, NULL);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_display_prefixes_for_all_units"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_display_prefixes_for_all_units_activate, NULL);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_abbreviate_names"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_abbreviate_names_activate, NULL);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_all_prefixes"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_denominator_prefixes_activate, NULL);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_denominator_prefixes"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_all_prefixes_activate, NULL);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_fraction_decimal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_fraction_decimal_activate, NULL);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_fraction_decimal_exact"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_fraction_decimal_exact_activate, NULL);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_fraction_combined"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_fraction_combined_activate, NULL);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_fraction_fraction"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_fraction_fraction_activate, NULL);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_assume_nonzero_denominators"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_assume_nonzero_denominators_activate, NULL);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_complex_rectangular"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_complex_rectangular_activate, NULL);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_complex_exponential"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_complex_exponential_activate, NULL);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_complex_polar"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_complex_polar_activate, NULL);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_complex_angle"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_complex_angle_activate, NULL);

	bool b_unit = displayed_mstruct && contains_convertable_unit(*displayed_mstruct);
	bool b_date = displayed_mstruct && displayed_mstruct->isDateTime();
	bool b_complex = displayed_mstruct && mstruct && contains_imaginary_number(*mstruct);
	bool b_rational = displayed_mstruct && mstruct && contains_rational_number(*mstruct);
	bool b_object = displayed_mstruct && (displayed_mstruct->containsType(STRUCT_UNIT) || displayed_mstruct->containsType(STRUCT_FUNCTION) || displayed_mstruct->containsType(STRUCT_VARIABLE));
	
	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_abbreviate_names")), b_object);
	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "separator_popup_abbreviate_names")), b_object);
	
	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "separator_popup_display_prefixes")), b_unit);
	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_display_no_prefixes")), b_unit);
	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_display_prefixes_for_selected_units")), b_unit);
	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_display_prefixes_for_currencies")), b_unit);
	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_display_prefixes_for_all_units")), b_unit);
	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_all_prefixes")), b_unit);
	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_denominator_prefixes")), b_unit);
	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "separator_popup_unit_settings")), b_unit);
	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_convert_to_unit")), FALSE);
	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_convert_to_base_units")), b_unit);
	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_convert_to_best_unit")), b_unit);
	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_set_optimal_prefix")), b_unit);
	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_convert_to")), FALSE);
	if(b_unit) {
		GtkWidget *sub = GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_convert_to"));
		GtkWidget *item;
		if(expression_has_changed && !rpn_mode && !auto_calculate) execute_expression(true);
		GList *list = gtk_container_get_children(GTK_CONTAINER(sub));
		for(GList *l = list; l != NULL; l = l->next) {
			gtk_widget_destroy(GTK_WIDGET(l->data));
		}
		g_list_free(list);
		Unit *u_result = NULL;
		if(displayed_mstruct) u_result = find_exact_matching_unit(*displayed_mstruct);
		bool b_exact = (u_result != NULL);
		if(!u_result) u_result = CALCULATOR->findMatchingUnit(*mstruct);
		vector<Unit*> to_us;
		if(u_result && u_result->isCurrency()) {
			Unit *u_local_currency = CALCULATOR->getLocalCurrency();
			if(latest_button_currency && latest_button_currency != u_result && latest_button_currency != u_local_currency) to_us.push_back(latest_button_currency);
			for(size_t i = 0; i < CALCULATOR->units.size() + 2; i++) {
				Unit * u;
				if(i == 0) u = u_local_currency;
				else if(i == 1) u = latest_button_currency;
				else u = CALCULATOR->units[i - 2];
				if(u && (!b_exact || u != u_result) && u->isActive() && u->isCurrency() && (i == 0 || (u != u_local_currency && u != latest_button_currency && !u->isHidden()))) {
					bool b = false;
					for(size_t i2 = 0; i2 < to_us.size(); i2++) {
						if(string_is_less(u->title(true), to_us[i2]->title(true))) {
							to_us.insert(to_us.begin() + i2, u);
							b = true;
							break;
						}
					}
					if(!b) to_us.push_back(u);
				}
			}
			for(size_t i = 0; i < to_us.size(); i++) {
				MENU_ITEM_WITH_POINTER_AND_FLAG(to_us[i]->title(true).c_str(), convert_to_unit, to_us[i])
			}
			vector<Unit*> to_us2;
			for(size_t i = 0; i < CALCULATOR->units.size(); i++) {
				if(CALCULATOR->units[i]->isCurrency()) {
					Unit *u = CALCULATOR->units[i];
					if(u->isActive() && (!b_exact || u != u_result) && u->isHidden() && u != u_local_currency && u != latest_button_currency) {
						bool b = false;
						for(int i2 = to_us2.size() - 1; i2 >= 0; i2--) {
							if(u->title(true) > to_us2[(size_t) i2]->title(true)) {
								if((size_t) i2 == to_us2.size() - 1) to_us2.push_back(u);
								else to_us2.insert(to_us2.begin() + (size_t) i2 + 1, u);
								b = true;
								break;
							}
						}
						if(!b) to_us2.insert(to_us2.begin(), u);
					}
				}
			}
			if(to_us2.size() > 0) {
				SUBMENU_ITEM(_("more"), sub);
				for(size_t i = 0; i < to_us2.size(); i++) {
					// Show further items in a submenu
					MENU_ITEM_WITH_POINTER_AND_FLAG(to_us2[i]->title(true).c_str(), convert_to_unit, to_us2[i])
				}
			}
			gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_convert_to")), TRUE);
		} else if(u_result && !u_result->category().empty()) {
			string s_cat = u_result->category();
			for(size_t i = 0; i < CALCULATOR->units.size(); i++) {
				if(CALCULATOR->units[i]->category() == s_cat) {
					Unit *u = CALCULATOR->units[i];
					if((!b_exact || u != u_result) && u->isActive() && !u->isHidden()) {
						bool b = false;
						for(size_t i2 = 0; i2 < to_us.size(); i2++) {
							if(string_is_less(u->title(true), to_us[i2]->title(true))) {
								to_us.insert(to_us.begin() + i2, u);
								b = true;
								break;
							}
						}
						if(!b) to_us.push_back(u);
					}
				}
			}
			for(size_t i = 0; i < to_us.size(); i++) {
				MENU_ITEM_WITH_POINTER(to_us[i]->title(true).c_str(), convert_to_unit_noprefix, to_us[i])
			}
			gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_convert_to")), TRUE);
		}
	}

	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "separator_popup_units")), b_unit);
	
	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_octal")), !b_unit && !b_date && !b_complex);
	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_decimal")), !b_unit && !b_date && !b_complex);
	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_duodecimal")), !b_unit && !b_date && !b_complex);
	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_hexadecimal")), !b_unit && !b_date && !b_complex);
	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_binary")), !b_unit && !b_date && !b_complex);
	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_roman")), FALSE);
	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_sexagesimal")), FALSE);
	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_time_format")), FALSE);
	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_custom_base")), !b_unit && !b_date && !b_complex);
	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "separator_popup_base")), !b_unit && !b_date && !b_complex);
	
	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_complex_rectangular")), b_complex);
	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_complex_exponential")), b_complex);
	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_complex_polar")), b_complex);
	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_complex_angle")), b_complex);
	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "separator_popup_complex")), b_complex);
	
	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_display_normal")), !b_unit && !b_date);
	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_display_engineering")), !b_unit && !b_date);
	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_display_scientific")), !b_unit && !b_date);
	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_display_purely_scientific")), FALSE);
	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_display_non_scientific")), FALSE);
	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "separator_popup_display")), !b_unit && !b_date);
	
	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "separator_popup_fraction")), b_rational);
	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_fraction_decimal")), b_rational);
	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_fraction_decimal_exact")), b_rational);
	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_fraction_combined")), b_rational);
	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_fraction_fraction")), b_rational);

	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_calendarconversion")), b_date);
	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_to_utc")), b_date);
	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "separator_popup_display_date")), b_date);
	
	if(mstruct && mstruct->containsUnknowns()) {
		gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_set_unknowns")));
		gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(main_builder, "separator_popup_factorize")));
	} else {
		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_set_unknowns")));
		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "separator_popup_factorize")));
	}
	if(mstruct && mstruct->containsType(STRUCT_ADDITION)) {
		if(evalops.structuring == STRUCTURING_FACTORIZE) {
			gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_factorize")));
		} else {
			gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_factorize")));
		}
		if(evalops.structuring == STRUCTURING_SIMPLIFY) {
			gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_simplify")));
		} else {
			gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_simplify")));
		}
		if(contains_polynomial_division(*mstruct)) gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_expand_partial_fractions")));
		else gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_expand_partial_fractions")));
		gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(main_builder, "separator_popup_factorize")));
	} else {
		if(mstruct && mstruct->isNumber() && mstruct->number().isInteger() && !mstruct->number().isZero()) {
			gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_factorize")));
			gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(main_builder, "separator_popup_factorize")));
		} else {
			gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_factorize")));
		}
		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_simplify")));
		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_expand_partial_fractions")));
	}
	if(mstruct && mstruct->containsDivision()) {
		gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_assume_nonzero_denominators")));
		gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(main_builder, "separator_popup_nonzero")));
	} else {
		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_assume_nonzero_denominators")));
		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "separator_popup_nonzero")));
	}
	if(mstruct->isVector() && (mstruct->size() != 1 || !(*mstruct)[0].isVector() || (*mstruct)[0].size() > 0)) {
		if(mstruct->isMatrix()) {
			gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_view_matrix")));
			gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_view_vector")));
		} else {
			gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_view_matrix")));
			gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_view_vector")));
		}
		gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(main_builder, "separator_popup_view_matrixvector")));
	} else {
		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_view_matrix")));
		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_view_vector")));
		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "separator_popup_view_matrixvector")));
	}
	switch (printops.base) {
		case BASE_OCTAL: {
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_octal")), TRUE);
			break;
		}
		case BASE_DECIMAL: {
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_decimal")), TRUE);
			break;
		}
		case 12: {
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_duodecimal")), TRUE);
			break;
		}
		case BASE_HEXADECIMAL: {
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_hexadecimal")), TRUE);
			break;
		}
		case BASE_BINARY: {
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_binary")), TRUE);
			break;
		}
		case BASE_ROMAN_NUMERALS: {
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_roman")), TRUE);
			break;
		}
		/*case BASE_SEXAGESIMAL: {
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_sexagesimal")), TRUE);
			break;
		}
		case BASE_TIME: {
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_time_format")), TRUE);
			break;
		}*/
		default: {
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_custom_base")), TRUE);
			break;
		}
	}
	switch(printops.min_exp) {
		case EXP_PRECISION: {
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_display_normal")), TRUE);
			break;
		}
		case EXP_BASE_3: {
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_display_engineering")), TRUE);
			break;
		}
		case EXP_SCIENTIFIC: {
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_display_scientific")), TRUE);
			break;
		}
		case EXP_PURE: {
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_display_purely_scientific")), TRUE);
			break;
		}
		case EXP_NONE: {
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_display_non_scientific")), TRUE);
			break;
		}
	}
	if(!printops.use_unit_prefixes) {
		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_display_no_prefixes")), TRUE);
	} else if(printops.use_prefixes_for_all_units) {
		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_display_prefixes_for_all_units")), TRUE);
	} else if(printops.use_prefixes_for_currencies) {
		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_display_prefixes_for_currencies")), TRUE);
	} else {
		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_display_prefixes_for_selected_units")), TRUE);
	}
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_abbreviate_names")), printops.abbreviate_names);
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_all_prefixes")), printops.use_all_prefixes);
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_denominator_prefixes")), printops.use_denominator_prefix);
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_assume_nonzero_denominators")), evalops.assume_denominators_nonzero);
	switch(printops.number_fraction_format) {
		case FRACTION_DECIMAL: {
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_fraction_decimal")), TRUE);
			break;
		}
		case FRACTION_DECIMAL_EXACT: {
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_fraction_decimal_exact")), TRUE);
			break;
		}
		case FRACTION_COMBINED: {
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_fraction_combined")), TRUE);
			break;		
		}
		case FRACTION_FRACTIONAL: {
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_fraction_fraction")), TRUE);
			break;		
		}
	}
	switch(evalops.complex_number_form) {
		case COMPLEX_NUMBER_FORM_RECTANGULAR: {
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_complex_rectangular")), TRUE);
			break;
		}
		case COMPLEX_NUMBER_FORM_EXPONENTIAL: {
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_complex_exponential")), TRUE);
			break;
		}
		case COMPLEX_NUMBER_FORM_POLAR: {
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_complex_polar")), TRUE);
			break;
		}
		case COMPLEX_NUMBER_FORM_CIS: {
			if(complex_angle_form) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_complex_angle")), TRUE);
			else gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_complex_polar")), TRUE);
			break;
		}
	}
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_octal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_octal_activate, NULL);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_decimal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_decimal_activate, NULL);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_duodecimal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_duodecimal_activate, NULL);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_hexadecimal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_hexadecimal_activate, NULL);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_binary"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_binary_activate, NULL);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_roman"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_roman_activate, NULL);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_sexagesimal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_sexagesimal_activate, NULL);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_time_format"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_time_format_activate, NULL);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_custom_base"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_custom_base_activate, NULL);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_display_normal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_display_normal_activate, NULL);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_display_engineering"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_display_engineering_activate, NULL);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_display_scientific"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_display_scientific_activate, NULL);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_display_purely_scientific"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_display_purely_scientific_activate, NULL);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_display_non_scientific"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_display_non_scientific_activate, NULL);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_display_no_prefixes"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_display_no_prefixes_activate, NULL);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_display_prefixes_for_selected_units"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_display_prefixes_for_selected_units_activate, NULL);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_display_prefixes_for_all_units"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_display_prefixes_for_all_units_activate, NULL);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_display_prefixes_for_currencies"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_display_prefixes_for_currencies_activate, NULL);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_abbreviate_names"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_abbreviate_names_activate, NULL);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_abbreviate_names"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_all_prefixes_activate, NULL);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_all_prefixes"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_denominator_prefixes_activate, NULL);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_fraction_decimal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_fraction_decimal_activate, NULL);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_fraction_decimal_exact"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_fraction_decimal_exact_activate, NULL);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_fraction_combined"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_fraction_combined_activate, NULL);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_fraction_fraction"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_fraction_fraction_activate, NULL);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_assume_nonzero_denominators"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_assume_nonzero_denominators_activate, NULL);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_complex_rectangular"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_complex_rectangular_activate, NULL);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_complex_exponential"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_complex_exponential_activate, NULL);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_complex_polar"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_complex_polar_activate, NULL);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_complex_angle"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_complex_angle_activate, NULL);
}
void on_expression_button_clicked(GtkButton*, gpointer) {
	GtkWidget *w = gtk_stack_get_visible_child(GTK_STACK(gtk_builder_get_object(main_builder, "expression_button_stack")));
	if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "expression_button_equals"))) {
		execute_expression();
	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "expression_button_clear"))) {
		clear_expression_text();
		gtk_widget_grab_focus(expressiontext);
	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "message_tooltip_icon"))) {
		gtk_widget_trigger_tooltip_query(w);
	} else {
		if(b_busy_command) on_abort_command(NULL, 0, NULL);
		else if(b_busy_expression) on_abort_calculation(NULL, 0, NULL);
		else if(b_busy_result) on_abort_display(NULL, 0, NULL);
	}
}
gboolean on_expressiontext_button_press_event(GtkWidget*, GdkEventButton *event, gpointer) {
	if(gdk_event_triggers_context_menu((GdkEvent*) event) && event->type == GDK_BUTTON_PRESS) {
		if(b_busy) return TRUE;
	}
	return FALSE;
}
gboolean on_units_dialog_button_press_event(GtkWidget*, GdkEventButton *event, gpointer) {
	gtk_widget_hide(units_convert_window);
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(units_builder, "units_convert_to_button")), FALSE);
	return FALSE;
}
gboolean on_units_dialog_delete_event() {
	gtk_widget_hide(units_convert_window);
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(units_builder, "units_convert_to_button")), FALSE);
	return FALSE;
}
gboolean on_main_window_button_press_event(GtkWidget*, GdkEventButton *event, gpointer) {
	gtk_widget_hide(completion_window);
	return FALSE;
}
gboolean on_resultview_button_press_event(GtkWidget*, GdkEventButton *event, gpointer) {
	if(gdk_event_triggers_context_menu((GdkEvent*) event) && event->type == GDK_BUTTON_PRESS) {
		if(b_busy) return TRUE;
		update_resultview_popup();
#if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 22
		gtk_menu_popup_at_pointer(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_resultview")), (GdkEvent*) event);
#else
		gtk_menu_popup(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_resultview")), NULL, NULL, NULL, NULL, event->button, event->time);
#endif
		return TRUE;
	}
	return FALSE;
}
gboolean on_resultview_popup_menu(GtkWidget*, gpointer) {
	if(b_busy) return TRUE;
	update_resultview_popup();
#if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 22
	gtk_menu_popup_at_pointer(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_resultview")), NULL);
#else
	gtk_menu_popup(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_resultview")), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time());
#endif
	return TRUE;
}

void on_button_programmers_keypad_toggled(GtkToggleButton *w, gpointer) {
	if(gtk_toggle_button_get_active(w)) {
		visible_keypad = 1;
		if(evalops.approximation == APPROXIMATION_EXACT) {
			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "button_exact")), FALSE);
			versatile_exact = true;
		} else {
			versatile_exact = false;
		}
		if(programming_inbase > 0 && programming_outbase != 0 && (((programming_inbase != 10 || (programming_outbase != 10 && programming_outbase > 0 && programming_outbase <= 36)) && evalops.parse_options.base == 10 && printops.base == 10) || evalops.parse_options.base < 2 || printops.base < 2 || evalops.parse_options.base > 36 || printops.base > 16)) {
			if(printops.base != programming_outbase) {
				printops.base = programming_outbase;
				set_output_base_from_dialog(programming_outbase);
				output_base_updated_from_menu();
				if(evalops.parse_options.base == programming_inbase) result_format_updated();
			}
			if(evalops.parse_options.base != programming_inbase) {
				evalops.parse_options.base = programming_inbase;
				input_base_updated_from_menu();
				update_keypad_bases();
				expression_format_updated();
			}
		}
		programming_inbase = 0;
		programming_outbase = 0;
		gtk_stack_set_visible_child(GTK_STACK(gtk_builder_get_object(main_builder, "stack_left_buttons")), GTK_WIDGET(gtk_builder_get_object(main_builder, "programmers_keypad")));
		gtk_stack_set_visible_child_name(GTK_STACK(gtk_builder_get_object(main_builder, "stack_keypad_top")), "page1");
	} else {
		if(versatile_exact && evalops.approximation == APPROXIMATION_TRY_EXACT) {
			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "button_exact")), TRUE);
		}
		gtk_stack_set_visible_child(GTK_STACK(gtk_builder_get_object(main_builder, "stack_left_buttons")), GTK_WIDGET(gtk_builder_get_object(main_builder, "versatile_keypad")));
		gtk_stack_set_visible_child_name(GTK_STACK(gtk_builder_get_object(main_builder, "stack_keypad_top")), "page0");
		visible_keypad = 0;
		programming_inbase = evalops.parse_options.base;
		programming_outbase = printops.base;
		if(evalops.parse_options.base != 10) clear_expression_text();
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "button_dec")), TRUE);
	}
	focus_keeping_selection();
}

void on_popup_menu_programmers_keypad_toggled(GtkCheckMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(w)) return;
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "button_programmers_keypad")), TRUE);
}
void on_popup_menu_general_keypad_toggled(GtkCheckMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(w)) return;
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "button_programmers_keypad")), FALSE);
}

void update_popup_menu_left_keypad() {
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_programmers_keypad"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_programmers_keypad_toggled, NULL);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_general_keypad"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_general_keypad_toggled, NULL);
	if(visible_keypad == 1) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_programmers_keypad")), TRUE);
	else gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_general_keypad")), TRUE);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_programmers_keypad"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_programmers_keypad_toggled, NULL);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_general_keypad"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_general_keypad_toggled, NULL);
}

gboolean on_stack_left_buttons_button_press_event(GtkWidget*, GdkEventButton *event, gpointer) {
	if(gdk_event_triggers_context_menu((GdkEvent*) event) && event->type == GDK_BUTTON_PRESS) {
		if(b_busy) return TRUE;
		update_popup_menu_left_keypad();
#if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 22
		gtk_menu_popup_at_pointer(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_left_keypad")), (GdkEvent*) event);
#else
		gtk_menu_popup(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_left_keypad")), NULL, NULL, NULL, NULL, event->button, event->time);
#endif
		return TRUE;
	}
	return FALSE;
}
gboolean on_stack_left_buttons_popup_menu(GtkWidget*, gpointer) {
	if(b_busy) return TRUE;
	update_popup_menu_left_keypad();
#if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 22
	gtk_menu_popup_at_pointer(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_left_keypad")), NULL);
#else
	gtk_menu_popup(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_left_keypad")), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time());
#endif
	return TRUE;
}

gboolean on_units_entry_from_val_focus_out_event(GtkEntry*, GdkEventFocus*, gpointer) {
	if(old_fromValue != gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(units_builder, "units_entry_from_val")))) convert_in_wUnits(0);
	return FALSE;
}
gboolean on_units_entry_to_val_focus_out_event(GtkEntry*, GdkEventFocus*, gpointer) {
	if(old_toValue != gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(units_builder, "units_entry_to_val")))) convert_in_wUnits(1);
	return FALSE;
}

/*
	enter in expression entry does the same as clicking "Execute" button
*/
void on_expression_activate(GtkEntry*, gpointer) {
	execute_expression();
}

void on_convert_entry_unit_icon_release(GtkEntry *entry, GtkEntryIconPosition icon_pos, GdkEvent*, gpointer) {
	switch(icon_pos) {
		case GTK_ENTRY_ICON_PRIMARY: {
			break;
		}
		case GTK_ENTRY_ICON_SECONDARY: {
			gtk_editable_delete_text(GTK_EDITABLE(entry), 0, -1);
			break;
		}
	}
}

/*
	"Execute" clicked
*/
void on_button_execute_clicked(GtkButton*, gpointer) {
	execute_expression();
}
/*
	save preferences, mode and definitions and then quit
*/
gboolean on_gcalc_exit(GtkWidget*, GdkEvent*, gpointer) {
	stop_timeouts = true;
	exit_in_progress = true;
	CALCULATOR->abort();
	if(plot_builder && gtk_widget_get_visible(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_dialog")))) {
		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_dialog")));
	}
	//save_accels();
	if(save_mode_on_exit) {
		save_mode();
	} else {
		save_preferences();
	}
	if(save_defs_on_exit) {
		save_defs();
	}
	for(size_t i = 0; i < history_parsed.size(); i++) {
		if(history_parsed[i]) history_parsed[i]->unref();
		if(history_answer[i]) history_answer[i]->unref();
	}
	if(view_thread->running) {
		view_thread->write(0);
		view_thread->write(NULL);
	}
	CALCULATOR->terminateThreads();
	g_application_quit(g_application_get_default());
	return TRUE;
}

void save_accels() {
	recursiveMakeDir(getLocalDir());
	gchar *gstr = g_build_filename(getLocalDir().c_str(), "accelmap", NULL);
	gtk_accel_map_save(gstr);
	g_free(gstr);
}


/*
	DEL button clicked -- delete in expression entry
*/
void on_button_del_clicked(GtkButton*, gpointer) {
	if(gtk_text_buffer_get_has_selection(expressionbuffer)) {
		overwrite_expression_selection(NULL);
		return;
	}
	block_completion();
	GtkTextMark *mpos = gtk_text_buffer_get_insert(expressionbuffer);
	GtkTextIter ipos, iend;
	gtk_text_buffer_get_iter_at_mark(expressionbuffer, &ipos, mpos);
	if(gtk_text_iter_is_end(&ipos)) {
		gtk_text_buffer_get_end_iter(expressionbuffer, &iend);
		if(gtk_text_iter_backward_char(&ipos)) {
			gtk_text_buffer_delete(expressionbuffer, &ipos, &iend);
		}
	} else {
		iend = ipos;
		if(!gtk_text_iter_forward_char(&iend)) {
			gtk_text_buffer_get_end_iter(expressionbuffer, &iend);
		}
		gtk_text_buffer_delete(expressionbuffer, &ipos, &iend);
	}
	focus_keeping_selection();
	unblock_completion();
}

/*
	AC button clicked -- clear expression entry
*/
void on_button_ac_clicked(GtkButton*, gpointer) {
	clear_expression_text();
	focus_keeping_selection();
}

void on_button_reciprocal_clicked(GtkButton*, gpointer) {
	if(rpn_mode || evalops.parse_options.rpn || is_at_beginning_of_expression()) {
		insertButtonFunction(CALCULATOR->getActiveFunction("inv"));
	} else {
		bool do_exec = wrap_expression_selection(NULL, true);
		insert_text("^-1");
		if(do_exec) execute_expression();
	}
}
void on_button_idiv_clicked(GtkButton*, gpointer) {
	if(expression_is_empty() || rpn_mode || evalops.parse_options.rpn || is_at_beginning_of_expression()) {
		insertButtonFunction(CALCULATOR->getActiveFunction("div"));
	} else {
		wrap_expression_selection();
		insert_text("//");
	}
}

/*
	STO button clicked -- store result
*/
void on_button_store_clicked(GtkButton*, gpointer) {
	if(displayed_mstruct && mstruct && !mstruct->isZero()) add_as_variable();
	else edit_variable(_("My Variables"), NULL, NULL, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")));
}

bool completion_ignore_enter = false, completion_hover_blocked = false;

gboolean on_completionview_enter_notify_event(GtkWidget*, GdkEventCrossing*, gpointer) {
	return completion_ignore_enter;
}
gboolean on_completionview_motion_notify_event(GtkWidget*, GdkEventMotion*, gpointer) {
	completion_ignore_enter = FALSE;
	if(completion_hover_blocked) {
		gtk_tree_view_set_hover_selection(GTK_TREE_VIEW(completion_view), TRUE);
		completion_hover_blocked = false;
	}
	return FALSE;
}
gboolean on_completionwindow_key_press_event(GtkWidget *widget, GdkEventKey *event, gpointer user_data) {
	if(!gtk_widget_get_mapped(completion_window)) return FALSE;
	gtk_widget_event(expressiontext, (GdkEvent*) event);
	return TRUE;
}
gboolean on_completionwindow_button_press_event(GtkWidget *widget, GdkEventButton *event, gpointer user_data) {
	if(!gtk_widget_get_mapped(completion_window)) return FALSE;
	gtk_widget_hide(completion_window);
	return TRUE;
}

bool units_convert_ignore_enter = false, units_convert_hover_blocked = false;

gboolean on_units_convert_view_enter_notify_event(GtkWidget*, GdkEventCrossing*, gpointer) {
	return units_convert_ignore_enter;
}
gboolean on_units_convert_view_motion_notify_event(GtkWidget*, GdkEventMotion*, gpointer) {
	units_convert_ignore_enter = FALSE;
	if(units_convert_hover_blocked) {
		gtk_tree_view_set_hover_selection(GTK_TREE_VIEW(units_convert_view), TRUE);
		units_convert_hover_blocked = false;
	}
	return FALSE;
}
gboolean on_units_convert_window_key_press_event(GtkWidget *widget, GdkEventKey *event, gpointer) {
	if(!gtk_widget_get_mapped(units_convert_window)) return FALSE;
	gtk_widget_event(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_convert_to_button")), (GdkEvent*) event);
	return TRUE;
}
gboolean on_units_convert_window_button_press_event(GtkWidget *widget, GdkEventButton *event, gpointer) {
	if(!gtk_widget_get_mapped(units_convert_window)) return FALSE;
	gtk_widget_hide(units_convert_window);
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(units_builder, "units_convert_to_button")), FALSE);
	return TRUE;
}
void units_convert_resize_popup() {

	int matches = gtk_tree_model_iter_n_children(units_convert_filter, NULL);

	gint x, y;
	gint items, height = 0, items_y = 0, height_diff;
	GdkDisplay *display;

#if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 22
	GdkMonitor *monitor;
#endif
	GdkRectangle area, rect;
	GtkAllocation alloc;
	GdkWindow *window;
	GtkRequisition popup_req;
	GtkRequisition tree_req;
	GtkTreePath *path;
	gboolean above;
	GtkTreeViewColumn *column;

	gtk_widget_get_allocation(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_convert_to_button")), &alloc);
	window = gtk_widget_get_window(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_convert_to_button")));
	gdk_window_get_origin(window, &x, &y);
	x += alloc.x;
	y += alloc.y;

	gtk_widget_realize(units_convert_view);
	while(gtk_events_pending()) gtk_main_iteration();
	gtk_tree_view_columns_autosize(GTK_TREE_VIEW(units_convert_view));
	column = gtk_tree_view_get_column(GTK_TREE_VIEW(units_convert_view), 0);
	
	gtk_widget_get_preferred_size(units_convert_view, &tree_req, NULL);
	gtk_tree_view_column_cell_get_size(column, NULL, NULL, NULL, NULL, &height_diff);
	
	path = gtk_tree_path_new_from_indices(0, -1);
	gtk_tree_view_get_cell_area(GTK_TREE_VIEW(units_convert_view), path, column, &rect);
	gtk_tree_path_free(path);
	items_y = rect.y;
	height_diff -= rect.height;
	if(height_diff < 2) height_diff = 2;

	display = gtk_widget_get_display(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_convert_to_button")));
#if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 22
	monitor = gdk_display_get_monitor_at_window(display, window);
	gdk_monitor_get_workarea(monitor, &area);
#else
	GdkScreen *screen = gdk_display_get_default_screen(display);
	gdk_screen_get_monitor_workarea(screen, gdk_screen_get_monitor_at_window(screen, window), &area);
#endif
	
	items = matches;
	if(items > 20) items = 20;
	if(items > 0) {
		path = gtk_tree_path_new_from_indices(items - 1, -1);
		gtk_tree_view_get_cell_area(GTK_TREE_VIEW(units_convert_view), path, column, &rect);
		gtk_tree_path_free(path);
		height = rect.y + rect.height - items_y + height_diff;
	}
	while(items > 0 && ((y > area.height / 2 && area.y + y < height) || (y <= area.height / 2 && area.height - y < height))) {
		items--;
		path = gtk_tree_path_new_from_indices(items - 1, -1);
		gtk_tree_view_get_cell_area(GTK_TREE_VIEW(units_convert_view), path, column, &rect);
		gtk_tree_path_free(path);
		height = rect.y + rect.height - items_y + height_diff;
	}

	gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW(units_convert_scrolled), height);
	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(units_convert_scrolled), GTK_POLICY_NEVER, matches > 20 ? GTK_POLICY_ALWAYS : GTK_POLICY_NEVER);


	if(items <= 0) gtk_widget_hide(units_convert_scrolled);
	else gtk_widget_show(units_convert_scrolled);

	gtk_widget_get_preferred_size(units_convert_window, &popup_req, NULL);
	
	if(popup_req.width < rect.width + 2) popup_req.width = rect.width + 2;
	if(popup_req.width < alloc.width) {
		popup_req.width = alloc.width;
		gtk_widget_set_size_request(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_convert_search")), popup_req.width, -1);
	}

	if(x < area.x) x = area.x;
	else if(x + popup_req.width > area.x + area.width) x = area.x + area.width - popup_req.width;

	if(y + alloc.height + popup_req.height <= area.y + area.height || y - area.y < (area.y + area.height) - (y + alloc.height)) {
		y += alloc.height;
		above = FALSE;
	} else {
		path = gtk_tree_path_new_from_indices(matches - 1, -1);
		gtk_tree_view_get_cell_area(GTK_TREE_VIEW(units_convert_view), path, column, &rect);
		gtk_tree_path_free(path);
		height = rect.y + rect.height + height_diff;
		path = gtk_tree_path_new_from_indices(matches - items, -1);
		gtk_tree_view_get_cell_area(GTK_TREE_VIEW(units_convert_view), path, column, &rect);
		gtk_tree_path_free(path);
		height -= rect.y;
		gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW(units_convert_scrolled), height);
		y -= popup_req.height;
		above = TRUE;
	}

	if(matches > 0) {
		path = gtk_tree_path_new_from_indices(above ? matches - 1 : 0, -1);
		gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(units_convert_view), path, NULL, FALSE, 0.0, 0.0);
		gtk_tree_path_free(path);
	}

	gtk_window_move(GTK_WINDOW(units_convert_window), x, y);

}
void on_units_convert_to_button_toggled(GtkToggleButton *w, gpointer) {
	if(gtk_toggle_button_get_active(w)) {
		units_convert_ignore_enter = TRUE;
		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(units_builder, "units_convert_search")), "");
		units_convert_resize_popup();
		if(!gtk_widget_is_visible(units_convert_window)) {
			gtk_tree_view_set_hover_selection(GTK_TREE_VIEW(completion_view), TRUE);
			gtk_window_set_transient_for(GTK_WINDOW(units_convert_window), GTK_WINDOW(gtk_builder_get_object(units_builder, "units_dialog")));
			gtk_window_group_add_window(gtk_window_get_group(GTK_WINDOW(gtk_builder_get_object(units_builder, "units_dialog"))), GTK_WINDOW(units_convert_window));
			gtk_window_set_screen(GTK_WINDOW(units_convert_window), gtk_widget_get_screen(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_convert_to_button"))));
			gtk_widget_show(units_convert_window);
		}
		gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(units_convert_view)));
		while(gtk_events_pending()) gtk_main_iteration();
		gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(units_convert_view)));
	} else {
		gtk_widget_hide(units_convert_window);
	}
}

void completion_resize_popup(int matches) {

	gint x, y;
	gint items, height = 0, items_y = 0, height_diff;
	GdkDisplay *display;

#if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 22
	GdkMonitor *monitor;
#endif
	GdkRectangle area, bufloc, rect;
	GdkWindow *window;
	GtkRequisition popup_req;
	GtkRequisition tree_req;
	GtkTreePath *path;
	gboolean above;
	GtkTreeViewColumn *column;

	GtkTextMark *miter = gtk_text_buffer_get_insert(expressionbuffer);
	GtkTextIter iter;
	gtk_text_buffer_get_iter_at_mark(expressionbuffer, &iter, miter);
	gtk_text_view_get_iter_location(GTK_TEXT_VIEW(expressiontext), &iter, &bufloc);
	gtk_text_view_buffer_to_window_coords(GTK_TEXT_VIEW(expressiontext), GTK_TEXT_WINDOW_WIDGET, bufloc.x, bufloc.y, &bufloc.x, &bufloc.y);
	window = gtk_text_view_get_window (GTK_TEXT_VIEW(expressiontext), GTK_TEXT_WINDOW_WIDGET);
	gdk_window_get_origin(window, &x, &y);

	x += bufloc.x;
	y += bufloc.y;

	gtk_widget_realize(completion_view);
	while(gtk_events_pending()) gtk_main_iteration();
	gtk_tree_view_columns_autosize(GTK_TREE_VIEW(completion_view));
	column = gtk_tree_view_get_column(GTK_TREE_VIEW(completion_view), 0);
	
	gtk_widget_get_preferred_size(completion_view, &tree_req, NULL);
	gtk_tree_view_column_cell_get_size(column, NULL, NULL, NULL, NULL, &height_diff);
	
	path = gtk_tree_path_new_from_indices(0, -1);
	gtk_tree_view_get_cell_area(GTK_TREE_VIEW(completion_view), path, column, &rect);
	gtk_tree_path_free(path);
	items_y = rect.y;
	height_diff -= rect.height;
	if(height_diff < 2) height_diff = 2;

	display = gtk_widget_get_display(GTK_WIDGET(expressiontext));
#if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 22
	monitor = gdk_display_get_monitor_at_window(display, window);
	gdk_monitor_get_workarea(monitor, &area);
#else
	GdkScreen *screen = gdk_display_get_default_screen(display);
	gdk_screen_get_monitor_workarea(screen, gdk_screen_get_monitor_at_window(screen, window), &area);
#endif
	
	items = matches;
	if(items > 20) items = 20;
	if(items > 0) {
		path = gtk_tree_path_new_from_indices(items - 1, -1);
		gtk_tree_view_get_cell_area(GTK_TREE_VIEW(completion_view), path, column, &rect);
		gtk_tree_path_free(path);
		height = rect.y + rect.height - items_y + height_diff;
	}
	while(items > 0 && ((y > area.height / 2 && area.y + y < height) || (y <= area.height / 2 && area.height - y < height))) {
		items--;
		path = gtk_tree_path_new_from_indices(items - 1, -1);
		gtk_tree_view_get_cell_area(GTK_TREE_VIEW(completion_view), path, column, &rect);
		gtk_tree_path_free(path);
		height = rect.y + rect.height - items_y + height_diff;
	}

	gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW(completion_scrolled), height);

	if(items <= 0) gtk_widget_hide(completion_scrolled);
	else gtk_widget_show(completion_scrolled);

	gtk_widget_get_preferred_size(completion_window, &popup_req, NULL);
	
	if(popup_req.width < rect.width + 2) popup_req.width = rect.width + 2;

	if(x < area.x) x = area.x;
	else if(x + popup_req.width > area.x + area.width) x = area.x + area.width - popup_req.width;

	if(y + bufloc.height + popup_req.height <= area.y + area.height || y - area.y < (area.y + area.height) - (y + bufloc.height)) {
		y += bufloc.height;
		above = FALSE;
	} else {
		path = gtk_tree_path_new_from_indices(matches - 1, -1);
		gtk_tree_view_get_cell_area(GTK_TREE_VIEW(completion_view), path, column, &rect);
		gtk_tree_path_free(path);
		height = rect.y + rect.height + height_diff;
		path = gtk_tree_path_new_from_indices(matches - items, -1);
		gtk_tree_view_get_cell_area(GTK_TREE_VIEW(completion_view), path, column, &rect);
		gtk_tree_path_free(path);
		height -= rect.y;
		gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW(completion_scrolled), height);
		y -= popup_req.height;
		above = TRUE;
	}

	if(matches > 0) {
		path = gtk_tree_path_new_from_indices(above ? matches - 1 : 0, -1);
		gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(completion_view), path, NULL, FALSE, 0.0, 0.0);
		gtk_tree_path_free(path);
	}

	gtk_window_move(GTK_WINDOW(completion_window), x, y);

}

void do_completion() {
	if(!enable_completion) {gtk_widget_hide(completion_window); return;}
	set_current_object();
	if(current_object_start < 0) {
		gtk_widget_hide(completion_window); 
		return;
	}
	GtkTextIter object_start, object_end;
	gtk_text_buffer_get_iter_at_offset(expressionbuffer, &object_start, current_object_start);
	gtk_text_buffer_get_iter_at_offset(expressionbuffer, &object_end, current_object_end);
	gchar *gstr2 = gtk_text_buffer_get_text(expressionbuffer, &object_start, &object_end, FALSE);
	string str = gstr2;
	g_free(gstr2);
	if(str.length() < (size_t) completion_min) {gtk_widget_hide(completion_window); return;}
	GtkTreeIter iter;
	int matches = 0;
	bool show_separator1 = false, show_separator2 = false;
	if(str.length() > 0 && is_not_in(NUMBERS NOT_IN_NAMES "%", str[0]) && gtk_tree_model_get_iter_first(GTK_TREE_MODEL(completion_store), &iter)) {
		string str2, str3, str4;
		Prefix *p2 = NULL, *p3 = NULL, *p4 = NULL;
		if(str.length() > (size_t) completion_min) {
			for(size_t pi = 1; ; pi++) {
				Prefix *prefix = CALCULATOR->getPrefix(pi);
				if(!prefix) break;
				for(size_t name_i = 0; name_i < 3; name_i++) {
					const string *pname;
					if(name_i == 0) pname = &prefix->shortName(false);
					else if(name_i == 1) pname = &prefix->longName(false);
					else pname = &prefix->unicodeName(false);
					if(!pname->empty() && pname->length() < str.length() - completion_min + 1) {
						bool pmatch = true;
						for(size_t i = 0; i < pname->length(); i++) {
							if((*pname)[i] != str[i]) {
								pmatch = false;
								break;
							}
						}
						if(pmatch) {
							if(str2.empty()) {p2 = prefix; str2 = str.substr(pname->length());}
							else if(str3.empty()) {p3 = prefix; str3 = str.substr(pname->length());}
							else if(str4.empty()) {p4 = prefix; str4 = str.substr(pname->length());}
						}
					}
				}
			}
		}
		do {
			ExpressionItem *item = NULL;
			Prefix *prefix = NULL;
			gtk_tree_model_get(GTK_TREE_MODEL(completion_store), &iter, 2, &item, 8, &prefix, -1);
			int b_match = false;
			size_t i_match = 0;
			if(item) {
				if((editing_to_expression || !evalops.parse_options.functions_enabled) && item->type() == TYPE_FUNCTION) {}
				else if(item->type() == TYPE_VARIABLE && (!evalops.parse_options.variables_enabled || (editing_to_expression && (!((Variable*) item)->isKnown() || ((KnownVariable*) item)->unit().empty())))) {}
				else if(!evalops.parse_options.units_enabled && item->type() == TYPE_UNIT) {}
				else {
					for(size_t name_i = 1; name_i <= item->countNames() && !b_match; name_i++) {
						const ExpressionName *ename = &item->getName(name_i);
						if(ename) {
							if(item->isHidden() && (item->type() != TYPE_UNIT || str.length() == 1 || !((Unit*) item)->isCurrency()) && ename) {
								b_match = (ename->name == str) ? 1 : 0;
							} else {
								for(size_t icmp = 0; icmp < 4; icmp++) {
									if(icmp == 1 && (item->type() != TYPE_UNIT || str2.empty() || !((Unit*) item)->useWithPrefixesByDefault())) break;
									const string *cmpstr;
									if(icmp == 0) cmpstr = &str;
									else if(icmp == 1) cmpstr = &str2;
									else if(icmp == 2) cmpstr = &str3;
									else cmpstr = &str4;
									if(cmpstr->empty()) break;
									if(cmpstr->length() <= ename->name.length()) {
										b_match = 2;
										for(size_t i = 0; i < cmpstr->length(); i++) {
											if(ename->name[i] != (*cmpstr)[i]) {
												b_match = false;
												break;
											}
										}
										if(b_match && ename->name == *cmpstr) b_match = 1;
										if(b_match) {
											if(icmp > 0) {
												if(icmp == 1) prefix = p2;
												else if(icmp == 2) prefix = p3;
												else if(icmp == 3) prefix = p4;
												i_match = str.length() - cmpstr->length();
											}
											break;
										}
									}
								}
							}
						}
					}
					if(b_match == 2 && item->countNames() > 1) {
						for(size_t icmp = 0; icmp < 4 && b_match > 1; icmp++) {
							if(icmp == 1 && (item->type() != TYPE_UNIT || str2.empty() || !((Unit*) item)->useWithPrefixesByDefault())) break;
							const string *cmpstr;
							if(icmp == 0) cmpstr = &str;
							else if(icmp == 1) cmpstr = &str2;
							else if(icmp == 2) cmpstr = &str3;
							else cmpstr = &str4;
							if(cmpstr->empty()) break;
							for(size_t name_i = 1; name_i <= item->countNames(); name_i++) {
								if(item->getName(name_i).name == *cmpstr) {
									if(icmp == 1) prefix = p2;
									else if(icmp == 2) prefix = p3;
									else if(icmp == 3) prefix = p4;
									else prefix = NULL;
									b_match = 1; break;
								}
							}
						}
					}
					if(!b_match && enable_completion2) {
						if(title_matches(item, str, completion_min2)) b_match = 4;
						else if(item->type() == TYPE_UNIT && ((Unit*) item)->isCurrency() && country_matches((Unit*) item, str, completion_min2)) b_match = 5;
					}
				}
				if(b_match) {
					gchar *gstr;
					gtk_tree_model_get(GTK_TREE_MODEL(completion_store), &iter, 0, &gstr, -1);
					if(gstr && strlen(gstr) > 0) {
						string nstr;
						if(gstr[0] == '<') {
							nstr = gstr;
							size_t i = nstr.find("-) </small>");
							if(i != string::npos && i > 2) {
								if(prefix && prefix->longName() == nstr.substr(8, i - 8)) {
									prefix = NULL;
								} else {
									nstr = nstr.substr(i + 11);
									if(!prefix) gtk_list_store_set(completion_store, &iter, 0, nstr.c_str(), -1);
								}
							}
						}
						if(prefix) {
							if(nstr.empty()) nstr = gstr;
							nstr.insert(0, "-) </small>");
							nstr.insert(0, prefix->longName());
							nstr.insert(0, "<small>(");
							gtk_list_store_set(completion_store, &iter, 0, nstr.c_str(), -1);
						}
						g_free(gstr);
					}
				}
			} else if(prefix) {
				for(size_t name_i = 0; name_i < 3 && !b_match; name_i++) {
					const string *pname;
					if(name_i == 0) pname = &prefix->shortName(false);
					else if(name_i == 1) pname = &prefix->unicodeName(false);
					else pname = &prefix->longName(false);
					if(!pname->empty() && str.length() <= pname->length()) {
						b_match = 2;
						for(size_t i = 0; i < str.length(); i++) {
							if(str[i] != (*pname)[i]) {
								b_match = false;
								break;
							}
						}
						if(b_match && *pname == str) b_match = 1;
					}
				}
				prefix = NULL;
			} else if(editing_to_expression) {
				gchar *gstr;
				gtk_tree_model_get(GTK_TREE_MODEL(completion_store), &iter, 0, &gstr, -1);
				if(completion_names_match(gstr, str)) {
					b_match = 2;
				}
				g_free(gstr);
			}
			gtk_list_store_set(completion_store, &iter, 3, b_match > 0, 4, b_match, 6, b_match == 1 ? PANGO_WEIGHT_BOLD : (b_match > 3 ? PANGO_WEIGHT_LIGHT : PANGO_WEIGHT_NORMAL), 7, i_match, -1);
			if(b_match) {
				matches++;
				if(b_match > 3) show_separator2 = true;
				else if(b_match < 3) show_separator1 = true;
			}
		} while(gtk_tree_model_iter_next(GTK_TREE_MODEL(completion_store), &iter));
	}
	if(matches > 0) {
		gtk_list_store_set(completion_store, &completion_separator_iter, 3, show_separator1 && show_separator2, 4, 3, -1);
		if(show_separator1 && show_separator2) matches++;
		completion_ignore_enter = TRUE;
		completion_resize_popup(matches);
		if(!gtk_widget_is_visible(completion_window)) {
			gtk_window_set_transient_for(GTK_WINDOW(completion_window), GTK_WINDOW(mainwindow));
			gtk_window_group_add_window(gtk_window_get_group(GTK_WINDOW(mainwindow)), GTK_WINDOW(completion_window));
			gtk_window_set_screen(GTK_WINDOW(completion_window), gtk_widget_get_screen(expressiontext));
			gtk_widget_show(completion_window);
		}
		gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(completion_view)));
		while(gtk_events_pending()) gtk_main_iteration();
		gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(completion_view)));
	} else {
		gtk_widget_hide(completion_window);
	}
}

gboolean do_completion_timeout(gpointer) {
	if(!completion_blocked) do_completion();
	completion_timeout_id = 0;
	return false;
}
void on_expressionbuffer_changed(GtkTextBuffer*, gpointer) {
	if(completion_timeout_id != 0) {
		g_source_remove(completion_timeout_id);
		completion_timeout_id = 0;
	}
	if(add_to_undo) add_expression_to_undo();
	expression_has_changed = true;
	expression_has_changed2 = true;
	current_object_has_changed = true;
	expression_has_changed_pos = true;
	highlight_parentheses();
	if(!completion_blocked) {
		if(completion_delay <= 0 || gtk_widget_is_visible(completion_window)) {
			completion_timeout_id = gdk_threads_add_idle(do_completion_timeout, NULL);
		} else {
			completion_timeout_id = g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE, completion_delay, do_completion_timeout, NULL, NULL);
		}
	}
	display_parse_status();
	if(!rpn_mode && auto_calculate) do_auto_calc();
	if(result_text.empty()) return;
	if(!dont_change_index) expression_history_index = -1;
	if(!auto_calculate && !rpn_mode) clearresult();
}

void on_convert_entry_unit_changed(GtkEditable *w, gpointer) {
	bool b = gtk_entry_get_text_length(GTK_ENTRY(w)) > 0;
	gtk_entry_set_icon_from_icon_name(GTK_ENTRY(w), GTK_ENTRY_ICON_SECONDARY, b ? "edit-clear-symbolic" : NULL);
	gtk_entry_set_icon_tooltip_text(GTK_ENTRY(w), GTK_ENTRY_ICON_SECONDARY, b ? _("Clear expression") : NULL);
	if(!keep_unit_selection) gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitSelector)));
}

gboolean on_keypad_button_alt(GtkWidget *w, bool b2) {
	if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_divide"))) {
		insertButtonFunction(CALCULATOR->getActiveFunction("inv"));
		return TRUE;
	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_exp"))) {
		if(b2) {
			insertButtonFunction(CALCULATOR->getActiveFunction("exp10"));
		} else {
			insertButtonFunction(CALCULATOR->f_exp);
		}
		return TRUE;
	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_dot")) || w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_comma"))) {
		if(b2) {
			insert_text("\n");
		} else {
			insert_text(" ");
		}
		return TRUE;
	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_brace_open"))) {
		insert_text("[");
		return TRUE;
	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_brace_close"))) {
		insert_text("]");
		return TRUE;
	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_brace_wrap"))) {
		if(gtk_text_buffer_get_has_selection(expressionbuffer)) {
			GtkTextIter istart, iend;
			gtk_text_buffer_get_selection_bounds(expressionbuffer, &istart, &iend);
			gchar *gstr = gtk_text_buffer_get_text(expressionbuffer, &istart, &iend, FALSE);
			string str = "[";
			str += gstr;
			str += "]";
			insert_text(str.c_str());
			g_free(gstr);
		} else {
			insert_text("[]");
			GtkTextIter iter;
			gtk_text_buffer_get_iter_at_mark(expressionbuffer, &iter, gtk_text_buffer_get_insert(expressionbuffer));
			gtk_text_iter_backward_char(&iter);
			gtk_text_buffer_place_cursor(expressionbuffer, &iter);
		}
		return TRUE;
	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_add"))) {
		insert_bitwise_and();
		return TRUE;
	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_sub"))) {
		if(b2) insert_bitwise_or();
		else insertButtonFunction(CALCULATOR->getActiveFunction("neg"));
		return TRUE;
	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_times"))) {
		insert_bitwise_xor();
		return TRUE;
	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_xy"))) {
		insertButtonFunction(CALCULATOR->f_sqrt);
		return TRUE;
	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_del"))) {
		if(gtk_text_buffer_get_has_selection(expressionbuffer)) {
			overwrite_expression_selection(NULL);
		} else {
			block_completion();
			GtkTextMark *mpos = gtk_text_buffer_get_insert(expressionbuffer);
			GtkTextIter ipos, iend;
			gtk_text_buffer_get_iter_at_mark(expressionbuffer, &ipos, mpos);
			iend = ipos;
			if(gtk_text_iter_backward_char(&ipos)) {
				gtk_text_buffer_delete(expressionbuffer, &ipos, &iend);
			}
			focus_keeping_selection();
			unblock_completion();
		}
		return TRUE;
	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_ans"))) {
		if(history_answer.size() > 0) {
			string str = f_answer->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext).name;
			Number nr(history_answer.size(), 1);
			str += '(';
			str += print_with_evalops(nr);
			str += ')';
			insert_text(str.c_str());
		}
		return TRUE;
	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_percent"))) {
		insert_var(CALCULATOR->v_permille);
		return TRUE;
	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_plusminus"))) {
		if(b2) insertButtonFunction(CALCULATOR->f_interval);
		else insertButtonFunction(CALCULATOR->f_uncertainty);
		return TRUE;
	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_bin"))) {
		base_button_alternative(2);
		return TRUE;
	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_oct"))) {
		base_button_alternative(8);
		return TRUE;
	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_dec"))) {
		base_button_alternative(10);
		return TRUE;
	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_hex"))) {
		base_button_alternative(16);
		return TRUE;
	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_mod2"))) {
		if(expression_is_empty() || rpn_mode || evalops.parse_options.rpn) {
			insertButtonFunction(CALCULATOR->f_rem);
		} else {
			wrap_expression_selection();
			insert_text(" rem ");
		}
		return TRUE;
	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_sqrt2"))) {
		insertButtonFunction(CALCULATOR->f_cbrt);
		return TRUE;
	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_expf"))) {
		insertButtonFunction(CALCULATOR->getActiveFunction("exp2"));
		return TRUE;
	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_log2"))) {
		insertButtonFunction(CALCULATOR->getActiveFunction("log10"));
		return TRUE;
	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_code"))) {
		insertButtonFunction(CALCULATOR->f_char);
		return TRUE;
	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_stamptodate"))) {
		insertButtonFunction(CALCULATOR->f_timestamp);
		return TRUE;
	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_and"))) {
		if(rpn_mode) {calculateRPN(OPERATION_LOGICAL_AND); return TRUE;}
		if(!evalops.parse_options.rpn) wrap_expression_selection();
		insert_text("&&");
		return TRUE;
	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_or"))) {
		if(rpn_mode) {calculateRPN(OPERATION_LOGICAL_OR); return TRUE;}
		if(!evalops.parse_options.rpn) wrap_expression_selection();
		insert_text("||");
		return TRUE;
	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_not"))) {
		if(rpn_mode) {
			if(expression_has_changed) {
				if(get_expression_text().find_first_not_of(SPACES) != string::npos) {
					execute_expression(true);
				}
			}
			execute_expression(true, false, OPERATION_ADD, NULL, false, 0, "!");
			return TRUE;
		}
		if(!evalops.parse_options.rpn && wrap_expression_selection("!")) return TRUE;
		insert_text("!");
		return TRUE;
	} else {
		int i = 0;
		if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_zero"))) i = 0;
		else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_one"))) i = 1;
		else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_two"))) i = 2;
		else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_three"))) i = 3;
		else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_four"))) i = 4;
		else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_five"))) i = 5;
		else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_six"))) i = 6;
		else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_seven"))) i = 7;
		else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_eight"))) i = 8;
		else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_nine"))) i = 9;
		else return FALSE;
		if(b2 && i == 1) {
			insertButtonFunction(CALCULATOR->getActiveFunction("inv"));
			return TRUE;
		} else if(b2 && i == 0) {
			insert_text(SIGN_DEGREE);
			return TRUE;
		}
		if(!b2) wrap_expression_selection();
		if(printops.use_unicode_signs && (evalops.parse_options.base > i || i == 0)) {
			if(b2) {
				if(i == 2 && can_display_unicode_string_function("½", (void*) expressiontext)) {insert_text("½"); return TRUE;}
				if(i == 3 && can_display_unicode_string_function("⅓", (void*) expressiontext)) {insert_text("⅓"); return TRUE;}
				if(i == 4 && can_display_unicode_string_function("¼", (void*) expressiontext)) {insert_text("¼"); return TRUE;}
				if(i == 5 && can_display_unicode_string_function("⅕", (void*) expressiontext)) {insert_text("⅕"); return TRUE;}
				if(i == 6 && can_display_unicode_string_function("⅙", (void*) expressiontext)) {insert_text("⅙"); return TRUE;}
				if(i == 7 && can_display_unicode_string_function("⅐", (void*) expressiontext)) {insert_text("⅐"); return TRUE;}
				if(i == 8 && can_display_unicode_string_function("⅛", (void*) expressiontext)) {insert_text("⅛"); return TRUE;}
				if(i == 9 && can_display_unicode_string_function("⅑", (void*) expressiontext)) {insert_text("⅑"); return TRUE;}
			} else {
				if(i == 0 && can_display_unicode_string_function(SIGN_POWER_0, (void*) expressiontext)) {insert_text(SIGN_POWER_0); return TRUE;}
				if(i == 1 && can_display_unicode_string_function(SIGN_POWER_1, (void*) expressiontext)) {insert_text(SIGN_POWER_1); return TRUE;}
				if(i == 2 && can_display_unicode_string_function(SIGN_POWER_2, (void*) expressiontext)) {insert_text(SIGN_POWER_2); return TRUE;}
				if(i == 3 && can_display_unicode_string_function(SIGN_POWER_3, (void*) expressiontext)) {insert_text(SIGN_POWER_3); return TRUE;}
				if(i == 4 && can_display_unicode_string_function(SIGN_POWER_4, (void*) expressiontext)) {insert_text(SIGN_POWER_4); return TRUE;}
				if(i == 5 && can_display_unicode_string_function(SIGN_POWER_5, (void*) expressiontext)) {insert_text(SIGN_POWER_5); return TRUE;}
				if(i == 6 && can_display_unicode_string_function(SIGN_POWER_6, (void*) expressiontext)) {insert_text(SIGN_POWER_6); return TRUE;}
				if(i == 7 && can_display_unicode_string_function(SIGN_POWER_7, (void*) expressiontext)) {insert_text(SIGN_POWER_7); return TRUE;}
				if(i == 8 && can_display_unicode_string_function(SIGN_POWER_8, (void*) expressiontext)) {insert_text(SIGN_POWER_8); return TRUE;}
				if(i == 9 && can_display_unicode_string_function(SIGN_POWER_9, (void*) expressiontext)) {insert_text(SIGN_POWER_9); return TRUE;}
			}
		}
		if(b2) {
			string str = "(";
			str += print_with_evalops(Number(1, 1));
			str += "/";
			str += print_with_evalops(Number(i, 1));
			str += ")";
			insert_text(str.c_str());
		} else {
			string str = "^";
			str += print_with_evalops(Number(i, 1));
			insert_text(str.c_str());
		}
		return TRUE;
	}
	return FALSE;
}

guint button_press_timeout_id = 0;
GtkWidget *button_press_timeout_w = NULL;
int button_press_timeout_side = 0;
bool button_press_timeout_done = false;

gboolean keypad_long_press_timeout(gpointer data) {
	if(!button_press_timeout_w) {
		button_press_timeout_id = 0;
		button_press_timeout_w = NULL;
		button_press_timeout_side = 0;
		button_press_timeout_done = false;
		return FALSE;
	}
	if(data) {
		if(GTK_WIDGET(data) == GTK_WIDGET(gtk_builder_get_object(main_builder, "menu_to"))) {
			if(b_busy) return TRUE;
			update_mb_to_menu();
		}
#if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 22
		gtk_menu_popup_at_widget(GTK_MENU(data), button_press_timeout_w, GDK_GRAVITY_SOUTH_WEST, GDK_GRAVITY_NORTH_WEST, gtk_get_current_event());
#else
		gtk_menu_popup(GTK_MENU(data), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time());
#endif
	} else if(button_press_timeout_w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_move2"))) {
		GtkTextIter iter;
		gtk_text_buffer_get_iter_at_mark(expressionbuffer, &iter, gtk_text_buffer_get_insert(expressionbuffer));
		if(button_press_timeout_side == 2) {
			if(gtk_text_iter_is_end(&iter)) gtk_text_buffer_get_start_iter(expressionbuffer, &iter);
			else gtk_text_iter_forward_char(&iter);
		} else {
			if(gtk_text_iter_is_start(&iter)) gtk_text_buffer_get_end_iter(expressionbuffer, &iter);
			else gtk_text_iter_backward_char(&iter);
		}
		gtk_text_buffer_place_cursor(expressionbuffer, &iter);
		button_press_timeout_done = true;
		return TRUE;
	} else if(button_press_timeout_w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_move"))) {
		if(button_press_timeout_side == 2) {
			if(expression_history_index > -1) {
				expression_history_index--;
				dont_change_index = true;
				block_completion();
				if(expression_history_index < 0) {
					clear_expression_text();
				} else {
					set_expression_text(expression_history[expression_history_index].c_str());
				}
				unblock_completion();
				dont_change_index = false;
			}
		} else {
			if(expression_history_index + 1 < (int) expression_history.size()) {
				expression_history_index++;
				dont_change_index = true;
				block_completion();
				set_expression_text(expression_history[expression_history_index].c_str());
				unblock_completion();
				dont_change_index = false;
			}
		}
		button_press_timeout_done = true;
		return TRUE;
	} else if(button_press_timeout_w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_del"))) {
		on_button_del_clicked(GTK_BUTTON(button_press_timeout_w), NULL);
		button_press_timeout_done = true;
		return TRUE;
	} else {
		on_keypad_button_alt(button_press_timeout_w, false);
	}
	button_press_timeout_done = true;
	button_press_timeout_id = 0;
	return FALSE;
}
gboolean on_button_del_button_event(GtkWidget *w, GdkEventButton *event, gpointer) {
	if(event->type == GDK_BUTTON_RELEASE && button_press_timeout_id != 0) {
		g_source_remove(button_press_timeout_id);
		bool b_this = (button_press_timeout_w == w);
		button_press_timeout_id = 0;
		button_press_timeout_w = NULL;
		button_press_timeout_side = 0;
		if(button_press_timeout_done) {
			button_press_timeout_done = false;
			if(b_this) return TRUE;
		}
	}
	if(event->type == GDK_BUTTON_PRESS && event->button == 1) {
		button_press_timeout_w = w;
		button_press_timeout_side = 0;
		button_press_timeout_id = g_timeout_add(250, keypad_long_press_timeout, NULL);
		return FALSE;
	}
	if(event->type == GDK_BUTTON_RELEASE && (event->button == 2 || event->button == 3)) {
		on_keypad_button_alt(w, event->button == 2);
	}
	return FALSE;
}
gboolean on_button_move2_button_event(GtkWidget *w, GdkEventButton *event, gpointer) {
	if(event->type == GDK_BUTTON_RELEASE && button_press_timeout_id != 0) {
		g_source_remove(button_press_timeout_id);
		bool b_this = (button_press_timeout_w == w);
		button_press_timeout_id = 0;
		button_press_timeout_w = NULL;
		button_press_timeout_side = 0;
		if(button_press_timeout_done) {
			button_press_timeout_done = false;
			if(b_this) return TRUE;
		}
	}
	if(event->type == GDK_BUTTON_PRESS && event->button == 1) {
		button_press_timeout_w = w;
		if(event->window && event->x > gdk_window_get_width(event->window) / 2) button_press_timeout_side = 2;
		else button_press_timeout_side = 1;
		button_press_timeout_id = g_timeout_add(250, keypad_long_press_timeout, NULL);
		return FALSE;
	}
	if(event->button == 2 || event->button == 3) {
		if(event->type == GDK_BUTTON_RELEASE) {
			GtkTextIter iter;
			if(event->window && event->x > gdk_window_get_width(event->window) / 2) {
				gtk_text_buffer_get_end_iter(expressionbuffer, &iter);
			} else {
				gtk_text_buffer_get_start_iter(expressionbuffer, &iter);
			}
			gtk_text_buffer_place_cursor(expressionbuffer, &iter);
		}
	} else {
		GtkTextIter iter;
		gtk_text_buffer_get_iter_at_mark(expressionbuffer, &iter, gtk_text_buffer_get_insert(expressionbuffer));
		if(event->window && event->x > gdk_window_get_width(event->window) / 2) {
			if(gtk_text_iter_is_end(&iter)) gtk_text_buffer_get_start_iter(expressionbuffer, &iter);
			else gtk_text_iter_forward_char(&iter);
		} else {
			if(gtk_text_iter_is_start(&iter)) gtk_text_buffer_get_end_iter(expressionbuffer, &iter);
			else gtk_text_iter_backward_char(&iter);
		}
		gtk_text_buffer_place_cursor(expressionbuffer, &iter);
	}
	return FALSE;
}
gboolean on_button_move_button_event(GtkWidget *w, GdkEventButton *event, gpointer) {
	if(event->type == GDK_BUTTON_RELEASE && button_press_timeout_id != 0) {
		g_source_remove(button_press_timeout_id);
		bool b_this = (button_press_timeout_w == w);
		button_press_timeout_id = 0;
		button_press_timeout_w = NULL;
		button_press_timeout_side = 0;
		if(button_press_timeout_done) {
			button_press_timeout_done = false;
			if(b_this) return TRUE;
		}
	}
	if(event->type == GDK_BUTTON_PRESS && event->button == 1) {
		button_press_timeout_w = w;
		if(event->window && event->x > gdk_window_get_width(event->window) / 2) button_press_timeout_side = 2;
		else button_press_timeout_side = 1;
		button_press_timeout_id = g_timeout_add(250, keypad_long_press_timeout, NULL);
		return FALSE;
	}
	if(event->type == GDK_BUTTON_RELEASE && event->button == 1) {
		if(event->window && (event->x < 0 || event->y < 0 || event->x > gdk_window_get_width(event->window) || event->y > gdk_window_get_height(event->window))) return FALSE;
		if(event->window && event->x > gdk_window_get_width(event->window) / 2) {
			if(expression_history_index > -1) {
				expression_history_index--;
				dont_change_index = true;
				block_completion();
				if(expression_history_index < 0) {
					clear_expression_text();
				} else {
					set_expression_text(expression_history[expression_history_index].c_str());
				}
				unblock_completion();
				dont_change_index = false;
			}
		} else {
			if(expression_history_index + 1 < (int) expression_history.size()) {
				expression_history_index++;
				dont_change_index = true;
				block_completion();
				set_expression_text(expression_history[expression_history_index].c_str());
				unblock_completion();
				dont_change_index = false;
			}
		}
	}
	return FALSE;
}

gboolean on_keypad_button_button_event(GtkWidget *w, GdkEventButton *event, gpointer) {
	if(event->type == GDK_BUTTON_RELEASE && button_press_timeout_id != 0) {
		g_source_remove(button_press_timeout_id);
		button_press_timeout_id = 0;
		button_press_timeout_w = NULL;
		button_press_timeout_side = 0;
		button_press_timeout_done = false;
	} else if(event->type == GDK_BUTTON_RELEASE && button_press_timeout_done) {
		button_press_timeout_done = false;
		bool b_this = (button_press_timeout_w == w);
		button_press_timeout_w = NULL;
		button_press_timeout_side = 0;
		if(b_this) return TRUE;
	}
	if(event->type == GDK_BUTTON_PRESS && event->button == 1) {
		button_press_timeout_w = w;
		button_press_timeout_side = 0;
		button_press_timeout_id = g_timeout_add(500, keypad_long_press_timeout, NULL);
		return FALSE;
	}
	if(event->type == GDK_BUTTON_RELEASE && (event->button == 2 || event->button == 3)) {
		if(on_keypad_button_alt(w, event->button == 2)) return TRUE;
	}
	return FALSE;
}

gboolean on_keypad_menu_button_button_event(GtkWidget *w, GdkEventButton *event, gpointer data) {
	if(event->type == GDK_BUTTON_RELEASE && button_press_timeout_id != 0) {
		g_source_remove(button_press_timeout_id);
		button_press_timeout_id = 0;
		button_press_timeout_w = NULL;
		button_press_timeout_side = 0;
		button_press_timeout_done = false;
	} else if(event->type == GDK_BUTTON_RELEASE && button_press_timeout_done) {
		button_press_timeout_done = false;
		bool b_this = (button_press_timeout_w == w);
		button_press_timeout_w = NULL;
		button_press_timeout_side = 0;
		if(b_this) return TRUE;
	}
	if(event->type == GDK_BUTTON_PRESS && event->button == 1) {
		button_press_timeout_w = w;
		button_press_timeout_side = 0;
		button_press_timeout_id = g_timeout_add(500, keypad_long_press_timeout, data);
		return FALSE;
	}
	bool b = (event->type == GDK_BUTTON_RELEASE && (event->button == 2 || event->button == 3));
	if(b) {
		if(GTK_WIDGET(data) == GTK_WIDGET(gtk_builder_get_object(main_builder, "menu_to"))) {
			if(b_busy) return TRUE;
			update_mb_to_menu();
		}
#if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 22
		gtk_menu_popup_at_pointer(GTK_MENU(data), (GdkEvent*) event);
#else
		gtk_menu_popup(GTK_MENU(data), NULL, NULL, NULL, NULL, event->button, event->time);
#endif
		return TRUE;
	}
	return FALSE;
}


/*
	Button clicked -- insert text (1,2,3,... +,-,...)
*/
void on_button_zero_clicked(GtkButton*, gpointer) {
	insert_text("0");
}
void on_button_one_clicked(GtkButton*, gpointer) {
	insert_text("1");
}
void on_button_two_clicked(GtkButton*, gpointer) {
	insert_text("2");
}
void on_button_three_clicked(GtkButton*, gpointer) {
	insert_text("3");
}
void on_button_four_clicked(GtkButton*, gpointer) {
	insert_text("4");
}
void on_button_five_clicked(GtkButton*, gpointer) {
	insert_text("5");
}
void on_button_six_clicked(GtkButton*, gpointer) {
	insert_text("6");
}
void on_button_seven_clicked(GtkButton*, gpointer) {
	insert_text("7");
}
void on_button_eight_clicked(GtkButton*, gpointer) {
	insert_text("8");
}
void on_button_nine_clicked(GtkButton*, gpointer) {
	insert_text("9");
}
void on_button_a_clicked(GtkButton*, gpointer) {
	insert_text(printops.lower_case_numbers ? "a" : "A");
}
void on_button_b_clicked(GtkButton*, gpointer) {
	insert_text(printops.lower_case_numbers ? "b" : "B");
}
void on_button_c_clicked(GtkButton*, gpointer) {
	insert_text(printops.lower_case_numbers ? "c" : "C");
}
void on_button_d_clicked(GtkButton*, gpointer) {
	insert_text(printops.lower_case_numbers ? "d" : "D");
}
void on_button_e_clicked(GtkButton*, gpointer) {
	insert_text(printops.lower_case_numbers ? "e" : "E");
}
void on_button_f_clicked(GtkButton*, gpointer) {
	insert_text(printops.lower_case_numbers ? "f" : "F");
}
void on_button_dot_clicked(GtkButton*, gpointer) {
	insert_text(CALCULATOR->getDecimalPoint().c_str());
}
void on_button_brace_open_clicked(GtkButton*, gpointer) {
	insert_text("(");
}
void on_button_brace_close_clicked(GtkButton*, gpointer) {
	insert_text(")");
}
void on_button_brace_wrap_clicked(GtkButton*, gpointer) {
	string expr = get_expression_text();
	GtkTextIter istart, iend, ipos;
	gint il = expr.length();
	if(il == 0) {
		set_expression_text("()");
		gtk_text_buffer_get_start_iter(expressionbuffer, &istart);
		gtk_text_iter_forward_char(&istart);
		gtk_text_buffer_place_cursor(expressionbuffer, &istart);
		return;
	}
	GtkTextMark *mpos = gtk_text_buffer_get_insert(expressionbuffer);
	gtk_text_buffer_get_iter_at_mark(expressionbuffer, &ipos, mpos);
	gtk_text_buffer_get_start_iter(expressionbuffer, &istart);
	iend = istart;
	bool goto_start = false;
	if(gtk_text_buffer_get_has_selection(expressionbuffer)) {
		GtkTextMark *mstart = gtk_text_buffer_get_selection_bound(expressionbuffer);
		gtk_text_buffer_get_iter_at_mark(expressionbuffer, &istart, mstart);
		if(gtk_text_iter_compare(&istart, &ipos) > 0) {
			iend = istart;
			istart = ipos;
		} else {
			iend = ipos;
		}
	} else {
		iend = ipos;
		if(!gtk_text_iter_is_start(&iend)) {
			gchar *gstr = gtk_text_buffer_get_text(expressionbuffer, &istart, &iend, FALSE);
			string str = CALCULATOR->unlocalizeExpression(gstr, evalops.parse_options);
			g_free(gstr);
			CALCULATOR->parseSigns(str);
			if(str.empty() || is_in(OPERATORS SPACES SEXADOT DOT LEFT_VECTOR_WRAP LEFT_PARENTHESIS COMMAS, str[str.length() - 1])) {
				istart = iend;
				gtk_text_buffer_get_end_iter(expressionbuffer, &iend);
				if(gtk_text_iter_compare(&istart, &iend) < 0) {
					gstr = gtk_text_buffer_get_text(expressionbuffer, &istart, &iend, FALSE);
					str = CALCULATOR->unlocalizeExpression(gstr, evalops.parse_options);
					g_free(gstr);
					CALCULATOR->parseSigns(str);
					if(str.empty() || (is_in(OPERATORS SPACES SEXADOT DOT RIGHT_VECTOR_WRAP LEFT_PARENTHESIS RIGHT_PARENTHESIS COMMAS, str[0]) && str[0] != MINUS_CH)) {
						iend = istart;
					}
				}
			}
		} else {
			goto_start = true;
			gtk_text_buffer_get_end_iter(expressionbuffer, &iend);
			gchar *gstr = gtk_text_buffer_get_text(expressionbuffer, &istart, &iend, FALSE);
			string str = CALCULATOR->unlocalizeExpression(gstr, evalops.parse_options);
			g_free(gstr);
			CALCULATOR->parseSigns(str);
			if(str.empty() || (is_in(OPERATORS SPACES SEXADOT DOT RIGHT_VECTOR_WRAP LEFT_PARENTHESIS RIGHT_PARENTHESIS COMMAS, str[0]) && str[0] != MINUS_CH)) {
				iend = istart;
			}
		}
	}
	if(gtk_text_iter_compare(&istart, &iend) >= 0) {
		gtk_text_buffer_insert(expressionbuffer, &istart, "()", -1);
		gtk_text_iter_backward_char(&istart);
		gtk_text_buffer_place_cursor(expressionbuffer, &istart);
		return;
	}
	gchar *gstr = gtk_text_buffer_get_text(expressionbuffer, &istart, &iend, FALSE);
	GtkTextMark *mstart = gtk_text_buffer_create_mark(expressionbuffer, "istart", &istart, TRUE);
	GtkTextMark *mend = gtk_text_buffer_create_mark(expressionbuffer, "iend", &iend, FALSE);
	add_to_undo = false;
	gtk_text_buffer_insert(expressionbuffer, &istart, "(", -1);
	gtk_text_buffer_get_iter_at_mark(expressionbuffer, &iend, mend);
	add_to_undo = true;
	gtk_text_buffer_insert(expressionbuffer, &iend, ")", -1);
	gtk_text_buffer_get_iter_at_mark(expressionbuffer, &istart, mstart);
	gtk_text_buffer_delete_mark(expressionbuffer, mstart);
	gtk_text_buffer_delete_mark(expressionbuffer, mend);
	string str = CALCULATOR->unlocalizeExpression(gstr, evalops.parse_options);
	g_free(gstr);
	CALCULATOR->parseSigns(str);
	if(str.empty() || is_in(OPERATORS SPACES SEXADOT DOT LEFT_VECTOR_WRAP LEFT_PARENTHESIS COMMAS, str[str.length() - 1])) {
		gtk_text_iter_backward_char(&iend);
		goto_start = false;
	}
	gtk_text_buffer_place_cursor(expressionbuffer, goto_start ? &istart : &iend);
}
void on_button_i_clicked(GtkButton*, gpointer) {
	insert_var(CALCULATOR->v_i);
}
void on_button_percent_clicked(GtkButton*, gpointer) {
	insert_text("%");
}
void on_button_si_clicked(GtkButton*, gpointer) {
	if(latest_button_unit) {
		insert_button_unit(NULL, (gpointer) latest_button_unit);
	} else {
		insert_text("kg");
	}
}
void on_button_euro_clicked(GtkButton*, gpointer) {
	if(latest_button_currency) {
		insert_button_currency(NULL, (gpointer) latest_button_currency);
	} else {
		insert_text("€");
	}
}

void on_button_to_clicked(GtkButton*, gpointer) {
	GtkTextIter istart, iend;
	if(gtk_text_buffer_get_has_selection(expressionbuffer)) {
		gtk_text_buffer_get_bounds(expressionbuffer, &istart, &iend);
		gtk_text_buffer_select_range(expressionbuffer, &iend, &iend);
	}
	gtk_text_buffer_get_start_iter(expressionbuffer, &istart);
	gtk_text_buffer_get_end_iter(expressionbuffer, &iend);
	gchar *gstr = gtk_text_buffer_get_text(expressionbuffer, &istart, &iend, FALSE);
	string to_str = CALCULATOR->localToString();
	remove_blank_ends(to_str);
	to_str += ' ';
	if(strlen(gstr) > 0 && gstr[strlen(gstr) - 1] != ' ') to_str.insert(0, " ");
	insert_text(to_str.c_str());
	g_free(gstr);
}
void on_button_new_function_clicked(GtkButton*, gpointer) {
	edit_function_simple("", NULL, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")));
}
void on_button_fac_clicked(GtkButton*, gpointer) {
	if(rpn_mode || evalops.parse_options.rpn || is_at_beginning_of_expression()) {
		insertButtonFunction(CALCULATOR->f_factorial);
	}
	bool do_exec = wrap_expression_selection(NULL, true);
	insert_text("!");
	if(do_exec) execute_expression();
}
void on_button_comma_clicked(GtkButton*, gpointer) {
	insert_text(CALCULATOR->getComma().c_str());
}
void on_button_x_clicked(GtkButton*, gpointer) {
	insert_text("x");
}
void on_button_y_clicked(GtkButton*, gpointer) {
	insert_text("y");
}
void on_button_z_clicked(GtkButton*, gpointer) {
	insert_text("z");
}
void on_button_xequals_clicked(GtkButton*, gpointer) {
	insert_text("=");
}
void on_button_plusminus_clicked(GtkButton*, gpointer) {
	wrap_expression_selection();
	insert_text("±");
}
void on_button_factorize_clicked(GtkButton*, gpointer) {
	if(evalops.structuring == STRUCTURING_FACTORIZE) executeCommand(COMMAND_EXPAND);
	else executeCommand(COMMAND_FACTORIZE);
}
void on_button_factorize2_clicked(GtkButton*, gpointer) {
	executeCommand(COMMAND_FACTORIZE);
}
void insert_angle_symbol() {
	insert_text("∠");
}
void insert_left_shift() {
	if(!evalops.parse_options.rpn) wrap_expression_selection();
	insert_text("<<");
}
void insert_right_shift() {
	if(!evalops.parse_options.rpn) wrap_expression_selection();
	insert_text(">>");
}
void insert_bitwise_and() {
	if(rpn_mode) {calculateRPN(OPERATION_BITWISE_AND); return;}
	if(!evalops.parse_options.rpn) wrap_expression_selection();
	insert_text("&");
}
void insert_bitwise_or() {
	if(rpn_mode) {calculateRPN(OPERATION_BITWISE_OR); return;}
	if(!evalops.parse_options.rpn) wrap_expression_selection();
	insert_text("|");
}
void insert_bitwise_xor() {
	if(rpn_mode) {calculateRPN(OPERATION_BITWISE_XOR); return;}
	if(!evalops.parse_options.rpn) wrap_expression_selection();
	insert_text(" xor ");
}
void insert_bitwise_not() {
	if(rpn_mode) {
		if(expression_has_changed) {
			if(get_expression_text().find_first_not_of(SPACES) != string::npos) {
				execute_expression(true);
			}
		}
		execute_expression(true, false, OPERATION_ADD, NULL, false, 0, "~");
		return;
	}
	if(!evalops.parse_options.rpn && wrap_expression_selection("~")) return;
	insert_text("~");
}

void on_button_add_clicked(GtkButton*, gpointer) {
	if(rpn_mode) {
		calculateRPN(OPERATION_ADD);
		return;
	}
	if(!evalops.parse_options.rpn) {
		wrap_expression_selection();
	}
	insert_text(expression_add_sign());
}

void on_button_sub_clicked(GtkButton*, gpointer) {
	if(rpn_mode) {
		calculateRPN(OPERATION_SUBTRACT);
		return;
	}
	if(!evalops.parse_options.rpn) {
		wrap_expression_selection();
	}
	insert_text(expression_sub_sign());
}
void on_button_times_clicked(GtkButton*, gpointer) {
	if(rpn_mode) {
		calculateRPN(OPERATION_MULTIPLY);
		return;
	}
	if(!evalops.parse_options.rpn) {
		wrap_expression_selection();
	}
	insert_text(expression_times_sign());
}
void on_button_divide_clicked(GtkButton*, gpointer) {
	if(rpn_mode) {
		calculateRPN(OPERATION_DIVIDE);
		return;
	}
	if(!evalops.parse_options.rpn) {
		wrap_expression_selection();
	}
	insert_text(expression_divide_sign());
}
void on_button_ans_clicked(GtkButton*, gpointer) {
	insert_text(vans[0]->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext).name.c_str());
}
void on_button_exp_clicked(GtkButton*, gpointer) {
	if(rpn_mode) {
		calculateRPN(OPERATION_EXP10);
		return;
	}
	if((!evalops.parse_options.rpn && wrap_expression_selection()) || (evalops.parse_options.base != 10 && evalops.parse_options.base >= 2)) {
		insert_text((expression_times_sign() + i2s(evalops.parse_options.base) + "^").c_str());
	} else {
		if(printops.lower_case_e) insert_text("e");
		else insert_text("E");
	}
}
void on_button_xy_clicked(GtkButton*, gpointer) {
	if(rpn_mode) {
		calculateRPN(OPERATION_RAISE);
		return;
	}
	if(!evalops.parse_options.rpn) {
		wrap_expression_selection();
	}
	insert_text("^");
}
void on_button_square_clicked() {
	if(rpn_mode) {
		calculateRPN(CALCULATOR->f_sq);
		return;
	}
	if(evalops.parse_options.rpn) {
		insertButtonFunction(CALCULATOR->f_sq);
	} else {
		wrap_expression_selection();
		if(printops.use_unicode_signs && can_display_unicode_string_function(SIGN_POWER_2, (void*) expressiontext)) insert_text(SIGN_POWER_2);
		else insert_text("^2");
	}
}

/*
	Button clicked -- insert corresponding function
*/
void on_button_sqrt_clicked(GtkButton*, gpointer) {
	insertButtonFunction(CALCULATOR->f_sqrt);
}
void on_button_log_clicked(GtkButton*, gpointer) {
	MathFunction *f = CALCULATOR->getActiveFunction("log10");
	if(f) {
		insertButtonFunction(f);
	} else {
		show_message(_("log10 function not found."), GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")));
	}
}
void on_button_ln_clicked(GtkButton*, gpointer) {
	insertButtonFunction(CALCULATOR->f_ln);
}

/*
	Buttons to the left of the RPN stack clicked
*/
void on_button_rpn_add_clicked(GtkButton*, gpointer) {
	calculateRPN(OPERATION_ADD);
}
void on_button_rpn_sub_clicked(GtkButton*, gpointer) {
	calculateRPN(OPERATION_SUBTRACT);
}
void on_button_rpn_times_clicked(GtkButton*, gpointer) {
	calculateRPN(OPERATION_MULTIPLY);
}
void on_button_rpn_divide_clicked(GtkButton*, gpointer) {
	calculateRPN(OPERATION_DIVIDE);
}
void on_button_rpn_xy_clicked(GtkButton*, gpointer) {
	calculateRPN(OPERATION_RAISE);
}
void on_button_rpn_sqrt_clicked(GtkButton*, gpointer) {
	insertButtonFunction(CALCULATOR->f_sqrt);
}
void on_button_rpn_reciprocal_clicked(GtkButton*, gpointer) {
	insertButtonFunction(CALCULATOR->getActiveFunction("inv"));
}
void on_button_rpn_negate_clicked(GtkButton*, gpointer) {
	insertButtonFunction(CALCULATOR->getActiveFunction("neg"));
}
void on_button_rpn_sum_clicked(GtkButton*, gpointer) {
	insertButtonFunction(CALCULATOR->f_total);
}
#define INDEX_TYPE_ANS 0
#define INDEX_TYPE_XPR 1
#define INDEX_TYPE_TXT 2
void process_history_selection(vector<size_t> *selected_rows, vector<size_t> *selected_indeces, vector<int> *selected_index_type, bool ans_priority = false) {
	GtkTreeModel *model;
	GtkTreeIter iter;
	GList *selected_list, *current_selected_list;
	gint index = -1, hindex = -1;
	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(historyview));
	selected_list = gtk_tree_selection_get_selected_rows(select, &model);
	current_selected_list = selected_list;
	while(current_selected_list) {
		gtk_tree_model_get_iter(model, &iter, (GtkTreePath*) current_selected_list->data);
		gtk_tree_model_get(model, &iter, 1, &hindex, 3, &index, -1);
		if(hindex >= 0) {
			if(selected_rows) selected_rows->push_back((size_t) hindex);
			if(selected_indeces && (index <= 0 || !evalops.parse_options.functions_enabled || evalops.parse_options.base > BASE_DECIMAL || evalops.parse_options.base < 0)) {
				if(inhistory_type[hindex] != QALCULATE_HISTORY_WARNING && inhistory_type[hindex] != QALCULATE_HISTORY_ERROR && (hindex < 1 || inhistory_type[hindex] != QALCULATE_HISTORY_TRANSFORMATION || inhistory_type[hindex - 1] == QALCULATE_HISTORY_RESULT || inhistory_type[hindex - 1] == QALCULATE_HISTORY_RESULT_APPROXIMATE)) {
					selected_indeces->push_back((size_t) hindex);
					selected_index_type->push_back(INDEX_TYPE_TXT);
				}
			} else if(selected_indeces && index > 0) {
				bool index_found = false;
				size_t i = selected_indeces->size();
				for(; i > 0; i--) {
					if(selected_index_type->at(i - 1) != INDEX_TYPE_TXT && selected_indeces->at(i - 1) == (size_t) index) {
						index_found = true;
						break;
					}
				}
				if(!index_found) selected_indeces->push_back(index);
				switch(inhistory_type[hindex]) {
					case QALCULATE_HISTORY_EXPRESSION: {}
					case QALCULATE_HISTORY_REGISTER_MOVED: {}
					case QALCULATE_HISTORY_PARSE: {}
					case QALCULATE_HISTORY_PARSE_APPROXIMATE: {}
					case QALCULATE_HISTORY_RPN_OPERATION: {
						if(!index_found) selected_index_type->push_back(INDEX_TYPE_XPR);
						else if(!ans_priority) selected_index_type->at(i - 1) = INDEX_TYPE_XPR;
						break;
					}
					default: {
						if(!index_found) selected_index_type->push_back(INDEX_TYPE_ANS);
						else if(ans_priority) selected_index_type->at(i - 1) = INDEX_TYPE_ANS;
					}
				}
			}
		}
		current_selected_list = current_selected_list->next;
	}
	if(selected_list) g_list_free_full(selected_list, (GDestroyNotify) gtk_tree_path_free);
}
void history_operator(string str_sign) {
	if(b_busy) return;
	vector<size_t> selected_indeces;
	vector<int> selected_index_type;
	process_history_selection(NULL, &selected_indeces, &selected_index_type);
	if(rpn_mode && !expression_is_empty()) execute_expression();
	if(selected_indeces.empty()) {
		if(rpn_mode) {
			add_to_undo = false;
			insert_text(str_sign.c_str());
			add_to_undo = true;
			execute_expression();
			return;
		}
		if(!evalops.parse_options.rpn) {
			wrap_expression_selection();
		}
		insert_text(str_sign.c_str());
		return;
	}
	bool only_one_value = false;
	string str;
	if(selected_indeces.size() == 1) {
		str = get_selected_expression_text(true);
		if(str.empty()) {
			only_one_value = true;
		} else {
			string search_s = CALCULATOR->getDecimalPoint() + NUMBER_ELEMENTS;
			if((str.length() < 2 || str[0] != '(' || str[str.length() - 1] != ')') && str.find_first_not_of(search_s) != string::npos) {
				str.insert(str.begin(), '(');
				str += ')';
			}
			if(evalops.parse_options.rpn) str += ' ';
			else str += str_sign;
		}
	}
	
	for(size_t i = 0; i < selected_indeces.size(); i++) {
		if(i > 0) {
			if(evalops.parse_options.rpn) str += ' ';
			else str += str_sign;
		}
		if(selected_index_type[i] == INDEX_TYPE_TXT) {
			int index = selected_indeces[i];
			if(index > 0 && inhistory_type[index] == QALCULATE_HISTORY_TRANSFORMATION) index--;
			string search_s = CALCULATOR->getDecimalPoint() + NUMBER_ELEMENTS;
			if((inhistory[index].length() >= 2 && inhistory[index][0] == '(' && inhistory[index][inhistory[index].length() - 1] == ')') || inhistory[index].find_first_not_of(search_s) == string::npos) {
				str += inhistory[index];
			} else {
				str += '(';
				str += inhistory[index];
				str += ')';
			}
		} else {
			const ExpressionName *ename = NULL;
			if(selected_index_type[i] == INDEX_TYPE_XPR) ename = &f_expression->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext);
			else ename = &f_answer->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext);
			str += ename->name;
			str += '(';
			Number nr(selected_indeces[i], 1);
			str += print_with_evalops(nr);
			str += ')';
		}
	}
	if(only_one_value && !evalops.parse_options.rpn && !rpn_mode) {
		str += str_sign;
	}
	if(evalops.parse_options.rpn) {
		str += ' ';
		if(selected_indeces.size() == 1) {
			str += str_sign;
		} else {
			for(size_t i = 0; i < selected_indeces.size() - 1; i++) {
				str += str_sign;
			}
		}
	}
	add_to_undo = false;
	gtk_text_buffer_set_text(expressionbuffer, "", -1);
	add_to_undo = true;
	insert_text(str.c_str());
	if(!only_one_value) {
		execute_expression();
	} else if(rpn_mode) {
		execute_expression();
		add_to_undo = false;
		insert_text(str_sign.c_str());
		add_to_undo = true;
		execute_expression();
	}

}

void on_button_history_add_clicked(GtkButton*, gpointer) {
	history_operator(expression_add_sign());
}
void on_button_history_sub_clicked(GtkButton*, gpointer) {
	history_operator(expression_sub_sign());
}
void on_button_history_times_clicked(GtkButton*, gpointer) {
	history_operator(expression_times_sign());
}
void on_button_history_divide_clicked(GtkButton*, gpointer) {
	history_operator(expression_divide_sign());
}
void on_button_history_xy_clicked(GtkButton*, gpointer) {
	history_operator("^");
}
void on_button_history_sqrt_clicked(GtkButton*, gpointer) {
	if(b_busy) return;
	vector<size_t> selected_indeces;
	vector<int> selected_index_type;
	process_history_selection(NULL, &selected_indeces, &selected_index_type);
	if(selected_indeces.empty()) {
		insertButtonFunction(CALCULATOR->f_sqrt);
		return;
	}	
	const ExpressionName *ename2 = &CALCULATOR->f_sqrt->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext);
	string str = ename2->name;
	str += "(";
	if(selected_index_type[0] == INDEX_TYPE_TXT) {
		int index = selected_indeces[0];
		if(index > 0 && inhistory_type[index] == QALCULATE_HISTORY_TRANSFORMATION) index--;
		str += inhistory[index];
	} else {
		const ExpressionName *ename = NULL;
		if(selected_index_type[0] == INDEX_TYPE_XPR) ename = &f_expression->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext);
		else ename = &f_answer->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext);
		str += ename->name;
		str += "(";
		Number nr(selected_indeces[0], 1);
		str += print_with_evalops(nr);
		str += ")";
	}
	str += ")";
	add_to_undo = false;
	gtk_text_buffer_set_text(expressionbuffer, "", -1);
	add_to_undo = true;
	insert_text(str.c_str());
	execute_expression();
}
void on_button_history_insert_value_clicked(GtkButton*, gpointer) {
	if(b_busy) return;
	vector<size_t> selected_indeces;
	vector<int> selected_index_type;
	process_history_selection(NULL, &selected_indeces, &selected_index_type);
	if(selected_indeces.empty() || selected_index_type[0] == INDEX_TYPE_TXT) return;
	if(selected_indeces.size() > 1) {
		selected_indeces.clear();
		selected_index_type.clear();
		process_history_selection(NULL, &selected_indeces, &selected_index_type, true);
	}
	const ExpressionName *ename = NULL;
	if(selected_index_type[0] == INDEX_TYPE_XPR && (selected_indeces.size() == 1 || selected_index_type[1] == INDEX_TYPE_XPR)) ename = &f_expression->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext);
	else ename = &f_answer->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext);
	string str = ename->name;
	str += "(";
	for(size_t i = 0; i < selected_indeces.size(); i++) {
		if(selected_index_type[i] != INDEX_TYPE_TXT) {
			if(i > 0) {str += CALCULATOR->getComma(); str += ' ';}
			Number nr(selected_indeces[i], 1);
			str += print_with_evalops(nr);
		}
	}
	str += ")";
	if(rpn_mode) {
		add_to_undo = false;
		insert_text(str.c_str());
		add_to_undo = true;
		execute_expression();
	} else {
		insert_text(str.c_str());
	}
}
void on_button_history_insert_text_clicked(GtkButton*, gpointer) {
	if(b_busy) return;
	vector<size_t> selected_rows;
	process_history_selection(&selected_rows, NULL, NULL);
	if(selected_rows.empty()) return;
	int index = selected_rows[0];
	if(index > 0 && ((inhistory_type[index] == QALCULATE_HISTORY_TRANSFORMATION && (inhistory_type[index - 1] == QALCULATE_HISTORY_RESULT || inhistory_type[index - 1] == QALCULATE_HISTORY_RESULT_APPROXIMATE)) || inhistory_type[index] == QALCULATE_HISTORY_RPN_OPERATION || inhistory_type[index] == QALCULATE_HISTORY_REGISTER_MOVED)) index--;
	else if((size_t) index < inhistory_type.size() - 1 && HISTORY_IS_PARSE(index) && inhistory_type[index + 1] == QALCULATE_HISTORY_EXPRESSION) index++;
	insert_text(inhistory[index].c_str());
}
void on_button_history_insert_parsed_text_clicked(GtkButton*, gpointer) {
	if(b_busy) return;
	vector<size_t> selected_rows;
	process_history_selection(&selected_rows, NULL, NULL);
	if(selected_rows.empty()) return;
	int index = selected_rows[0];
	if(index > 0 && ((inhistory_type[index] == QALCULATE_HISTORY_TRANSFORMATION && (inhistory_type[index - 1] == QALCULATE_HISTORY_RESULT || inhistory_type[index - 1] == QALCULATE_HISTORY_RESULT_APPROXIMATE)) || inhistory_type[index] == QALCULATE_HISTORY_RPN_OPERATION || inhistory_type[index] == QALCULATE_HISTORY_REGISTER_MOVED)) index--;
	else if(index > 0 && inhistory_type[index] == QALCULATE_HISTORY_EXPRESSION && HISTORY_IS_PARSE(index - 1)) index--;
	insert_text(inhistory[index].c_str());
}
void history_copy(bool full_text) {
	if(b_busy) return;
	vector<size_t> selected_rows;
	process_history_selection(&selected_rows, NULL, NULL);
	if(selected_rows.empty()) return;
	if(!full_text && selected_rows.size() == 1) {
		int index = selected_rows[0];
		if(index > 0 && ((inhistory_type[index] == QALCULATE_HISTORY_TRANSFORMATION && (inhistory_type[index - 1] == QALCULATE_HISTORY_RESULT || inhistory_type[index - 1] == QALCULATE_HISTORY_RESULT_APPROXIMATE)) || inhistory_type[index] == QALCULATE_HISTORY_RPN_OPERATION || inhistory_type[index] == QALCULATE_HISTORY_REGISTER_MOVED)) index--;
		else if((size_t) index < inhistory_type.size() - 1 && (inhistory_type[index] == QALCULATE_HISTORY_PARSE || inhistory_type[index] == QALCULATE_HISTORY_PARSE_WITHEQUALS || inhistory_type[index] == QALCULATE_HISTORY_PARSE_APPROXIMATE) && inhistory_type[index + 1] == QALCULATE_HISTORY_EXPRESSION) index++;
		string copy_text = inhistory[index];
		if(!copy_separator) {
			remove_separator(copy_text);
		}
		gtk_clipboard_set_text(gtk_clipboard_get(gdk_atom_intern("CLIPBOARD", FALSE)), copy_text.c_str(), -1);
	} else {
		string str;
		int hindex = 0;
		for(size_t i = 0; i < selected_rows.size(); i++) {
			if(i > 0) str += '\n';
			hindex = selected_rows[i];
			if((size_t) hindex < inhistory_type.size() - 1 && (inhistory_type[hindex] == QALCULATE_HISTORY_PARSE || inhistory_type[hindex] == QALCULATE_HISTORY_PARSE_WITHEQUALS || inhistory_type[hindex] == QALCULATE_HISTORY_PARSE_APPROXIMATE) && (inhistory_type[hindex + 1] == QALCULATE_HISTORY_EXPRESSION || inhistory_type[hindex + 1] == QALCULATE_HISTORY_REGISTER_MOVED || inhistory_type[hindex + 1] == QALCULATE_HISTORY_RPN_OPERATION)) hindex++;
			on_button_history_copy_add_hindex:
			bool add_parse = false;
			switch(inhistory_type[hindex]) {
				case QALCULATE_HISTORY_EXPRESSION: {
					if(i > 0) str += '\n';
					str += inhistory[hindex];
					add_parse = true;
					break;
				}
				case QALCULATE_HISTORY_REGISTER_MOVED: {
					if(i > 0) str += '\n';
					str += _("RPN Register Moved");
					add_parse = true;
					break;
				}
				case QALCULATE_HISTORY_RPN_OPERATION: {
					if(i > 0) str += '\n';
					str += _("RPN Operation");
					add_parse = true;
					break;
				}
				case QALCULATE_HISTORY_TRANSFORMATION: {
					str += inhistory[hindex];
					str += ": ";
					if(hindex > 0 && (inhistory_type[hindex - 1] == QALCULATE_HISTORY_RESULT || inhistory_type[hindex - 1] == QALCULATE_HISTORY_RESULT_APPROXIMATE)) {
						hindex--;
						goto on_button_history_copy_add_hindex;
					}
					break;
				}
				case QALCULATE_HISTORY_PARSE: {str += " ";}
				case QALCULATE_HISTORY_RESULT: {
					str += "= ";
					str += inhistory[hindex];
					break;
				}
				case QALCULATE_HISTORY_PARSE_APPROXIMATE: {str += " ";}
				case QALCULATE_HISTORY_RESULT_APPROXIMATE: {
					if(printops.use_unicode_signs && can_display_unicode_string_function(SIGN_ALMOST_EQUAL, (void*) historyview)) {
						str += SIGN_ALMOST_EQUAL " ";
					} else {
						str += "= ";
						str += _("approx.");
						str += " ";
					}
					str += inhistory[hindex];
					break;
				}
				case QALCULATE_HISTORY_PARSE_WITHEQUALS: {
					str += " ";
					str += inhistory[hindex];
					break;
				}
				case QALCULATE_HISTORY_WARNING: {}
				case QALCULATE_HISTORY_ERROR: {}
				case QALCULATE_HISTORY_OLD: {
					str += inhistory[hindex];
					break;
				}
				case QALCULATE_HISTORY_BOOKMARK: {break;}
			}
			if(add_parse && hindex > 0 && (inhistory_type[hindex - 1] == QALCULATE_HISTORY_PARSE || inhistory_type[hindex - 1] == QALCULATE_HISTORY_PARSE_APPROXIMATE || inhistory_type[hindex - 1] == QALCULATE_HISTORY_PARSE_WITHEQUALS)) {
				hindex--;
				goto on_button_history_copy_add_hindex;
			}
		}
		if(!copy_separator) {
			remove_separator(str);
		}
		gtk_clipboard_set_text(gtk_clipboard_get(gdk_atom_intern("CLIPBOARD", FALSE)), str.c_str(), -1);
	}
}
void on_button_history_copy_clicked(GtkButton*, gpointer) {
	history_copy(false);
}
bool history_protected_by_bookmark(size_t hi);
bool history_protected(size_t hi);
void on_popup_menu_item_history_clear_activate(GtkMenuItem*, gpointer) {
	if(b_busy) return;
	gtk_list_store_clear(historystore);
	bool b_protected = false;
	for(size_t i = inhistory.size(); i > 0;) {
		--i;
		if(inhistory_type[i] == QALCULATE_HISTORY_EXPRESSION || inhistory_type[i] == QALCULATE_HISTORY_RPN_OPERATION || inhistory_type[i] == QALCULATE_HISTORY_REGISTER_MOVED || inhistory_type[i] == QALCULATE_HISTORY_OLD) {
			b_protected = (inhistory_type[i] != QALCULATE_HISTORY_OLD && (inhistory_protected[i] || history_protected_by_bookmark(i)));
		}
		if(!b_protected && inhistory_type[i] != QALCULATE_HISTORY_BOOKMARK) {
			inhistory.erase(inhistory.begin() + i);
			inhistory_type.erase(inhistory_type.begin() + i);
			inhistory_protected.erase(inhistory_protected.begin() + i);
			inhistory_value.erase(inhistory_value.begin() + i);
		}
	}
	current_inhistory_index = inhistory.size() - 1;
	history_index = inhistory.size() - 1;
	initial_inhistory_index = inhistory.size() - 1;
	on_expressionbuffer_changed(expressionbuffer, NULL);
	reload_history();
}
void on_popup_menu_item_history_movetotop_activate(GtkMenuItem*, gpointer) {
	if(b_busy) return;
	GtkTreeModel *model;
	GtkTreeIter iter, iter_first;
	GList *selected_list;
	gint hindex = -1, hindex2 = -1;
	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(historyview));
	selected_list = gtk_tree_selection_get_selected_rows(select, &model);
	if(!selected_list) return;
	GList *list_i = g_list_last(selected_list);
	vector<int> indexes;
	while(list_i) {
		gtk_tree_model_get_iter(model, &iter, (GtkTreePath*) list_i->data);
		gtk_tree_model_get(model, &iter, 1, &hindex, -1);
		list_i = list_i->prev;
		if(hindex > 0) {
			if(inhistory_type[hindex] == QALCULATE_HISTORY_OLD) {
				indexes.push_back(hindex);
				gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
			} else {
				iter_first = iter;
				while(gtk_tree_model_iter_next(model, &iter)) {
					gtk_tree_model_get(model, &iter, 1, &hindex, -1);
					if(hindex < 0 || ITEM_IS_EXPRESSION(hindex) || inhistory_type[hindex] == QALCULATE_HISTORY_OLD || inhistory_type[hindex] == QALCULATE_HISTORY_BOOKMARK) {
						if(hindex < 0) {
							gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
						}
						break;
					}
					iter_first = iter;
				}
				iter = iter_first;
				do {
					if(list_i) {
						GtkTreePath *path = gtk_tree_model_get_path(model, &iter);
						if(gtk_tree_path_compare(path, (GtkTreePath*) list_i->data) == 0) list_i = list_i->prev;
						gtk_tree_path_free(path);
					}
					gtk_tree_model_get(model, &iter, 1, &hindex, -1);
					if(inhistory_type[hindex] == QALCULATE_HISTORY_TRANSFORMATION) indexes.push_back(hindex - 1);
					indexes.push_back(hindex);
					if(HISTORY_IS_PARSE(hindex)) {indexes.push_back(hindex + 1); hindex++;}
					gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
					if(hindex < 0 || ITEM_IS_EXPRESSION(hindex) || inhistory_type[hindex] == QALCULATE_HISTORY_OLD || inhistory_type[hindex] == QALCULATE_HISTORY_BOOKMARK) {
						if(hindex >= 0 && inhistory_type[hindex] != QALCULATE_HISTORY_BOOKMARK && gtk_tree_model_iter_previous(model, &iter)) {
							gtk_tree_model_get(model, &iter, 1, &hindex, -1);
							if(hindex >= 0 && inhistory_type[hindex] == QALCULATE_HISTORY_BOOKMARK) {
								gtk_tree_model_iter_next(model, &iter);
							} else {
								break;
							}
						} else {
							break;
						}
					}
				} while(gtk_tree_model_iter_previous(model, &iter));
			}
		} else {
			gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
		}
	}
	unordered_map<int, int> new_indexes;
	hindex2 = -1;
	int n = 0;
	for(size_t i = 0; i < indexes.size(); i++) {
		hindex = indexes[i];
		if(hindex >= 0) {
			while(hindex2 >= 0 && hindex2 < hindex) {
				new_indexes[hindex2] = hindex2 - n;
				hindex2++;
			}
			n++;
			hindex2 = hindex + 1;
		}
	}
	while(hindex2 >= 0 && hindex2 < (gint) inhistory.size()) {
		new_indexes[hindex2] = hindex2 - n;
		hindex2++;
	}
	hindex2 = indexes[0];
	if(gtk_tree_model_get_iter_first(model, &iter)) {
		do {
			gtk_tree_model_get(model, &iter, 1, &hindex, -1);
			if(hindex >= 0) {
				if(hindex < hindex2) break;
				gtk_list_store_set(GTK_LIST_STORE(model), &iter, 1, new_indexes[hindex], -1);
			}
		} while(gtk_tree_model_iter_next(model, &iter));
	}
	hindex2 = (gint) inhistory.size() - indexes.size() + 1;
	for(size_t i = 0; i < indexes.size(); i++) {
		hindex = indexes[i];
		inhistory.push_back(inhistory[hindex]);
		inhistory_protected.push_back(inhistory_protected[hindex]);
		inhistory_type.push_back(inhistory_type[hindex]);
		inhistory_value.push_back(inhistory_value[hindex]);
	}
	for(size_t i = indexes.size() - 1; ; i--) {
		hindex = indexes[i];
		inhistory.erase(inhistory.begin() + hindex);
		inhistory_protected.erase(inhistory_protected.begin() + hindex);
		inhistory_type.erase(inhistory_type.begin() + hindex);
		inhistory_value.erase(inhistory_value.begin() + hindex);
		if(i == 0) break;
	}
	current_inhistory_index = inhistory.size() - 1;
	history_index = inhistory.size() - 1;
	initial_inhistory_index = inhistory.size() - 1;
	on_expressionbuffer_changed(expressionbuffer, NULL);
	reload_history(hindex2);
	g_list_free_full(selected_list, (GDestroyNotify) gtk_tree_path_free);
}
void on_popup_menu_item_history_delete_activate(GtkMenuItem*, gpointer) {
	if(b_busy) return;
	GtkTreeModel *model;
	GtkTreeIter iter, iter2, iter3;
	GList *selected_list;
	gint hindex = -1, hindex2 = -1;
	bool del_prev = false;
	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(historyview));
	selected_list = gtk_tree_selection_get_selected_rows(select, &model);
	if(!selected_list) return;
	GList *list_i = g_list_last(selected_list);
	vector<int> indexes;
	while(list_i || del_prev) {
		if(list_i) {
			gtk_tree_model_get_iter(model, &iter, (GtkTreePath*) list_i->data);
			gtk_tree_model_get(model, &iter, 1, &hindex, -1);
		}
		if(del_prev && (!list_i || hindex != hindex2)) {
			gtk_list_store_remove(GTK_LIST_STORE(model), &iter2);
			if(HISTORY_IS_EXPRESSION(hindex2)) indexes.push_back(hindex2 - 1);
			indexes.push_back(hindex2);
			if(HISTORY_IS_PARSE(hindex2)) {indexes.push_back(hindex2 + 1); hindex2++;}
			if(hindex2 + 1 != hindex && (size_t) hindex2 + 1 < inhistory.size() && inhistory_type[hindex2 + 1] == QALCULATE_HISTORY_BOOKMARK) {
				if(gtk_tree_model_iter_previous(model, &iter2)) {
					indexes.push_back(hindex2);
					gtk_list_store_remove(GTK_LIST_STORE(model), &iter2);
				}
			}
		}
		if(!list_i) break;
		del_prev = false;
		if(hindex >= 0 && (ITEM_IS_EXPRESSION(hindex) || inhistory_type[hindex] == QALCULATE_HISTORY_BOOKMARK)) {
			iter3 = iter;
			if(inhistory_type[hindex] == QALCULATE_HISTORY_BOOKMARK) gtk_tree_model_iter_next(model, &iter3);
			bool b = false;
			while(gtk_tree_model_iter_next(model, &iter3)) {
				gtk_tree_model_get(model, &iter3, 1, &hindex2, -1);
				if(hindex2 >= 0 && (ITEM_IS_EXPRESSION(hindex2) || inhistory_type[hindex2] == QALCULATE_HISTORY_OLD)) break;
				b = true;
				iter2 = iter3;
			}
			if(b) {
				while(true) {
					gtk_tree_model_get(model, &iter2, 1, &hindex2, -1);
					if(hindex2 == hindex) break;
					if(hindex2 >= 0) {
						if(inhistory_type[hindex2] == QALCULATE_HISTORY_TRANSFORMATION) indexes.push_back(hindex2 - 1);
						indexes.push_back(hindex2);
					}
					iter3 = iter2;
					gtk_tree_model_iter_previous(model, &iter2);
					gtk_list_store_remove(GTK_LIST_STORE(model), &iter3);
				}
			}
			if(HISTORY_IS_EXPRESSION(hindex)) indexes.push_back(hindex - 1);
		} else if(hindex >= 0 && inhistory_type[hindex] != QALCULATE_HISTORY_OLD) {
			iter2 = iter;
			if(gtk_tree_model_iter_next(model, &iter2)) {
				gtk_tree_model_get(model, &iter2, 1, &hindex2, -1);
				if(hindex2 < 0 || ITEM_IS_EXPRESSION(hindex2) || inhistory_type[hindex2] == QALCULATE_HISTORY_OLD) {
					iter2 = iter;
					if(gtk_tree_model_iter_previous(model, &iter2)) {
						gtk_tree_model_get(model, &iter2, 1, &hindex2, -1);
						if(hindex2 >= 0 && (ITEM_IS_EXPRESSION(hindex2) || inhistory_type[hindex2] == QALCULATE_HISTORY_OLD)) {
							del_prev = true;
						}
					}
				}
			}
		}
		gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
		if(hindex >= 0) {
			if(inhistory_type[hindex] == QALCULATE_HISTORY_TRANSFORMATION) indexes.push_back(hindex - 1);
			indexes.push_back(hindex);
			if(HISTORY_IS_PARSE(hindex)) {indexes.push_back(hindex + 1); hindex++;}
			if(!del_prev && (size_t) hindex + 1 < inhistory.size() && inhistory_type[hindex + 1] == QALCULATE_HISTORY_BOOKMARK) {
				iter2 = iter;
				if(gtk_tree_model_iter_previous(model, &iter2)) {
					hindex2 = hindex + 1;
					del_prev = true;
				}
			}
		}
		list_i = list_i->prev;
	}
	unordered_map<int, int> new_indexes;
	hindex2 = -1;
	int n = 0;
	for(size_t i = 0; i < indexes.size(); i++) {
		hindex = indexes[i];
		if(hindex >= 0) {
			while(hindex2 >= 0 && hindex2 < hindex) {
				new_indexes[hindex2] = hindex2 - n;
				hindex2++;
			}
			n++;
			hindex2 = hindex + 1;
		}
	}
	while(hindex2 >= 0 && hindex2 < (gint) inhistory.size()) {
		new_indexes[hindex2] = hindex2 - n;
		hindex2++;
	}
	hindex2 = indexes[0];
	if(gtk_tree_model_get_iter_first(model, &iter)) {
		do {
			gtk_tree_model_get(model, &iter, 1, &hindex, -1);
			if(hindex >= 0) {
				if(hindex < hindex2) break;
				gtk_list_store_set(GTK_LIST_STORE(model), &iter, 1, new_indexes[hindex], -1);
			}
		} while(gtk_tree_model_iter_next(model, &iter));
	}
	for(size_t i = indexes.size() - 1; ; i--) {
		hindex = indexes[i];
		inhistory.erase(inhistory.begin() + hindex);
		inhistory_protected.erase(inhistory_protected.begin() + hindex);
		inhistory_type.erase(inhistory_type.begin() + hindex);
		inhistory_value.erase(inhistory_value.begin() + hindex);
		if(i == 0) break;
	}
	current_inhistory_index = inhistory.size() - 1;
	history_index = inhistory.size() - 1;
	initial_inhistory_index = inhistory.size() - 1;
	on_expressionbuffer_changed(expressionbuffer, NULL);
	g_list_free_full(selected_list, (GDestroyNotify) gtk_tree_path_free);
}
void on_popup_menu_item_history_insert_value_activate(GtkMenuItem*, gpointer) {
	on_button_history_insert_value_clicked(NULL, NULL);
}
void on_popup_menu_item_history_insert_text_activate(GtkMenuItem*, gpointer) {
	on_button_history_insert_text_clicked(NULL, NULL);
}
void on_popup_menu_item_history_insert_parsed_text_activate(GtkMenuItem*, gpointer) {
	on_button_history_insert_parsed_text_clicked(NULL, NULL);
}
void on_popup_menu_item_history_copy_text_activate(GtkMenuItem*, gpointer) {
	history_copy(false);
}
void on_popup_menu_item_history_copy_full_text_activate(GtkMenuItem*, gpointer) {
	history_copy(true);
}
bool find_history_bookmark(string str, GtkTreeIter *iter2) {
	GtkTreeIter iter;
	gint hindex = -1;
	if(!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(historystore), &iter)) return false;
	while(true) {
		gtk_tree_model_get(GTK_TREE_MODEL(historystore), &iter, 1, &hindex, -1);
		if(hindex >= 0 && inhistory_type[hindex] == QALCULATE_HISTORY_BOOKMARK && inhistory[hindex] == str) {
			*iter2 = iter;
			return true;
		}
		if(!gtk_tree_model_iter_next(GTK_TREE_MODEL(historystore), &iter)) break;
	}
	return false;
}
void goto_history_bookmark(GtkMenuItem *w, gpointer) {
	string str = gtk_menu_item_get_label(w);
	GtkTreeIter iter;
	if(find_history_bookmark(str, &iter)) {
		GtkTreePath *path = gtk_tree_model_get_path(GTK_TREE_MODEL(historystore), &iter);
		gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(historyview), path, history_index_column, TRUE, 0.0, 0.0);
		gtk_tree_path_free(path);
	}
}
void remove_history_bookmark(string str) {
	for(vector<string>::iterator it = history_bookmarks.begin(); it != history_bookmarks.end(); ++it) {
		if(equalsIgnoreCase(str, *it)) {
			history_bookmarks.erase(it);
			break;
		}
	}
	GtkTreeIter iter;
	gint hindex = 0;
	if(!find_history_bookmark(str, &iter)) return;
	gtk_tree_model_get(GTK_TREE_MODEL(historystore), &iter, 1, &hindex, -1);
	inhistory.erase(inhistory.begin() + hindex);
	inhistory_protected.erase(inhistory_protected.begin() + hindex);
	inhistory_type.erase(inhistory_type.begin() + hindex);
	inhistory_value.erase(inhistory_value.begin() + hindex);
	GtkTreeIter history_iter = iter;
	if(gtk_tree_model_iter_next(GTK_TREE_MODEL(historystore), &history_iter)) {
		gtk_tree_model_get(GTK_TREE_MODEL(historystore), &history_iter, 1, &hindex, -1);
		if(hindex >= 0 && !history_protected(hindex)) {
			gchar *gstr;
			gtk_tree_model_get(GTK_TREE_MODEL(historystore), &history_iter, 0, &gstr, -1);
			string str = gstr;
			size_t i = str.rfind("<span size=\"small\"><sup> ");
			if(i == string::npos) i = str.rfind("<span size=\"x-small\"><sup> ");
			if(i != string::npos) str = str.substr(0, i);
			gtk_list_store_set(historystore, &history_iter, 0, str.c_str(), -1);
			g_free(gstr);
		}
	}
	history_iter = iter;
	while(gtk_tree_model_iter_previous(GTK_TREE_MODEL(historystore), &history_iter)) {
		gtk_tree_model_get(GTK_TREE_MODEL(historystore), &history_iter, 1, &hindex, -1);
		if(hindex >= 0) gtk_list_store_set(historystore, &history_iter, 1, hindex - 1, -1);
	}
	gtk_list_store_remove(historystore, &iter);
}
void add_history_bookmark(string history_message) {
	GtkTreeModel *model;
	GtkTreeIter iter;
	GList *selected_list;
	gint hindex = -1;
	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(historyview));
	selected_list = gtk_tree_selection_get_selected_rows(select, &model);
	if(!selected_list) return;
	gtk_tree_model_get_iter(model, &iter, (GtkTreePath*) selected_list->data);
	while(true) {
		gtk_tree_model_get(model, &iter, 1, &hindex, -1);
		if(hindex >= 0 && ITEM_IS_EXPRESSION(hindex)) break;
		if((hindex >= 0 && inhistory_type[hindex] == QALCULATE_HISTORY_OLD) || !gtk_tree_model_iter_previous(model, &iter)) {
			hindex = -1;
			break;
		}
	}
	if(hindex >= 0) {
		bool b = false;
		for(vector<string>::iterator it = history_bookmarks.begin(); it != history_bookmarks.end(); ++it) {
			if(string_is_less(history_message, *it)) {
				history_bookmarks.insert(it, history_message);
				b = true;
				break;
			}
		}
		if(!b) history_bookmarks.push_back(history_message);
		add_line_breaks(history_message, false);
		if(HISTORY_IS_PARSE(hindex)) hindex++;
		hindex++;
		inhistory.insert(inhistory.begin() + hindex, history_message);
		inhistory_type.insert(inhistory_type.begin() + hindex, QALCULATE_HISTORY_BOOKMARK);
		inhistory_protected.insert(inhistory_protected.begin() + hindex, false);
		inhistory_value.insert(inhistory_value.begin() + hindex, 0);
		string history_str = "<span foreground=\"";
		history_str += history_bookmark_color;
		history_str += "\">";
		history_str += fix_history_string(history_message);
		history_str += ":";
		history_str += "</span>";
		gchar *gstr;
		gtk_tree_model_get(model, &iter, 0, &gstr, -1);
		string str = gstr;
		if(str.find("<span size=\"x-small\"><sup> ") == string::npos && str.rfind("<span size=\"small\"><sup> ") == string::npos) {
			if(can_display_unicode_string_function_exact("🔒", historyview)) str += "<span size=\"small\"><sup> 🔒</sup></span>";
			else str += "<span size=\"x-small\"><sup> P</sup></span>";
			gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, str.c_str(), -1);
		}
		g_free(gstr);
		gtk_list_store_insert_before(historystore, &iter, &iter);
		while(gtk_events_pending()) gtk_main_iteration();
		GtkTreePath *path = gtk_tree_model_get_path(model, &iter);
		gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(historyview), path, NULL, FALSE, 0, 0);
		gtk_tree_path_free(path);
		gtk_list_store_set(historystore, &iter, 0, history_str.c_str(), 1, hindex, 3, -1, 4, 0, 5, 6, 6, 0.0, 7, PANGO_ALIGN_LEFT, -1);
		while(gtk_tree_model_iter_previous(GTK_TREE_MODEL(historystore), &iter)) {
			gtk_tree_model_get(GTK_TREE_MODEL(historystore), &iter, 1, &hindex, -1);
			if(hindex >= 0) gtk_list_store_set(historystore, &iter, 1, hindex + 1, -1);
		}
	}
	on_expressionbuffer_changed(expressionbuffer, NULL);
	g_list_free_full(selected_list, (GDestroyNotify) gtk_tree_path_free);
}
void on_popup_menu_item_history_bookmark_activate(GtkMenuItem *w, gpointer) {
	if(b_busy) return;
	if(strcmp(gtk_menu_item_get_label(w), _("Remove Bookmark")) == 0) {
		GtkTreeModel *model;
		GtkTreeIter iter;
		GList *selected_list;
		gint hindex = -1;
		GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(historyview));
		selected_list = gtk_tree_selection_get_selected_rows(select, &model);
		if(!selected_list) return;
		gtk_tree_model_get_iter(model, &iter, (GtkTreePath*) selected_list->data);
		while(true) {
			gtk_tree_model_get(model, &iter, 1, &hindex, -1);
			if(hindex >= 0 && inhistory_type[hindex] == QALCULATE_HISTORY_BOOKMARK) break;
			if(!gtk_tree_model_iter_previous(model, &iter)) {
				hindex = -1;
				break;
			}
		}
		if(hindex >= 0) {
			for(vector<string>::iterator it = history_bookmarks.begin(); it != history_bookmarks.end(); ++it) {
				if(equalsIgnoreCase(inhistory[hindex], *it)) {
					history_bookmarks.erase(it);
					break;
				}
			}
			inhistory.erase(inhistory.begin() + hindex);
			inhistory_protected.erase(inhistory_protected.begin() + hindex);
			inhistory_type.erase(inhistory_type.begin() + hindex);
			inhistory_value.erase(inhistory_value.begin() + hindex);
			GtkTreeIter history_iter = iter;
			if(gtk_tree_model_iter_next(GTK_TREE_MODEL(historystore), &history_iter)) {
				gtk_tree_model_get(GTK_TREE_MODEL(historystore), &history_iter, 1, &hindex, -1);
				if(!history_protected(hindex)) {
					gchar *gstr;
					gtk_tree_model_get(GTK_TREE_MODEL(historystore), &history_iter, 0, &gstr, -1);
					string str = gstr;
					size_t i = str.rfind("<span size=\"small\"><sup> ");
					if(i == string::npos) i = str.rfind("<span size=\"x-small\"><sup> ");
					if(i != string::npos) str = str.substr(0, i);
					gtk_list_store_set(historystore, &history_iter, 0, str.c_str(), -1);
					g_free(gstr);
				}
			}
			history_iter = iter;
			while(gtk_tree_model_iter_previous(GTK_TREE_MODEL(historystore), &history_iter)) {
				gtk_tree_model_get(GTK_TREE_MODEL(historystore), &history_iter, 1, &hindex, -1);
				if(hindex >= 0) gtk_list_store_set(historystore, &history_iter, 1, hindex - 1, -1);
			}
			gtk_list_store_remove(historystore, &iter);
			on_expressionbuffer_changed(expressionbuffer, NULL);
		}
		g_list_free_full(selected_list, (GDestroyNotify) gtk_tree_path_free);
	} else {
		string history_message;
		GtkWidget *dialog = gtk_dialog_new_with_buttons(_("Add Bookmark"), GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT), _("_OK"), GTK_RESPONSE_ACCEPT, _("_Cancel"), GTK_RESPONSE_REJECT, NULL);
		gtk_container_set_border_width(GTK_CONTAINER(dialog), 5);
		GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 12);
		gtk_box_set_homogeneous(GTK_BOX(hbox), TRUE);
		gtk_container_set_border_width(GTK_CONTAINER(hbox), 12);
		gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), hbox);
		gtk_widget_show(hbox);
		GtkWidget *label = gtk_label_new(_("Name"));
		gtk_widget_set_halign(label, GTK_ALIGN_START);
		gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 0);
		gtk_widget_show(label);
		GtkWidget *entry = gtk_entry_new();
		gtk_box_pack_end(GTK_BOX(hbox), entry, FALSE, TRUE, 0);
		gtk_widget_show(entry);
		if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
			string history_message = gtk_entry_get_text(GTK_ENTRY(entry));
			remove_blank_ends(history_message);
			bool b = false;
			for(vector<string>::iterator it = history_bookmarks.begin(); it != history_bookmarks.end(); ++it) {
				if(equalsIgnoreCase(history_message, *it)) {
					b = true;
					break;
				}
			}
			if(b) {
				if(ask_question(_("A bookmark with the selected name already exists.\nDo you want to overwrite it?"), dialog)) {
					remove_history_bookmark(history_message);
				} else {
					history_message = "";
				}
			}
			if(!history_message.empty()) {
				add_history_bookmark(history_message);
			}
		}
		gtk_widget_destroy(dialog);
	}
}
bool history_protected_by_bookmark(size_t hi) {
	if(inhistory_type[hi] == QALCULATE_HISTORY_BOOKMARK) return true;
	while(hi + 1 < inhistory_type.size() && HISTORY_NOT_EXPRESSION(hi)) {
		hi++;
		if(inhistory_type[hi] == QALCULATE_HISTORY_BOOKMARK) return true;
	}
	if(hi + 1 < inhistory_type.size() && inhistory_type[hi + 1] == QALCULATE_HISTORY_BOOKMARK) return true;
	return false;
}
bool history_protected(size_t hi) {
	if(inhistory_protected[hi]) return true;
	while(hi + 1 < inhistory_type.size() && HISTORY_NOT_EXPRESSION(hi) && inhistory_type[hi] != QALCULATE_HISTORY_OLD) {
		hi++;
	}
	return inhistory_protected[hi];
}
void on_popup_menu_item_history_protect_toggled(GtkCheckMenuItem *w, gpointer) {
	if(b_busy) return;
	bool b = gtk_check_menu_item_get_active(w);
	GtkTreeModel *model;
	GtkTreeIter iter;
	GList *selected_list;
	gint hi = -1, hi_pre = 0, hi_pre_next;
	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(historyview));
	selected_list = gtk_tree_selection_get_selected_rows(select, &model);
	GList *current_selected_list = selected_list;
	while(current_selected_list) {
		gtk_tree_model_get_iter(model, &iter, (GtkTreePath*) current_selected_list->data);
		gtk_tree_model_get(model, &iter, 1, &hi, -1);
		hi_pre_next = hi;
		bool b2 = true;
		while(hi >= 0 && (size_t) hi + 1 < inhistory_type.size() && ITEM_NOT_EXPRESSION(hi)) {
			if(!gtk_tree_model_iter_previous(model, &iter)) {
				b2 = false;
				break;
			}
			gtk_tree_model_get(model, &iter, 1, &hi, -1);
			if(hi == hi_pre) {
				b2 = false;
				break;
			}
		}
		if(hi >= 0 && b2) {
			if(HISTORY_IS_PARSE(hi)) hi++;
			if(b != inhistory_protected[hi]) {
				inhistory_protected[hi] = b;
				gchar *gstr;
				gtk_tree_model_get(model, &iter, 0, &gstr, -1);
				string str = gstr;
				if((size_t) hi + 1 >= inhistory_type.size() || inhistory_type[hi + 1] != QALCULATE_HISTORY_BOOKMARK) {
					if(b) {
						if(str.find("<span size=\"x-small\"><sup> ") == string::npos && str.find("<span size=\"small\"><sup> ") == string::npos) {
							if(can_display_unicode_string_function_exact("🔒", historyview)) str += "<span size=\"small\"><sup> 🔒</sup></span>";
							else str += "<span size=\"x-small\"><sup> P</sup></span>";
						}
					} else {
						size_t i = str.rfind("<span size=\"small\"><sup> ");
						if(i == string::npos) i = str.rfind("<span size=\"x-small\"><sup> ");
						if(i != string::npos) str = str.substr(0, i);
					}
					gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, str.c_str(), -1);
				}
				g_free(gstr);
			}
		}
		hi_pre = hi_pre_next;
		current_selected_list = current_selected_list->next;
	}
	g_list_free_full(selected_list, (GDestroyNotify) gtk_tree_path_free);
}
void on_popup_menu_history_bookmark_update_activate(GtkMenuItem*, gpointer data) {
	remove_history_bookmark(gtk_menu_item_get_label(GTK_MENU_ITEM(data)));
	add_history_bookmark(gtk_menu_item_get_label(GTK_MENU_ITEM(data)));
	gtk_menu_popdown(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_historyview")));
}
void on_popup_menu_history_bookmark_delete_activate(GtkMenuItem*, gpointer data) {
	remove_history_bookmark(gtk_menu_item_get_label(GTK_MENU_ITEM(data)));
	gtk_menu_popdown(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_historyview")));
}

gulong on_popup_menu_history_bookmark_update_activate_handler = 0, on_popup_menu_history_bookmark_delete_activate_handler = 0;

gboolean on_menu_history_bookmark_popup_menu(GtkWidget*, gpointer data) {
	if(b_busy) return TRUE;
	vector<size_t> selected_rows;
	process_history_selection(&selected_rows, NULL, NULL);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_history_bookmark_update")), selected_rows.size() == 1 && inhistory_type[selected_rows[0]] != QALCULATE_HISTORY_OLD);
	if(on_popup_menu_history_bookmark_update_activate_handler != 0) g_signal_handler_disconnect(gtk_builder_get_object(main_builder, "popup_menu_history_bookmark_update"), on_popup_menu_history_bookmark_update_activate_handler);
	if(on_popup_menu_history_bookmark_delete_activate_handler != 0) g_signal_handler_disconnect(gtk_builder_get_object(main_builder, "popup_menu_history_bookmark_delete"), on_popup_menu_history_bookmark_delete_activate_handler);
	on_popup_menu_history_bookmark_update_activate_handler = g_signal_connect(gtk_builder_get_object(main_builder, "popup_menu_history_bookmark_update"), "activate", G_CALLBACK(on_popup_menu_history_bookmark_update_activate), data);
	on_popup_menu_history_bookmark_delete_activate_handler = g_signal_connect(gtk_builder_get_object(main_builder, "popup_menu_history_bookmark_delete"), "activate", G_CALLBACK(on_popup_menu_history_bookmark_delete_activate), data);
#if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 22
	gtk_menu_popup_at_pointer(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_history_bookmark")), NULL);
#else
	gtk_menu_popup(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_history_bookmark")), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time());
#endif
	return TRUE;
}

gboolean on_menu_history_bookmark_button_press(GtkWidget *widget, GdkEventButton *event, gpointer data) {
	/* Ignore double-clicks and triple-clicks */
	if(gdk_event_triggers_context_menu((GdkEvent *) event) && event->type == GDK_BUTTON_PRESS) {
		on_menu_history_bookmark_popup_menu(widget, data);
		return TRUE;
	}
	return FALSE;
}

void update_historyview_popup() {
	GtkTreeIter iter;
	vector<size_t> selected_rows;
	vector<size_t> selected_indeces;
	vector<int> selected_index_type;
	size_t hi = 0;
	process_history_selection(&selected_rows, &selected_indeces, &selected_index_type);
	if(selected_rows.size() == 1) {
		hi = selected_rows[0];
		if(HISTORY_IS_PARSE(hi)) {
			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_history_insert_parsed_text")), TRUE);
			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_history_insert_text")), hi < inhistory_type.size() - 1 && inhistory_type[hi + 1] == QALCULATE_HISTORY_EXPRESSION);
		} else {
			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_history_insert_text")), inhistory_type[hi] != QALCULATE_HISTORY_WARNING && inhistory_type[hi] != QALCULATE_HISTORY_ERROR && inhistory_type[hi] != QALCULATE_HISTORY_BOOKMARK && inhistory_type[hi] != QALCULATE_HISTORY_RPN_OPERATION && inhistory_type[hi] != QALCULATE_HISTORY_REGISTER_MOVED);
			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_history_insert_parsed_text")), hi > 0 && HISTORY_IS_EXPRESSION(hi) && HISTORY_IS_PARSE(hi - 1));
		}
	} else {
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_history_insert_text")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_history_insert_parsed_text")), FALSE);
	}
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_history_insert_value")), selected_indeces.size() > 0 && selected_index_type[0] != INDEX_TYPE_TXT && selected_index_type.back() != INDEX_TYPE_TXT);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_history_copy_text")), selected_indeces.size() == 1 && inhistory_type[hi] != QALCULATE_HISTORY_BOOKMARK);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_history_copy_full_text")), !selected_rows.empty());
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_history_movetotop")), !selected_rows.empty());
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_history_delete")), !selected_rows.empty());
	bool protected_by_bookmark = true, b_protected = true, b_old = false;
	for(size_t i = 0; i < selected_rows.size(); i++) {
		if(!b_old && inhistory_type[selected_rows[i]] == QALCULATE_HISTORY_OLD) {b_old = true; b_protected = false; break;}
		if(b_protected) {
			if(history_protected(selected_rows[i])) {
				protected_by_bookmark = false;
			} else if(!history_protected_by_bookmark(selected_rows[i])) {
				protected_by_bookmark = false;
				b_protected = false;
			}
		}
	}
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_history_protect")), selected_rows.size() > 0 && !b_old && !protected_by_bookmark);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_history_protect"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_history_protect_toggled, NULL);
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_history_protect")), selected_rows.size() > 0 && b_protected);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_history_protect"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_history_protect_toggled, NULL);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_history_bookmark")), selected_rows.size() == 1 && hi >= 0 && inhistory_type[hi] != QALCULATE_HISTORY_OLD);
	if(selected_rows.size() == 1 && history_protected_by_bookmark(hi)) gtk_menu_item_set_label(GTK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_history_bookmark")), _("Remove Bookmark"));
	else gtk_menu_item_set_label(GTK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_history_bookmark")), _("Add Bookmark…"));
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_history_clear")), gtk_tree_model_get_iter_first(GTK_TREE_MODEL(historystore), &iter));
	gtk_container_foreach(GTK_CONTAINER(gtk_builder_get_object(main_builder, "popup_menu_history_bookmarks")), (GtkCallback) gtk_widget_destroy, NULL);
	GtkWidget *item;
	GtkWidget *sub = GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_history_bookmarks"));
	for(size_t i = 0; i < history_bookmarks.size(); i++) {		
		MENU_ITEM(history_bookmarks[i].c_str(), goto_history_bookmark)
		g_signal_connect(G_OBJECT(item), "button-press-event", G_CALLBACK(on_menu_history_bookmark_button_press), (gpointer) item);
		g_signal_connect(G_OBJECT(item), "popup-menu", G_CALLBACK(on_menu_history_bookmark_popup_menu), (gpointer) item);
	}
	if(history_bookmarks.empty()) {MENU_NO_ITEMS(_("No items found"))}
}
gboolean on_historyview_button_press_event(GtkWidget*, GdkEventButton *event, gpointer) {
	GtkTreePath *path = NULL;
	GtkTreeSelection *select = NULL;
	if(gdk_event_triggers_context_menu((GdkEvent*) event) && event->type == GDK_BUTTON_PRESS) {
		if(b_busy) return TRUE;
		if(gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(historyview), event->x, event->y, &path, NULL, NULL, NULL)) {
			select = gtk_tree_view_get_selection(GTK_TREE_VIEW(historyview));
			if(!gtk_tree_selection_path_is_selected(select, path)) {
				gtk_tree_selection_unselect_all(select);
				gtk_tree_selection_select_path(select, path);
			}
			gtk_tree_path_free(path);
		}
		update_historyview_popup();
#if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 22
		gtk_menu_popup_at_pointer(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_historyview")), (GdkEvent*) event);
#else
		gtk_menu_popup(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_historyview")), NULL, NULL, NULL, NULL, event->button, event->time);
#endif
		return TRUE;
	}
	return FALSE;
}
Unit *popup_convert_unit = NULL;
void update_convert_popup() {
	GtkTreeIter iter_sel;
	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitSelector));
	GtkTreeModel *model;
	Unit *u_sel = popup_convert_unit;
	if(!u_sel && gtk_tree_selection_get_selected(select, &model, &iter_sel)) gtk_tree_model_get(model, &iter_sel, 1, &u_sel, -1);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_convert_insert")), u_sel != NULL);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_convert_convert")), u_sel != NULL);
}
void on_popup_menu_convert_insert_activate(GtkMenuItem*, gpointer) {
	GtkTreeIter iter_sel;
	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitSelector));
	GtkTreeModel *model;
	Unit *u = popup_convert_unit;
	if(!u && gtk_tree_selection_get_selected(select, &model, &iter_sel)) gtk_tree_model_get(model, &iter_sel, 1, &u, -1);
	if(u) {
		if(u->subtype() == SUBTYPE_COMPOSITE_UNIT) {
			insert_text(((CompositeUnit*) u)->print(true, printops.abbreviate_names, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) expressiontext).c_str());
		} else {
			insert_text(u->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, true, false, &can_display_unicode_string_function, (void*) expressiontext).name.c_str());
		}
		unit_inserted(u);
	}
}
void on_popup_menu_convert_convert_activate(GtkMenuItem*, gpointer) {
	GtkTreeIter iter_sel;
	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitSelector));
	GtkTreeModel *model;
	Unit *u = popup_convert_unit;
	if(!u && gtk_tree_selection_get_selected(select, &model, &iter_sel)) gtk_tree_model_get(model, &iter_sel, 1, &u, -1);
	if(u) {
		keep_unit_selection = true;
		for(size_t i = 0; i < CALCULATOR->units.size(); i++) {
			if(CALCULATOR->units[i] == u) {
				if(u->subtype() == SUBTYPE_COMPOSITE_UNIT) {
					gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(main_builder, "convert_entry_unit")), ((CompositeUnit*) u)->print(true, printops.abbreviate_names, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) gtk_builder_get_object(main_builder, "convert_entry_unit")).c_str());
				} else {
					gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(main_builder, "convert_entry_unit")), u->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) gtk_builder_get_object(main_builder, "convert_entry_unit")).name.c_str());
				}
				if(!block_unit_selector_convert) convert_from_convert_entry_unit();
			}
		}
		keep_unit_selection = false;
	}
}
gboolean on_convert_treeview_unit_button_press_event(GtkWidget *w, GdkEventButton *event, gpointer) {
	GtkTreePath *path = NULL;
	if(event->type == GDK_BUTTON_PRESS && event->button == 2) {
		if(b_busy) return TRUE;
		if(gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(w), event->x, event->y, &path, NULL, NULL, NULL)) {
			GtkTreeIter iter;
			if(gtk_tree_model_get_iter(tUnitSelector_store_filter, &iter, path)) {
				Unit *u = NULL;
				gtk_tree_model_get(tUnitSelector_store_filter, &iter, 1, &u, -1);
				if(u) {
					if(u->subtype() == SUBTYPE_COMPOSITE_UNIT) {
						insert_text(((CompositeUnit*) u)->print(true, printops.abbreviate_names, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) expressiontext).c_str());
					} else {
						insert_text(u->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, true, false, &can_display_unicode_string_function, (void*) expressiontext).name.c_str());
					}
					unit_inserted(u);
				}
				gtk_tree_path_free(path);
				return TRUE;
			}
			gtk_tree_path_free(path);
		}
	} else if(gdk_event_triggers_context_menu((GdkEvent*) event) && event->type == GDK_BUTTON_PRESS) {
		if(b_busy) return TRUE;
		if(gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(w), event->x, event->y, &path, NULL, NULL, NULL)) {
			GtkTreeIter iter;
			if(gtk_tree_model_get_iter(tUnitSelector_store_filter, &iter, path)) {
				gtk_tree_model_get(tUnitSelector_store_filter, &iter, 1, &popup_convert_unit, -1);
			} else {
				popup_convert_unit = NULL;
			}
			gtk_tree_path_free(path);
		}
		
		update_convert_popup();
#if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 22
		gtk_menu_popup_at_pointer(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_convert")), (GdkEvent*) event);
#else
		gtk_menu_popup(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_convert")), NULL, NULL, NULL, NULL, event->button, event->time);
#endif
		return TRUE;
	}
	return FALSE;
}
gboolean on_convert_treeview_unit_popup_menu(GtkWidget*, gpointer) {
	if(b_busy) return TRUE;
	popup_convert_unit = NULL;
	update_convert_popup();
#if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 22
	gtk_menu_popup_at_pointer(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_convert")), NULL);
#else
	gtk_menu_popup(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_convert")), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time());
#endif
	return TRUE;
}
gboolean on_historyview_popup_menu(GtkWidget*, gpointer) {
	if(b_busy) return TRUE;
	update_historyview_popup();
#if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 22
	gtk_menu_popup_at_pointer(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_historyview")), NULL);
#else
	gtk_menu_popup(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_historyview")), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time());
#endif
	return TRUE;
}
void on_historyview_selection_changed(GtkTreeSelection*, gpointer) {
	vector<size_t> selected_rows;
	vector<size_t> selected_indeces;
	vector<int> selected_index_type;
	process_history_selection(&selected_rows, &selected_indeces, &selected_index_type);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_history_insert_value")), selected_indeces.size() > 0 && selected_index_type[0] != INDEX_TYPE_TXT && selected_index_type.back() != INDEX_TYPE_TXT);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_history_insert_text")), selected_indeces.size() == 1);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_history_copy")), !selected_rows.empty());
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_history_sqrt")), selected_indeces.size() <= 1);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_history_xy")), selected_indeces.size() <= 2);
}
void on_historyview_row_activated(GtkTreeView*, GtkTreePath *path, GtkTreeViewColumn *column, gpointer) {
	GtkTreeIter iter;
	gint index = -1, hindex = -1;
	if(!gtk_tree_model_get_iter(GTK_TREE_MODEL(historystore), &iter, path)) return;
	gtk_tree_model_get(GTK_TREE_MODEL(historystore), &iter, 1, &hindex, 3, &index, -1);
	if(index > 0 && hindex >= 0 && evalops.parse_options.functions_enabled && evalops.parse_options.base <= BASE_DECIMAL && evalops.parse_options.base > 0) {
		const ExpressionName *ename = NULL;
		switch(inhistory_type[(size_t) hindex]) {
			case QALCULATE_HISTORY_RPN_OPERATION: {}
			case QALCULATE_HISTORY_REGISTER_MOVED: {
				if(hindex == 0 || column == history_index_column) {
					ename = &f_expression->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext);
				} else {
					insert_text(inhistory[(size_t) hindex - 1].c_str());
					return;
				}
				break;
			}
			case QALCULATE_HISTORY_PARSE: {}
			case QALCULATE_HISTORY_PARSE_APPROXIMATE: {
				if(column != history_index_column && (size_t) hindex < inhistory_type.size() - 1 && inhistory_type[hindex + 1] == QALCULATE_HISTORY_EXPRESSION) hindex++;
			}
			case QALCULATE_HISTORY_EXPRESSION: {
				if(column == history_index_column) {
					ename = &f_expression->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext);
				} else {
					insert_text(inhistory[(size_t) hindex].c_str());
					return;
				}
				break;
			}
			default: {
				ename = &f_answer->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext);
			}
		}		
		string str = ename->name;
		str += "(";
		Number nr(index, 1);
		str += print_with_evalops(nr);
		str += ")";
		if(rpn_mode) {
			add_to_undo = false;
			insert_text(str.c_str());
			add_to_undo = true;
			execute_expression();
		} else {
			insert_text(str.c_str());
		}
	} else if(hindex >= 0) {
		if(hindex > 0 && (inhistory_type[hindex] == QALCULATE_HISTORY_TRANSFORMATION || inhistory_type[hindex] == QALCULATE_HISTORY_RPN_OPERATION || inhistory_type[hindex] == QALCULATE_HISTORY_REGISTER_MOVED)) hindex--;
		else if((size_t) hindex < inhistory_type.size() - 1 && (inhistory_type[hindex] == QALCULATE_HISTORY_PARSE || inhistory_type[hindex] == QALCULATE_HISTORY_PARSE_WITHEQUALS || inhistory_type[hindex] == QALCULATE_HISTORY_PARSE_APPROXIMATE) && inhistory_type[hindex + 1] == QALCULATE_HISTORY_EXPRESSION) hindex++;
		if(inhistory_type[hindex] != QALCULATE_HISTORY_WARNING && inhistory_type[hindex] != QALCULATE_HISTORY_ERROR && inhistory_type[hindex] != QALCULATE_HISTORY_BOOKMARK) {
			if(rpn_mode && ITEM_NOT_EXPRESSION(hindex) && inhistory_type[hindex] != QALCULATE_HISTORY_OLD) {
				add_to_undo = false;
				insert_text(inhistory[(size_t) hindex].c_str());
				add_to_undo = true;
				execute_expression();
			} else {
				insert_text(inhistory[(size_t) hindex].c_str());
			}
		}
	}
}

void on_menu_item_manage_variables_activate(GtkMenuItem*, gpointer) {
	manage_variables();
}
void on_menu_item_manage_functions_activate(GtkMenuItem*, gpointer) {
	manage_functions();
}
void on_menu_item_manage_units_activate(GtkMenuItem*, gpointer) {
	manage_units();
}

void on_menu_item_datasets_activate(GtkMenuItem*, gpointer) {
	GtkWidget *dialog = get_datasets_dialog();
	gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")));
	gtk_widget_show(dialog);
	gtk_window_present(GTK_WINDOW(dialog));	
}

void on_menu_item_import_csv_file_activate(GtkMenuItem*, gpointer) {
	import_csv_file(GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")));
}

void on_menu_item_export_csv_file_activate(GtkMenuItem*, gpointer) {
	export_csv_file(NULL, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")));
}

void on_expander_convert_activate(GtkExpander *o, gpointer) {
	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(main_builder, "convert_entry_unit"))); 
}
void on_menu_item_convert_to_unit_expression_activate(GtkMenuItem*, gpointer) {
	gtk_expander_set_expanded(GTK_EXPANDER(expander_convert), TRUE);
	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(main_builder, "convert_entry_unit"))); 
}
void on_menu_item_convert_to_best_unit_activate(GtkMenuItem*, gpointer) {
	executeCommand(COMMAND_CONVERT_OPTIMAL);
}
void on_menu_item_convert_to_base_units_activate(GtkMenuItem*, gpointer) {
	executeCommand(COMMAND_CONVERT_BASE);
}

void on_menu_item_set_prefix_activate(GtkMenuItem*, gpointer user_data) {
	result_prefix_changed((Prefix*) user_data);
	focus_keeping_selection();
}

void on_menu_item_insert_date_activate(GtkMenuItem*, gpointer) {
	GtkWidget *d = gtk_dialog_new_with_buttons(_("Select date"), GTK_WINDOW(mainwindow), (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT), _("_OK"), GTK_RESPONSE_OK, _("_Cancel"), GTK_RESPONSE_CANCEL, NULL);
	GtkWidget *date_w = gtk_calendar_new();
	string str = get_selected_expression_text();
	remove_blank_ends(str);
	int b_quote = -1;
	if(str.length() > 2 && ((str[0] == '\"' && str[str.length() - 1] == '\"') || (str[0] == '\'' && str[str.length() - 1] == '\''))) {
		str = str.substr(1, str.length() - 2);
		remove_blank_ends(str);
		b_quote = 1;
	}
	if(!str.empty()) {
		QalculateDateTime date;
		if(date.set(str)) {
			if(b_quote < 0) b_quote = 0;
			gtk_calendar_select_month(GTK_CALENDAR(date_w), date.month() - 1, date.year());
			gtk_calendar_select_day(GTK_CALENDAR(date_w), date.day());
		}
	}
	gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(d))), date_w);
	gtk_widget_show_all(d);
	if(gtk_dialog_run(GTK_DIALOG(d)) == GTK_RESPONSE_OK) {
		guint year = 0, month = 0, day = 0;
		gtk_calendar_get_date(GTK_CALENDAR(date_w), &year, &month, &day);
		gchar *gstr;
		if(b_quote == 0) gstr = g_strdup_printf("%i-%02i-%02i", year, month + 1, day);
		else gstr = g_strdup_printf("\"%i-%02i-%02i\"", year, month + 1, day);
		insert_text(gstr);
		g_free(gstr);
	}
	gtk_widget_destroy(d);
}

void on_menu_item_insert_matrix_activate(GtkMenuItem*, gpointer) {
	string str = get_selected_expression_text();
	remove_blank_ends(str);
	if(!str.empty()) {
		MathStructure mstruct_sel;
		CALCULATOR->beginTemporaryStopMessages();
		CALCULATOR->parse(&mstruct_sel, CALCULATOR->unlocalizeExpression(str, evalops.parse_options), evalops.parse_options);
		CALCULATOR->endTemporaryStopMessages();
		if(mstruct_sel.isMatrix() && mstruct_sel[0].size() > 0) {
			insert_matrix(&mstruct_sel, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")), false);
			return;
		}
	}
	insert_matrix(NULL, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")), false);
}
void on_menu_item_insert_vector_activate(GtkMenuItem*, gpointer) {
	string str = get_selected_expression_text();
	remove_blank_ends(str);
	if(!str.empty()) {
		MathStructure mstruct_sel;
		CALCULATOR->beginTemporaryStopMessages();
		CALCULATOR->parse(&mstruct_sel, CALCULATOR->unlocalizeExpression(str, evalops.parse_options), evalops.parse_options);
		CALCULATOR->endTemporaryStopMessages();
		if(mstruct_sel.isVector() && !mstruct_sel.isMatrix()) {
			insert_matrix(&mstruct_sel, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")), true);
			return;
		}
	}
	insert_matrix(NULL, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")), true);
}

void update_assumptions_items() {
	if(!block_expression_execution) {
		block_expression_execution = true;
		set_assumptions_items(CALCULATOR->defaultAssumptions()->type(), CALCULATOR->defaultAssumptions()->sign());
		block_expression_execution = false;
	}
}

void on_menu_item_assumptions_integer_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	CALCULATOR->defaultAssumptions()->setType(ASSUMPTION_TYPE_INTEGER);
	update_assumptions_items();
	expression_calculation_updated();
}
void on_menu_item_assumptions_rational_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	CALCULATOR->defaultAssumptions()->setType(ASSUMPTION_TYPE_RATIONAL);
	update_assumptions_items();
	expression_calculation_updated();
}
void on_menu_item_assumptions_real_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	CALCULATOR->defaultAssumptions()->setType(ASSUMPTION_TYPE_REAL);
	update_assumptions_items();
	expression_calculation_updated();
}
void on_menu_item_assumptions_complex_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	CALCULATOR->defaultAssumptions()->setType(ASSUMPTION_TYPE_COMPLEX);
	update_assumptions_items();
	expression_calculation_updated();
}
void on_menu_item_assumptions_number_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	CALCULATOR->defaultAssumptions()->setType(ASSUMPTION_TYPE_NUMBER);
	update_assumptions_items();
	expression_calculation_updated();
}
void on_menu_item_assumptions_none_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	CALCULATOR->defaultAssumptions()->setType(ASSUMPTION_TYPE_NONE);
	update_assumptions_items();
	expression_calculation_updated();
}
void on_menu_item_assumptions_nonmatrix_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	CALCULATOR->defaultAssumptions()->setType(ASSUMPTION_TYPE_NONMATRIX);
	update_assumptions_items();
	expression_calculation_updated();
}
void on_menu_item_assumptions_nonzero_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	CALCULATOR->defaultAssumptions()->setSign(ASSUMPTION_SIGN_NONZERO);
	update_assumptions_items();
	expression_calculation_updated();
}
void on_menu_item_assumptions_positive_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	CALCULATOR->defaultAssumptions()->setSign(ASSUMPTION_SIGN_POSITIVE);
	update_assumptions_items();
	expression_calculation_updated();
}
void on_menu_item_assumptions_nonnegative_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	CALCULATOR->defaultAssumptions()->setSign(ASSUMPTION_SIGN_NONNEGATIVE);
	update_assumptions_items();
	expression_calculation_updated();
}
void on_menu_item_assumptions_negative_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	CALCULATOR->defaultAssumptions()->setSign(ASSUMPTION_SIGN_NEGATIVE);
	update_assumptions_items();
	expression_calculation_updated();
}
void on_menu_item_assumptions_nonpositive_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	CALCULATOR->defaultAssumptions()->setSign(ASSUMPTION_SIGN_NONPOSITIVE);
	update_assumptions_items();
	expression_calculation_updated();
}
void on_menu_item_assumptions_unknown_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	CALCULATOR->defaultAssumptions()->setSign(ASSUMPTION_SIGN_UNKNOWN);
	update_assumptions_items();
	expression_calculation_updated();
}

void set_type(const char *var, AssumptionType at) {
	if(block_expression_execution) return;
	Variable *v = CALCULATOR->getActiveVariable(var);
	if(!v || v->isKnown()) return;
	UnknownVariable *uv = (UnknownVariable*) v;
	if(!uv->assumptions()) uv->setAssumptions(new Assumptions()); 
	uv->assumptions()->setType(at);
	expression_calculation_updated();
}
void set_sign(const char *var, AssumptionSign as) {
	if(block_expression_execution) return;
	Variable *v = CALCULATOR->getActiveVariable(var);
	if(!v || v->isKnown()) return;
	UnknownVariable *uv = (UnknownVariable*) v;
	if(!uv->assumptions()) uv->setAssumptions(new Assumptions()); 
	uv->assumptions()->setSign(as);
	expression_calculation_updated();
}
void reset_assumptions(const char *var) {
	Variable *v = CALCULATOR->getActiveVariable(var);
	if(!v || v->isKnown()) return;
	UnknownVariable *uv = (UnknownVariable*) v;
	uv->setAssumptions(NULL);
	expression_calculation_updated();
}

void set_x_assumptions_items() {
	Variable *v = CALCULATOR->getActiveVariable("x");
	if(!v || v->isKnown()) return;
	UnknownVariable *uv = (UnknownVariable*) v;
	bool b_bak = block_expression_execution;
	block_expression_execution = true;
	Assumptions *ass = uv->assumptions();
	if(!ass) ass = CALCULATOR->defaultAssumptions();
	switch(ass->sign()) {
		case ASSUMPTION_SIGN_POSITIVE: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_x_positive")), TRUE); break;}
		case ASSUMPTION_SIGN_NONPOSITIVE: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_x_nonpositive")), TRUE); break;}
		case ASSUMPTION_SIGN_NEGATIVE: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_x_negative")), TRUE); break;}
		case ASSUMPTION_SIGN_NONNEGATIVE: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_x_nonnegative")), TRUE); break;}
		case ASSUMPTION_SIGN_NONZERO: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_x_nonzero")), TRUE); break;}
		default: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_x_unknown")), TRUE);}
	}
	switch(ass->type()) {
		case ASSUMPTION_TYPE_INTEGER: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_x_integer")), TRUE); break;}
		case ASSUMPTION_TYPE_RATIONAL: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_x_rational")), TRUE); break;}
		case ASSUMPTION_TYPE_REAL: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_x_real")), TRUE); break;}
		case ASSUMPTION_TYPE_COMPLEX: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_x_complex")), TRUE); break;}
		case ASSUMPTION_TYPE_NUMBER: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_x_number")), TRUE); break;}
		case ASSUMPTION_TYPE_NONMATRIX: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_x_nonmatrix")), TRUE); break;}
		default: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_x_none")), TRUE);}
	}
	block_expression_execution = b_bak;
}
void on_mb_x_toggled(GtkToggleButton *w, gpointer) {
	if(!gtk_toggle_button_get_active(w)) return;
	set_x_assumptions_items();
}

void on_menu_item_x_default_activate() {
	reset_assumptions("x");
}
void on_menu_item_x_integer_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	set_type("x", ASSUMPTION_TYPE_INTEGER);
}
void on_menu_item_x_rational_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	set_type("x", ASSUMPTION_TYPE_RATIONAL);
}
void on_menu_item_x_real_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	set_type("x", ASSUMPTION_TYPE_REAL);
}
void on_menu_item_x_complex_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	set_type("x", ASSUMPTION_TYPE_COMPLEX);
}
void on_menu_item_x_number_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	set_type("x", ASSUMPTION_TYPE_NUMBER);
}
void on_menu_item_x_none_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	set_type("x", ASSUMPTION_TYPE_NONE);
}
void on_menu_item_x_nonmatrix_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	set_type("x", ASSUMPTION_TYPE_NONMATRIX);
}
void on_menu_item_x_nonzero_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	set_sign("x", ASSUMPTION_SIGN_NONZERO);
}
void on_menu_item_x_positive_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	set_sign("x", ASSUMPTION_SIGN_POSITIVE);
}
void on_menu_item_x_nonnegative_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	set_sign("x", ASSUMPTION_SIGN_NONNEGATIVE);
}
void on_menu_item_x_negative_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	set_sign("x", ASSUMPTION_SIGN_NEGATIVE);
}
void on_menu_item_x_nonpositive_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	set_sign("x", ASSUMPTION_SIGN_NONPOSITIVE);
}
void on_menu_item_x_unknown_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	set_sign("x", ASSUMPTION_SIGN_UNKNOWN);
}

void set_y_assumptions_items() {
	Variable *v = CALCULATOR->getActiveVariable("y");
	if(!v || v->isKnown()) return;
	UnknownVariable *uv = (UnknownVariable*) v;
	bool b_bak = block_expression_execution;
	block_expression_execution = true;
	Assumptions *ass = uv->assumptions();
	if(!ass) ass = CALCULATOR->defaultAssumptions();
	switch(ass->sign()) {
		case ASSUMPTION_SIGN_POSITIVE: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_y_positive")), TRUE); break;}
		case ASSUMPTION_SIGN_NONPOSITIVE: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_y_nonpositive")), TRUE); break;}
		case ASSUMPTION_SIGN_NEGATIVE: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_y_negative")), TRUE); break;}
		case ASSUMPTION_SIGN_NONNEGATIVE: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_y_nonnegative")), TRUE); break;}
		case ASSUMPTION_SIGN_NONZERO: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_y_nonzero")), TRUE); break;}
		default: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_y_unknown")), TRUE);}
	}
	switch(ass->type()) {
		case ASSUMPTION_TYPE_INTEGER: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_y_integer")), TRUE); break;}
		case ASSUMPTION_TYPE_RATIONAL: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_y_rational")), TRUE); break;}
		case ASSUMPTION_TYPE_REAL: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_y_real")), TRUE); break;}
		case ASSUMPTION_TYPE_COMPLEX: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_y_complex")), TRUE); break;}
		case ASSUMPTION_TYPE_NUMBER: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_y_number")), TRUE); break;}
		case ASSUMPTION_TYPE_NONMATRIX: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_y_nonmatrix")), TRUE); break;}
		default: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_y_none")), TRUE);}
	}
	block_expression_execution = b_bak;
}
void on_mb_y_toggled(GtkToggleButton *w, gpointer) {
	if(!gtk_toggle_button_get_active(w)) return;
	set_y_assumptions_items();
}

void on_menu_item_y_default_activate() {
	reset_assumptions("y");
}
void on_menu_item_y_integer_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	set_type("y", ASSUMPTION_TYPE_INTEGER);
}
void on_menu_item_y_rational_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	set_type("y", ASSUMPTION_TYPE_RATIONAL);
}
void on_menu_item_y_real_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	set_type("y", ASSUMPTION_TYPE_REAL);
}
void on_menu_item_y_complex_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	set_type("y", ASSUMPTION_TYPE_COMPLEX);
}
void on_menu_item_y_number_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	set_type("y", ASSUMPTION_TYPE_NUMBER);
}
void on_menu_item_y_none_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	set_type("y", ASSUMPTION_TYPE_NONE);
}
void on_menu_item_y_nonmatrix_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	set_type("y", ASSUMPTION_TYPE_NONMATRIX);
}
void on_menu_item_y_nonzero_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	set_sign("y", ASSUMPTION_SIGN_NONZERO);
}
void on_menu_item_y_positive_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	set_sign("y", ASSUMPTION_SIGN_POSITIVE);
}
void on_menu_item_y_nonnegative_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	set_sign("y", ASSUMPTION_SIGN_NONNEGATIVE);
}
void on_menu_item_y_negative_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	set_sign("y", ASSUMPTION_SIGN_NEGATIVE);
}
void on_menu_item_y_nonpositive_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	set_sign("y", ASSUMPTION_SIGN_NONPOSITIVE);
}
void on_menu_item_y_unknown_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	set_sign("y", ASSUMPTION_SIGN_UNKNOWN);
}

void set_z_assumptions_items() {
	Variable *v = CALCULATOR->getActiveVariable("z");
	if(!v || v->isKnown()) return;
	UnknownVariable *uv = (UnknownVariable*) v;
	bool b_bak = block_expression_execution;
	block_expression_execution = true;
	Assumptions *ass = uv->assumptions();
	if(!ass) ass = CALCULATOR->defaultAssumptions();
	switch(ass->sign()) {
		case ASSUMPTION_SIGN_POSITIVE: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_z_positive")), TRUE); break;}
		case ASSUMPTION_SIGN_NONPOSITIVE: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_z_nonpositive")), TRUE); break;}
		case ASSUMPTION_SIGN_NEGATIVE: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_z_negative")), TRUE); break;}
		case ASSUMPTION_SIGN_NONNEGATIVE: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_z_nonnegative")), TRUE); break;}
		case ASSUMPTION_SIGN_NONZERO: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_z_nonzero")), TRUE); break;}
		default: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_z_unknown")), TRUE);}
	}
	switch(ass->type()) {
		case ASSUMPTION_TYPE_INTEGER: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_z_integer")), TRUE); break;}
		case ASSUMPTION_TYPE_RATIONAL: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_z_rational")), TRUE); break;}
		case ASSUMPTION_TYPE_REAL: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_z_real")), TRUE); break;}
		case ASSUMPTION_TYPE_COMPLEX: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_z_complex")), TRUE); break;}
		case ASSUMPTION_TYPE_NUMBER: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_z_number")), TRUE); break;}
		case ASSUMPTION_TYPE_NONMATRIX: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_z_nonmatrix")), TRUE); break;}
		default: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_z_none")), TRUE);}
	}
	block_expression_execution = b_bak;
}
void on_mb_z_toggled(GtkToggleButton *w, gpointer) {
	if(!gtk_toggle_button_get_active(w)) return;
	set_z_assumptions_items();
}

void on_menu_item_z_default_activate() {
	reset_assumptions("z");
}
void on_menu_item_z_integer_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	set_type("z", ASSUMPTION_TYPE_INTEGER);
}
void on_menu_item_z_rational_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	set_type("z", ASSUMPTION_TYPE_RATIONAL);
}
void on_menu_item_z_real_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	set_type("z", ASSUMPTION_TYPE_REAL);
}
void on_menu_item_z_complex_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	set_type("z", ASSUMPTION_TYPE_COMPLEX);
}
void on_menu_item_z_number_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	set_type("z", ASSUMPTION_TYPE_NUMBER);
}
void on_menu_item_z_none_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	set_type("z", ASSUMPTION_TYPE_NONE);
}
void on_menu_item_z_nonmatrix_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	set_type("z", ASSUMPTION_TYPE_NONMATRIX);
}
void on_menu_item_z_nonzero_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	set_sign("z", ASSUMPTION_SIGN_NONZERO);
}
void on_menu_item_z_positive_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	set_sign("z", ASSUMPTION_SIGN_POSITIVE);
}
void on_menu_item_z_nonnegative_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	set_sign("z", ASSUMPTION_SIGN_NONNEGATIVE);
}
void on_menu_item_z_negative_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	set_sign("z", ASSUMPTION_SIGN_NEGATIVE);
}
void on_menu_item_z_nonpositive_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	set_sign("z", ASSUMPTION_SIGN_NONPOSITIVE);
}
void on_menu_item_z_unknown_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	set_sign("z", ASSUMPTION_SIGN_UNKNOWN);
}

void menu_to_bin(GtkMenuItem*, gpointer) {
	int save_base = printops.base;
	to_base = 0;
	printops.base = BASE_BINARY;
	result_format_updated();
	printops.base = save_base;
}
void menu_to_oct(GtkMenuItem*, gpointer) {
	int save_base = printops.base;
	to_base = 0;
	printops.base = BASE_OCTAL;
	result_format_updated();
	printops.base = save_base;
}
void menu_to_duo(GtkMenuItem*, gpointer) {
	int save_base = printops.base;
	to_base = 0;
	printops.base = 12;
	result_format_updated();
	printops.base = save_base;
}
void menu_to_hex(GtkMenuItem*, gpointer) {
	int save_base = printops.base;
	to_base = 0;
	printops.base = BASE_HEXADECIMAL;
	result_format_updated();
	printops.base = save_base;
}
void menu_to_roman(GtkMenuItem*, gpointer) {
	int save_base = printops.base;
	to_base = 0;
	printops.base = BASE_ROMAN_NUMERALS;
	result_format_updated();
	printops.base = save_base;
}
void menu_to_utc(GtkMenuItem*, gpointer) {
	printops.time_zone = TIME_ZONE_UTC;
	result_format_updated();
	printops.time_zone = TIME_ZONE_LOCAL;
}
void menu_to_fraction(GtkMenuItem*, gpointer) {
	NumberFractionFormat save_format = printops.number_fraction_format;
	bool save_restrict_fraction_length = printops.restrict_fraction_length;
	printops.restrict_fraction_length = false;
	to_fraction = false;
	if(mstruct && mstruct->isNumber()) printops.number_fraction_format = FRACTION_COMBINED;
	else printops.number_fraction_format = FRACTION_FRACTIONAL;
	result_format_updated();
	printops.number_fraction_format = save_format;
	printops.restrict_fraction_length = save_restrict_fraction_length;
}
void menu_to_rectangular(GtkMenuItem*, gpointer) {
	ComplexNumberForm cnf_bak = evalops.complex_number_form;
	bool caf_bak = complex_angle_form;
	complex_angle_form = false;
	evalops.complex_number_form = COMPLEX_NUMBER_FORM_RECTANGULAR;
	executeCommand(COMMAND_EVAL);
	complex_angle_form = caf_bak;
	evalops.complex_number_form = cnf_bak;
}
void menu_to_exponential(GtkMenuItem*, gpointer) {
	ComplexNumberForm cnf_bak = evalops.complex_number_form;
	bool caf_bak = complex_angle_form;
	complex_angle_form = false;
	evalops.complex_number_form = COMPLEX_NUMBER_FORM_EXPONENTIAL;
	executeCommand(COMMAND_EVAL);
	complex_angle_form = caf_bak;
	evalops.complex_number_form = cnf_bak;
}
void menu_to_polar(GtkMenuItem*, gpointer) {
	ComplexNumberForm cnf_bak = evalops.complex_number_form;
	bool caf_bak = complex_angle_form;
	complex_angle_form = false;
	evalops.complex_number_form = COMPLEX_NUMBER_FORM_POLAR;
	executeCommand(COMMAND_EVAL);
	complex_angle_form = caf_bak;
	evalops.complex_number_form = cnf_bak;
}
void menu_to_angle(GtkMenuItem*, gpointer) {
	ComplexNumberForm cnf_bak = evalops.complex_number_form;
	bool caf_bak = complex_angle_form;
	complex_angle_form = true;
	evalops.complex_number_form = COMPLEX_NUMBER_FORM_CIS;
	executeCommand(COMMAND_EVAL);
	complex_angle_form = caf_bak;
	evalops.complex_number_form = cnf_bak;
}
void update_mb_to_menu() {
	GtkWidget *sub = GTK_WIDGET(gtk_builder_get_object(main_builder, "menu_to"));
	if(expression_has_changed && !rpn_mode && !auto_calculate) execute_expression(true);
	GtkWidget *item;
	GList *list = gtk_container_get_children(GTK_CONTAINER(sub));
	for(GList *l = list; l != NULL; l = l->next) {
		gtk_widget_destroy(GTK_WIDGET(l->data));
	}
	g_list_free(list);
	if(!mstruct || !displayed_mstruct || !contains_convertable_unit(*displayed_mstruct)) {
		bool b_date = (mstruct && displayed_mstruct && mstruct->isDateTime());
		bool b_integ = (mstruct && displayed_mstruct && mstruct->isInteger());
		bool b_complex = (mstruct && displayed_mstruct && contains_imaginary_number(*mstruct));
		bool b_rational = (mstruct && displayed_mstruct && contains_rational_number(*displayed_mstruct));
		if(b_date) {
			MENU_ITEM(_("Calendars"), on_popup_menu_item_calendarconversion_activate)
			MENU_ITEM("UTC", menu_to_utc)
			return;
		}
		bool base_sep = false;
		if(!b_complex) {
			MENU_ITEM(_("Number bases"), on_menu_item_convert_number_bases_activate)
			MENU_ITEM(_("Binary"), menu_to_bin)
			MENU_ITEM(_("Octal"), menu_to_oct)
			MENU_ITEM(_("Duodecimal"), menu_to_duo)
			MENU_ITEM(_("Hexadecimal"), menu_to_hex)
			if(b_integ) {
				MENU_ITEM(_("Roman"), menu_to_roman)
				MENU_SEPARATOR
				base_sep = true;
				MENU_ITEM(_("Factors"), on_menu_item_factorize_activate)
			} else if(displayed_mstruct && displayed_mstruct->containsType(STRUCT_ADDITION)) {
				MENU_SEPARATOR
				base_sep = true;
				MENU_ITEM(_("Factors"), on_menu_item_factorize_activate)
			}
		}
		if(b_rational) {
			if(!base_sep) {
				MENU_SEPARATOR
				base_sep = true;
			}
			MENU_ITEM(_("Fraction"), menu_to_fraction)
			if(b_complex) {
				MENU_SEPARATOR
			}
		}
		if(b_complex && evalops.complex_number_form != COMPLEX_NUMBER_FORM_RECTANGULAR) {MENU_ITEM(_("Rectangular form"), menu_to_rectangular)}
		if(b_complex && evalops.complex_number_form != COMPLEX_NUMBER_FORM_EXPONENTIAL) {MENU_ITEM(_("Exponential form"), menu_to_exponential)}
		if(b_complex && evalops.complex_number_form != COMPLEX_NUMBER_FORM_POLAR) {MENU_ITEM(_("Polar form"), menu_to_polar)}
		if(b_complex && (evalops.complex_number_form != COMPLEX_NUMBER_FORM_CIS || !complex_angle_form)) {MENU_ITEM(_("Angle/phasor notation"), menu_to_angle)}
		return;
	}
	MENU_ITEM(_("Base units"), on_menu_item_convert_to_base_units_activate);
	MENU_ITEM(_("Optimal unit"), on_menu_item_convert_to_best_unit_activate);
	MENU_ITEM(_("Optimal prefix"), on_menu_item_set_prefix_activate);
	MENU_SEPARATOR
	string s_cat;
	Unit *u_result = NULL;
	if(displayed_mstruct) u_result = find_exact_matching_unit(*displayed_mstruct);
	bool b_exact = (u_result != NULL);
	if(!u_result) u_result = CALCULATOR->findMatchingUnit(*mstruct);
	if(u_result) s_cat = u_result->category();
	vector<Unit*> to_us;
	size_t i_added = 0;
	if(u_result && u_result->isCurrency()) {
		Unit *u_local_currency = CALCULATOR->getLocalCurrency();
		const char *currency_units[] = {"USD", "GBP", "JPY", "CNY", "INR", "CAD", "BRL"};
		to_us.clear();
		if(latest_button_currency && latest_button_currency != u_result) to_us.push_back(latest_button_currency);
		for(size_t i = 0; i < 9 && to_us.size() < 6; i++) {
			Unit * u;
			if(i == 0) u = CALCULATOR->u_euro;
			else if(i == 1) u = u_local_currency;
			else u = CALCULATOR->getActiveUnit(currency_units[i - 2]);
			if(u && (!b_exact || u != u_result) && (i == 1 || !u->isHidden())) {
				bool b = false;
				for(size_t i2 = 0; i2 < to_us.size(); i2++) {
					if(u == to_us[i2]) {
						b = true;
						break;
					}
					if(string_is_less(u->title(true), to_us[i2]->title(true))) {
						to_us.insert(to_us.begin() + i2, u);
						b = true;
						break;
					}
				}
				if(!b) to_us.push_back(u);
			}
		}
		for(size_t i = 0; i < to_us.size(); i++) {
			MENU_ITEM_WITH_POINTER_AND_FLAG(to_us[i]->title(true).c_str(), convert_to_unit, to_us[i])
		}
		i_added = to_us.size();
		vector<Unit*> to_us2;
		for(size_t i = 0; i < CALCULATOR->units.size(); i++) {
			if(CALCULATOR->units[i]->isCurrency()) {
				Unit *u = CALCULATOR->units[i];
				if(u->isActive()) {
					bool b = false;
					if(u->isHidden() && (!b_exact || u != u_result) && u != u_local_currency) {
						for(int i2 = to_us2.size() - 1; i2 >= 0; i2--) {
							if(u->title(true) > to_us2[(size_t) i2]->title(true)) {
								if((size_t) i2 == to_us2.size() - 1) to_us2.push_back(u);
								else to_us2.insert(to_us2.begin() + (size_t) i2 + 1, u);
								b = true;
								break;
							}
						}
						if(!b) to_us2.insert(to_us2.begin(), u);
					} else {
						for(size_t i2 = 0; i2 < i_added; i2++) {
							if(u == to_us[i2]) {
								b = true;
								break;
							}
						}
						for(size_t i2 = to_us.size() - 1; !b && i2 >= i_added; i2--) {
							if(u->title(true) > to_us[i2]->title(true)) {
								if(i2 == to_us.size() - 1) to_us.push_back(u);
								else to_us.insert(to_us.begin() + i2 + 1, u);
								b = true;
							}
						}
						if(!b) to_us.insert(to_us.begin() + i_added, u);
					}
				}
			}
		}
		for(size_t i = i_added; i < to_us.size(); i++) {
			// Show further items in a submenu
			if(i == i_added) {SUBMENU_ITEM(_("more"), sub);}
			MENU_ITEM_WITH_POINTER_AND_FLAG(to_us[i]->title(true).c_str(), convert_to_unit, to_us[i])
		}
		if(to_us2.size() > 0) {SUBMENU_ITEM(_("more"), sub);}
		for(size_t i = 0; i < to_us2.size(); i++) {
			// Show further items in a submenu
			MENU_ITEM_WITH_POINTER_AND_FLAG(to_us2[i]->title(true).c_str(), convert_to_unit, to_us2[i])
		}
	} else if(!s_cat.empty()) {
		for(size_t i = 0; i < CALCULATOR->units.size(); i++) {
			if(CALCULATOR->units[i]->category() == s_cat) {
				Unit *u = CALCULATOR->units[i];
				if(u->isActive() && (!b_exact || u != u_result) && !u->isHidden()) {
					bool b = false;
					for(size_t i2 = 0; i2 < to_us.size(); i2++) {
						if(string_is_less(u->title(true), to_us[i2]->title(true))) {
							to_us.insert(to_us.begin() + i2, u);
							b = true;
							break;
						}
					}
					if(!b) to_us.push_back(u);
					i_added++;
				}
			}
		}
		for(size_t i = 0; i < to_us.size(); i++) {
			if(i + 4 == 10 && i + 1 != to_us.size()) {SUBMENU_ITEM(_("more"), sub);}
			MENU_ITEM_WITH_POINTER(to_us[i]->title(true).c_str(), convert_to_unit_noprefix, to_us[i])
		}
	}
	if(!i_added) {
		const char *si_units[] = {"m", "g", "s", "A", "K", "L", "J", "N"};
		vector<Unit*> to_us2;
		for(size_t i = 0; i < 8 && i_added + 3 < 10; i++) {
			Unit * u = CALCULATOR->getActiveUnit(si_units[i]);
			if(!u->isHidden() && (!b_exact || u != u_result)) {
				bool b = false;
				for(size_t i2 = 0; i2 < to_us.size(); i2++) {
					if(u == to_us[i2]) {
						b = true;
						break;
					}
				}
				for(size_t i2 = 0; !b && i2 < to_us2.size(); i2++) {
					if(string_is_less(u->title(true), to_us2[i2]->title(true))) {
						to_us2.insert(to_us2.begin() + i2, u);
						b = true;
						i_added++;
						break;
					}
				}
				if(!b) {
					to_us2.push_back(u);
					i_added++;
				}
			}
		}
		for(size_t i = 0; i < to_us2.size(); i++) {
			MENU_ITEM_WITH_POINTER(to_us2[i]->title(true).c_str(), convert_to_unit, to_us2[i])
		}
	}
}
gboolean on_mb_to_button_release_event(GtkWidget, GdkEventButton *event, gpointer) {
	if(b_busy) return TRUE;
	update_mb_to_menu();
	return FALSE;
}

void update_mb_units_menu() {
	GtkMenu *sub = GTK_MENU(gtk_builder_get_object(main_builder, "menu_units"));
	GtkWidget *item;
	GList *list = gtk_container_get_children(GTK_CONTAINER(sub));
	for(GList *l = list; l != NULL; l = l->next) {
		gtk_widget_destroy(GTK_WIDGET(l->data));
	}
	g_list_free(list);
	const char *si_units[] = {"m", "g", "s", "A", "K"};
	size_t i_added = 0;
	for(size_t i = recent_units.size(); i > 0; i--) {
		if(!recent_units[i - 1]->isLocal() && CALCULATOR->stillHasUnit(recent_units[i - 1])) {
			MENU_ITEM_WITH_POINTER(recent_units[i - 1]->title(true).c_str(), insert_unit, recent_units[i - 1])
			i_added++;
		}
	}
	for(size_t i = 0; i_added < 5 && i < 5; i++) {
		Unit * u = CALCULATOR->getActiveUnit(si_units[i]);
		if(u && !u->isHidden()) {
			MENU_ITEM_WITH_POINTER(u->title(true).c_str(), insert_unit, u)
			i_added++;
		}
	}
	
	MENU_SEPARATOR
	Prefix *p = CALCULATOR->getPrefix("giga");
	if(p) {MENU_ITEM_WITH_POINTER(p->longName(true, printops.use_unicode_signs).c_str(), insert_prefix, p);}
	p = CALCULATOR->getPrefix("mega");
	if(p) {MENU_ITEM_WITH_POINTER(p->longName(true, printops.use_unicode_signs).c_str(), insert_prefix, p);}
	p = CALCULATOR->getPrefix("kilo");
	if(p) {MENU_ITEM_WITH_POINTER(p->longName(true, printops.use_unicode_signs).c_str(), insert_prefix, p);}
	p = CALCULATOR->getPrefix("milli");
	if(p) {MENU_ITEM_WITH_POINTER(p->longName(true, printops.use_unicode_signs).c_str(), insert_prefix, p);}
	p = CALCULATOR->getPrefix("micro");
	if(p) {MENU_ITEM_WITH_POINTER(p->longName(true, printops.use_unicode_signs).c_str(), insert_prefix, p);}
}

void on_popup_menu_fx_edit_activate(GtkMenuItem *w, gpointer data) {
	edit_function_simple("", (MathFunction*) data, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")));
}
void on_popup_menu_fx_delete_activate(GtkMenuItem *w, gpointer data) {
	delete_function((MathFunction*) data);
	gtk_menu_popdown(GTK_MENU(gtk_builder_get_object(main_builder, "menu_fx")));
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "mb_fx")), FALSE);
	focus_keeping_selection();
}

gulong on_popup_menu_fx_edit_activate_handler = 0, on_popup_menu_fx_delete_activate_handler = 0;

gboolean on_menu_fx_popup_menu(GtkWidget*, gpointer data) {
	if(b_busy) return TRUE;
	if(on_popup_menu_fx_edit_activate_handler != 0) g_signal_handler_disconnect(gtk_builder_get_object(main_builder, "popup_menu_fx_edit"), on_popup_menu_fx_edit_activate_handler);
	if(on_popup_menu_fx_delete_activate_handler != 0) g_signal_handler_disconnect(gtk_builder_get_object(main_builder, "popup_menu_fx_delete"), on_popup_menu_fx_delete_activate_handler);
	on_popup_menu_fx_edit_activate_handler = g_signal_connect(gtk_builder_get_object(main_builder, "popup_menu_fx_edit"), "activate", G_CALLBACK(on_popup_menu_fx_edit_activate), data);
	on_popup_menu_fx_delete_activate_handler = g_signal_connect(gtk_builder_get_object(main_builder, "popup_menu_fx_delete"), "activate", G_CALLBACK(on_popup_menu_fx_delete_activate), data);
#if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 22
	gtk_menu_popup_at_pointer(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_fx")), NULL);
#else
	gtk_menu_popup(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_fx")), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time());
#endif
	return TRUE;
}

gboolean on_menu_fx_button_press(GtkWidget *widget, GdkEventButton *event, gpointer data) {
	/* Ignore double-clicks and triple-clicks */
	if(gdk_event_triggers_context_menu((GdkEvent *) event) && event->type == GDK_BUTTON_PRESS) {
		on_menu_fx_popup_menu(widget, data);
		return TRUE;
	}
	return FALSE;
}


void update_mb_fx_menu() {
	GtkMenu *sub = GTK_MENU(gtk_builder_get_object(main_builder, "menu_fx"));
	GtkWidget *item;
	GList *list = gtk_container_get_children(GTK_CONTAINER(sub));
	for(GList *l = list; l != NULL; l = l->next) {
		gtk_widget_destroy(GTK_WIDGET(l->data));
	}
	g_list_free(list);
	bool b = false;
	for(size_t i = 0; i < CALCULATOR->functions.size(); i++) {
		if(CALCULATOR->functions[i]->isLocal() && !CALCULATOR->functions[i]->isBuiltin() && CALCULATOR->functions[i]->isActive() && !CALCULATOR->functions[i]->isHidden()) {
			MENU_ITEM_WITH_POINTER(CALCULATOR->functions[i]->title(true).c_str(), insert_button_function, CALCULATOR->functions[i])
			g_signal_connect(G_OBJECT(item), "button-press-event", G_CALLBACK(on_menu_fx_button_press), CALCULATOR->functions[i]);
			g_signal_connect(G_OBJECT(item), "popup-menu", G_CALLBACK(on_menu_fx_popup_menu), (gpointer) CALCULATOR->functions[i]);
			b = true;
		}
	}
	bool b2 = false;
	for(size_t i = recent_functions.size(); i > 0; i--) {
		if(!recent_functions[i - 1]->isLocal() && CALCULATOR->stillHasFunction(recent_functions[i - 1])) {
			if(!b2 && b) {MENU_SEPARATOR}
			b2 = true;
			MENU_ITEM_WITH_POINTER(recent_functions[i - 1]->title(true).c_str(), insert_button_function_save, recent_functions[i - 1])
		}
	}
	if(b2 || b) {MENU_SEPARATOR}
	MENU_ITEM(_("All functions"), on_menu_item_manage_functions_activate);
}

void insert_button_sqrt2() {
	insert_text((CALCULATOR->f_sqrt->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext).name + "(2)").c_str());
}
void update_mb_pi_menu() {

	GtkMenu *sub = GTK_MENU(gtk_builder_get_object(main_builder, "menu_pi"));
	GtkWidget *item;
	GList *list = gtk_container_get_children(GTK_CONTAINER(sub));
	for(GList *l = list; l != NULL; l = l->next) {
		gtk_widget_destroy(GTK_WIDGET(l->data));
	}
	g_list_free(list);
	
	Variable *v = CALCULATOR->getActiveVariable("pythagoras");
	MENU_ITEM(v ? v->title(true).c_str() : SIGN_SQRT "2", insert_button_sqrt2)
	MENU_ITEM_WITH_POINTER(CALCULATOR->v_euler->title(true).c_str(), insert_button_variable, CALCULATOR->v_euler);
	v = CALCULATOR->getActiveVariable("golden");
	if(v) {MENU_ITEM_WITH_POINTER(v->title(true).c_str(), insert_button_variable, v);}
	MENU_SEPARATOR

	int i_added = 0;
	for(size_t i = recent_variables.size(); i > 0; i--) {
		if(!recent_variables[i - 1]->isLocal() && CALCULATOR->stillHasVariable(recent_variables[i - 1])) {
			MENU_ITEM_WITH_POINTER(recent_variables[i - 1]->title(true).c_str(), insert_variable, recent_variables[i - 1])
			i_added++;
		}
	}
	if(i_added < 5)	{
		v = CALCULATOR->getActiveVariable("c");
		if(v) {MENU_ITEM_WITH_POINTER(v->title(true).c_str(), insert_button_variable, v); i_added++;}
	}
	if(i_added < 5)	{
		v = CALCULATOR->getActiveVariable("newtonian_constant");
		if(v) {MENU_ITEM_WITH_POINTER(v->title(true).c_str(), insert_button_variable, v); i_added++;}
	}
	if(i_added < 5)	{
		v = CALCULATOR->getActiveVariable("planck");
		if(v) {MENU_ITEM_WITH_POINTER(v->title(true).c_str(), insert_button_variable, v); i_added++;}
	}
	if(i_added < 5)	{
		v = CALCULATOR->getActiveVariable("boltzmann");
		if(v) {MENU_ITEM_WITH_POINTER(v->title(true).c_str(), insert_button_variable, v); i_added++;}
	}
	if(i_added < 5)	{
		v = CALCULATOR->getActiveVariable("avogadro");
		if(v) {MENU_ITEM_WITH_POINTER(v->title(true).c_str(), insert_button_variable, v); i_added++;}
	}
	
	MENU_SEPARATOR
	MENU_ITEM(_("All variables"), on_menu_item_manage_variables_activate);
	
}

void on_popup_menu_sto_set_activate(GtkMenuItem *w, gpointer data) {
	((KnownVariable*) data)->set(*mstruct);
	gtk_menu_popdown(GTK_MENU(gtk_builder_get_object(main_builder, "menu_sto")));
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "mb_sto")), FALSE);
	focus_keeping_selection();
}
void on_popup_menu_sto_edit_activate(GtkMenuItem *w, gpointer data) {
	edit_variable("", (Variable*) data, NULL, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")));
}
void on_popup_menu_sto_delete_activate(GtkMenuItem *w, gpointer data) {
	delete_variable((Variable*) data);
	gtk_menu_popdown(GTK_MENU(gtk_builder_get_object(main_builder, "menu_sto")));
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "mb_sto")), FALSE);
	focus_keeping_selection();
}

gulong on_popup_menu_sto_set_activate_handler = 0, on_popup_menu_sto_edit_activate_handler = 0, on_popup_menu_sto_delete_activate_handler = 0;

gboolean on_menu_sto_popup_menu(GtkWidget*, gpointer data) {
	if(b_busy) return TRUE;
	if(on_popup_menu_sto_set_activate_handler != 0) g_signal_handler_disconnect(gtk_builder_get_object(main_builder, "popup_menu_sto_set"), on_popup_menu_sto_set_activate_handler);
	if(on_popup_menu_sto_edit_activate_handler != 0) g_signal_handler_disconnect(gtk_builder_get_object(main_builder, "popup_menu_sto_edit"), on_popup_menu_sto_edit_activate_handler);
	if(on_popup_menu_sto_delete_activate_handler != 0) g_signal_handler_disconnect(gtk_builder_get_object(main_builder, "popup_menu_sto_delete"), on_popup_menu_sto_delete_activate_handler);
	if(((Variable*) data)->isKnown() && mstruct && displayed_mstruct) {
		on_popup_menu_sto_set_activate_handler = g_signal_connect(gtk_builder_get_object(main_builder, "popup_menu_sto_set"), "activate", G_CALLBACK(on_popup_menu_sto_set_activate), data);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_sto_set")), TRUE);
	} else {
		on_popup_menu_sto_set_activate_handler = 0;
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_sto_set")), FALSE);
	}
	on_popup_menu_sto_edit_activate_handler = g_signal_connect(gtk_builder_get_object(main_builder, "popup_menu_sto_edit"), "activate", G_CALLBACK(on_popup_menu_sto_edit_activate), data);
	on_popup_menu_sto_delete_activate_handler = g_signal_connect(gtk_builder_get_object(main_builder, "popup_menu_sto_delete"), "activate", G_CALLBACK(on_popup_menu_sto_delete_activate), data);
#if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 22
	gtk_menu_popup_at_pointer(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_sto")), NULL);
#else
	gtk_menu_popup(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_sto")), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time());
#endif
	return TRUE;
}

gboolean on_menu_sto_button_press(GtkWidget *widget, GdkEventButton *event, gpointer data) {
	/* Ignore double-clicks and triple-clicks */
	if(gdk_event_triggers_context_menu((GdkEvent *) event) && event->type == GDK_BUTTON_PRESS) {
		on_menu_sto_popup_menu(widget, data);
		return TRUE;
	}
	return FALSE;
}

void update_mb_sto_menu() {
	GtkMenu *sub = GTK_MENU(gtk_builder_get_object(main_builder, "menu_sto"));
	GtkWidget *item;
	GList *list = gtk_container_get_children(GTK_CONTAINER(sub));
	for(GList *l = list; l != NULL; l = l->next) {
		gtk_widget_destroy(GTK_WIDGET(l->data));
	}
	g_list_free(list);
	bool b = false;
	for(size_t i = 0; i < CALCULATOR->variables.size(); i++) {
		if(CALCULATOR->variables[i]->isLocal() && !CALCULATOR->variables[i]->isBuiltin() && CALCULATOR->variables[i]->isActive() && !CALCULATOR->variables[i]->isHidden()) {
			MENU_ITEM_WITH_POINTER(CALCULATOR->variables[i]->title(true).c_str(), insert_button_variable, CALCULATOR->variables[i])
			g_signal_connect(G_OBJECT(item), "button-press-event", G_CALLBACK(on_menu_sto_button_press), CALCULATOR->variables[i]);
			g_signal_connect(G_OBJECT(item), "popup-menu", G_CALLBACK(on_menu_sto_popup_menu), (gpointer) CALCULATOR->variables[i]);
			b = true;
		}
	}
	if(!b) {MENU_NO_ITEMS(_("No items found"))}
}


void on_menu_item_enable_variables_activate(GtkMenuItem *w, gpointer) {
	evalops.parse_options.variables_enabled = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
	expression_format_updated(evalops.parse_options.variables_enabled);
}
void on_menu_item_enable_functions_activate(GtkMenuItem *w, gpointer) {
	evalops.parse_options.functions_enabled = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
	expression_format_updated(evalops.parse_options.functions_enabled);
}
void on_menu_item_enable_units_activate(GtkMenuItem *w, gpointer) {
	evalops.parse_options.units_enabled = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
	expression_format_updated(evalops.parse_options.units_enabled);
}
void on_menu_item_enable_unknown_variables_activate(GtkMenuItem *w, gpointer) {
	evalops.parse_options.unknowns_enabled = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
	expression_format_updated(evalops.parse_options.unknowns_enabled);
}
void on_menu_item_calculate_variables_activate(GtkMenuItem *w, gpointer) {
	evalops.calculate_variables = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
	expression_calculation_updated();
}
void on_menu_item_enable_variable_units_activate(GtkMenuItem *w, gpointer) {
	CALCULATOR->setVariableUnitsEnabled(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)));
	expression_calculation_updated();
}
void on_menu_item_allow_complex_activate(GtkMenuItem *w, gpointer) {
	evalops.allow_complex = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
	expression_calculation_updated();
}
void on_menu_item_allow_infinite_activate(GtkMenuItem *w, gpointer) {
	evalops.allow_infinite = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
	expression_calculation_updated();
}
void on_menu_item_assume_nonzero_denominators_activate(GtkMenuItem *w, gpointer) {
	evalops.assume_denominators_nonzero = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
	expression_calculation_updated();
}
void on_menu_item_warn_about_denominators_assumed_nonzero_activate(GtkMenuItem *w, gpointer) {
	evalops.warn_about_denominators_assumed_nonzero = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
	if(evalops.warn_about_denominators_assumed_nonzero) expression_calculation_updated();
}
void on_menu_item_algebraic_mode_simplify_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	evalops.structuring = STRUCTURING_SIMPLIFY;
	printops.allow_factorization = false;
	gtk_widget_hide(item_factorize);
	gtk_widget_show(item_simplify);
	PangoFontDescription *font_desc;
	gtk_style_context_get(gtk_widget_get_style_context(GTK_WIDGET(gtk_builder_get_object(main_builder, "label_factorize"))), GTK_STATE_FLAG_NORMAL, GTK_STYLE_PROPERTY_FONT, &font_desc, NULL);
	gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "label_factorize")), (string("a(x)") + SUP_STRING("b")).c_str());
	pango_font_description_free(font_desc);
	gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_factorize")), _("Factorize"));
	expression_calculation_updated();
}
void on_menu_item_algebraic_mode_factorize_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	evalops.structuring = STRUCTURING_FACTORIZE;
	printops.allow_factorization = true;
	gtk_widget_show(item_factorize);
	gtk_widget_hide(item_simplify);
	PangoFontDescription *font_desc;
	gtk_style_context_get(gtk_widget_get_style_context(GTK_WIDGET(gtk_builder_get_object(main_builder, "label_factorize"))), GTK_STATE_FLAG_NORMAL, GTK_STYLE_PROPERTY_FONT, &font_desc, NULL);
	gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "label_factorize")), (string("x+x") + SUP_STRING("b")).c_str());
	pango_font_description_free(font_desc);
	gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_factorize")), _("Expand"));
	expression_calculation_updated();
}
void on_menu_item_read_precision_activate(GtkMenuItem *w, gpointer) {
	 if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) evalops.parse_options.read_precision = READ_PRECISION_WHEN_DECIMALS;
	 else evalops.parse_options.read_precision = DONT_READ_PRECISION;
	 expression_format_updated(true);
}
void on_menu_item_new_unknown_activate(GtkMenuItem*, gpointer) {
	edit_unknown(_("My Variables"), NULL, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")));
}
void on_menu_item_new_variable_activate(GtkMenuItem*, gpointer) {
	edit_variable(_("My Variables"), NULL, NULL, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")));
}
void on_menu_item_new_matrix_activate(GtkMenuItem*, gpointer) {
	edit_matrix(_("Matrices"), NULL, NULL, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")), FALSE);
}
void on_menu_item_new_vector_activate(GtkMenuItem*, gpointer) {
	edit_matrix(_("Vectors"), NULL, NULL, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")), TRUE);
}
void on_menu_item_new_function_activate(GtkMenuItem*, gpointer) {
	edit_function("", NULL, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")));
}
void on_menu_item_new_function_simple_activate(GtkMenuItem*, gpointer) {
	edit_function_simple("", NULL, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")));
}
void on_menu_item_new_dataset_activate(GtkMenuItem*, gpointer) {
	edit_dataset(NULL, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")));
}
void on_menu_item_new_unit_activate(GtkMenuItem*, gpointer) {
	edit_unit("", NULL, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")));
}

void on_menu_item_autocalc_activate(GtkMenuItem *w, gpointer) {
	if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)) == auto_calculate) return;
	auto_calculate = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
	if(auto_calculate && !rpn_mode) do_auto_calc();
}
void on_menu_item_rpn_mode_activate(GtkMenuItem *w, gpointer) {
	set_rpn_mode(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)));
}
void on_menu_item_rpn_syntax_activate(GtkMenuItem *w, gpointer) {
	evalops.parse_options.rpn = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
	expression_format_updated(false);
}
void on_menu_item_limit_implicit_multiplication_activate(GtkMenuItem *w, gpointer) {
	evalops.parse_options.limit_implicit_multiplication = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
	printops.limit_implicit_multiplication = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
	expression_format_updated(true);
	result_format_updated();
}
void on_menu_item_adaptive_parsing_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	evalops.parse_options.parsing_mode = PARSING_MODE_ADAPTIVE;
	expression_format_updated(true);
}
void on_menu_item_ignore_whitespace_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	evalops.parse_options.parsing_mode = PARSING_MODE_IMPLICIT_MULTIPLICATION_FIRST;
	expression_format_updated(true);
}
void on_menu_item_no_special_implicit_multiplication_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	evalops.parse_options.parsing_mode = PARSING_MODE_CONVENTIONAL;
	expression_format_updated(true);
}

void on_menu_item_fetch_exchange_rates_activate(GtkMenuItem*, gpointer) {
	do_timeout = false;
	fetch_exchange_rates(15);
	CALCULATOR->loadExchangeRates();
	display_errors(NULL, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")));
	do_timeout = true;
	while(gtk_events_pending()) gtk_main_iteration();
	expression_calculation_updated();
}
void on_menu_item_save_defs_activate(GtkMenuItem*, gpointer) {
	save_defs();
}
void on_menu_item_import_definitions_activate(GtkMenuItem*, gpointer) {
	GtkWidget *d = gtk_file_chooser_dialog_new(_("Select definitions file"), GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), GTK_FILE_CHOOSER_ACTION_OPEN, _("_Cancel"), GTK_RESPONSE_CANCEL, _("_Import"), GTK_RESPONSE_ACCEPT, NULL);
	gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(d), TRUE);
	GtkFileFilter *filter = gtk_file_filter_new();
	//gtk_file_filter_set_name(filter, _("XML Files"));
	gtk_file_filter_add_mime_type(filter, "text/xml");
	gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(d), filter);
	if(gtk_dialog_run(GTK_DIALOG(d)) == GTK_RESPONSE_ACCEPT) {
		GFile *file = gtk_file_chooser_get_file(GTK_FILE_CHOOSER(d));
		char *str = g_file_get_basename(file);
		char *from_file = g_file_get_path(file);
		string homedir = buildPath(getLocalDataDir(), "definitions");
		recursiveMakeDir(homedir);
#ifdef _WIN32
		if(CopyFile(from_file, buildPath(homedir, str).c_str(), false) != 0) {
			CALCULATOR->loadDefinitions(buildPath(homedir, str).c_str(), false, true);
			update_fmenu();
			update_vmenu();
			update_umenus();
		} else {
			GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(mainwindow), (GtkDialogFlags) 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("Could not copy %s to %s."), from_file, buildPath(homedir, str).c_str());
			gtk_dialog_run(GTK_DIALOG(dialog));
			gtk_widget_destroy(dialog);
		}
#else
		ifstream source(from_file);
		if(source.fail()) {
			source.close();
			GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(mainwindow), (GtkDialogFlags) 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("Could not read %s."), from_file);
			gtk_dialog_run(GTK_DIALOG(dialog));
			gtk_widget_destroy(dialog);
		} else {
			ofstream dest(buildPath(homedir, str).c_str());
			if(dest.fail()) {
				source.close();
				dest.close();
				GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(mainwindow), (GtkDialogFlags) 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("Could not copy file to %s."), homedir.c_str());
				gtk_dialog_run(GTK_DIALOG(dialog));
				gtk_widget_destroy(dialog);
			} else {
				dest << source.rdbuf();
				source.close();
				dest.close();
				CALCULATOR->loadDefinitions(buildPath(homedir, str).c_str(), false, true);
				update_fmenu();
				update_vmenu();
				update_umenus();
			}
		}
#endif
		g_free(str);
		g_free(from_file);
		g_object_unref(file);
	}
	gtk_widget_destroy(d);
}
void on_menu_item_save_mode_activate(GtkMenuItem*, gpointer) {
	save_mode();
}
void on_menu_item_edit_prefs_activate(GtkMenuItem*, gpointer) {
	edit_preferences();
}
void on_menu_item_degrees_activate(GtkMenuItem *w, gpointer) {
	if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) {
		evalops.parse_options.angle_unit = ANGLE_UNIT_DEGREES;
		expression_format_updated(true);
	}
}
void on_menu_item_radians_activate(GtkMenuItem *w, gpointer) {
	if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) {
		evalops.parse_options.angle_unit = ANGLE_UNIT_RADIANS;
		expression_format_updated(true);
	}
}
void on_menu_item_gradians_activate(GtkMenuItem *w, gpointer) {
	if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) {
		evalops.parse_options.angle_unit = ANGLE_UNIT_GRADIANS;
		expression_format_updated(true);
	}
}
void on_menu_item_no_default_angle_unit_activate(GtkMenuItem *w, gpointer) {
	if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) {
		evalops.parse_options.angle_unit = ANGLE_UNIT_NONE;
		expression_format_updated(true);
	}
}

void set_output_base_from_dialog(int base) {
	bool b = (printops.base == base && base != BASE_CUSTOM);
	to_base = 0;
	printops.base = base;
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_combo_output_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_combo_output_other_changed, NULL);
	switch(printops.base) {
		case BASE_BINARY: {
			g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_binary"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_binary_activate, NULL);
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_binary")), TRUE);
			g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_binary"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_binary_activate, NULL);
			g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_base"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_base_changed, NULL);
			gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_base")), 0);
			g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_base"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_base_changed, NULL);
			output_base_updated_from_menu();
			break;
		}
		case BASE_OCTAL: {
			g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_octal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_octal_activate, NULL);
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_octal")), TRUE);
			g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_octal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_octal_activate, NULL);
			g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_base"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_base_changed, NULL);
			gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_base")), 1);
			g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_base"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_base_changed, NULL);
			output_base_updated_from_menu();
			break;
		}
		case BASE_DECIMAL: {
			g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_decimal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_decimal_activate, NULL);
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_decimal")), TRUE);
			g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_decimal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_decimal_activate, NULL);
			g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_base"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_base_changed, NULL);
			gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_base")), 2);
			g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_base"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_base_changed, NULL);
			output_base_updated_from_menu();
			break;
		}
		case 12: {
			g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_duodecimal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_decimal_activate, NULL);
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_duodecimal")), TRUE);
			g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_duodecimal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_decimal_activate, NULL);
			g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_base"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_base_changed, NULL);
			gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_base")), 3);
			g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_base"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_base_changed, NULL);
			output_base_updated_from_menu();
			break;
		}
		case BASE_HEXADECIMAL: {
			g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_hexadecimal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_hexadecimal_activate, NULL);
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_hexadecimal")), TRUE);
			g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_hexadecimal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_hexadecimal_activate, NULL);
			g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_base"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_base_changed, NULL);
			gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_base")), 4);
			g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_base"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_base_changed, NULL);
			output_base_updated_from_menu();
			break;
		}
		case BASE_SEXAGESIMAL: {
			g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_sexagesimal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_hexadecimal_activate, NULL);
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_sexagesimal")), TRUE);
			g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_sexagesimal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_hexadecimal_activate, NULL);
			g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_base"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_base_changed, NULL);
			gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_base")), 5);
			g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_base"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_base_changed, NULL);
			break;
		}
		case BASE_TIME: {
			g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_time_format"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_hexadecimal_activate, NULL);
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_time_format")), TRUE);
			g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_time_format"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_hexadecimal_activate, NULL);
			g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_base"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_base_changed, NULL);
			gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_base")), 6);
			g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_base"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_base_changed, NULL);
			break;
		}
		case BASE_ROMAN_NUMERALS: {
			g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_roman"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_hexadecimal_activate, NULL);
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_roman")), TRUE);
			g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_roman"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_hexadecimal_activate, NULL);
			g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_base"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_base_changed, NULL);
			gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_base")), 7);
			g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_base"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_base_changed, NULL);
			break;
		}
		default: {
			g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_custom_base"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_custom_base_activate, NULL);
			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_custom_base")), TRUE);
			g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_custom_base"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_custom_base_activate, NULL);
			g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_base"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_base_changed, NULL);
			gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_base")), 8);
			g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_base"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_base_changed, NULL);
			g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_input_other_toggled, NULL);
			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other")), TRUE);
			g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_input_other_toggled, NULL);
			break;
		}
	}
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_combo_output_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_combo_output_other_changed, NULL);
	update_keypad_bases();
	if(!b) result_format_updated();
}
void output_base_updated_from_menu() {
	if(setbase_builder) {
		g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_combo_output_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_combo_output_other_changed, NULL);
		switch(printops.base) {
			case BASE_BINARY: {
				g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_binary"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_output_binary_toggled, NULL);
				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_binary")), TRUE);
				g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_binary"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_output_binary_toggled, NULL);
				break;
			}
			case BASE_OCTAL: {
				g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_octal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_output_octal_toggled, NULL);
				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_octal")), TRUE);
				g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_octal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_output_octal_toggled, NULL);
				break;
			}
			case BASE_DECIMAL: {
				g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_decimal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_output_decimal_toggled, NULL);
				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_decimal")), TRUE);
				g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_decimal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_output_decimal_toggled, NULL);
				break;
			}
			case 12: {
				g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_duodecimal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_output_duodecimal_toggled, NULL);
				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_duodecimal")), TRUE);
				g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_duodecimal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_output_duodecimal_toggled, NULL);
				break;
			}
			case BASE_HEXADECIMAL: {
				g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_hexadecimal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_output_hexadecimal_toggled, NULL);
				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_hexadecimal")), TRUE);
				g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_hexadecimal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_output_hexadecimal_toggled, NULL);
				break;
			}
			case BASE_SEXAGESIMAL: {
				g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_sexagesimal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_output_sexagesimal_toggled, NULL);
				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_sexagesimal")), TRUE);
				g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_sexagesimal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_output_sexagesimal_toggled, NULL);
				break;
			}
			case BASE_TIME: {
				g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_time"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_output_time_toggled, NULL);
				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_time")), TRUE);
				g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_time"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_output_time_toggled, NULL);
				break;
			}
			case BASE_ROMAN_NUMERALS: {
				g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_roman"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_output_roman_toggled, NULL);
				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_roman")), TRUE);
				g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_roman"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_output_roman_toggled, NULL);
				break;
			}
			case BASE_UNICODE: {
				g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_output_other_toggled, NULL);
				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other")), TRUE);
				g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_output_other_toggled, NULL);
				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_output_other")), "Unicode");
				break;
			}
			case BASE_E: {
				g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_output_other_toggled, NULL);
				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other")), TRUE);
				g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_output_other_toggled, NULL);
				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_output_other")), "e");
				break;
			}
			case BASE_PI: {
				g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_output_other_toggled, NULL);
				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other")), TRUE);
				g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_output_other_toggled, NULL);
				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_output_other")), "π");
				break;
			}
			case BASE_GOLDEN_RATIO: {
				g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_output_other_toggled, NULL);
				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other")), TRUE);
				g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_output_other_toggled, NULL);
				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_output_other")), "φ");
				break;
			}
			case BASE_SUPER_GOLDEN_RATIO: {
				g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_output_other_toggled, NULL);
				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other")), TRUE);
				g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_output_other_toggled, NULL);
				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_output_other")), "ψ");
				break;
			}
			case BASE_SQRT2: {
				g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_output_other_toggled, NULL);
				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other")), TRUE);
				g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_output_other_toggled, NULL);
				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_output_other")), "√2");
				break;
			}
			case BASE_BIJECTIVE_26: {
				g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_output_other_toggled, NULL);
				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other")), TRUE);
				g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_output_other_toggled, NULL);
				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_output_other")), _("Bijective base-26"));
				break;
			}
			case BASE_CUSTOM: {
				g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_output_other_toggled, NULL);
				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other")), TRUE);
				g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_output_other_toggled, NULL);
				PrintOptions po = printops;
				po.number_fraction_format = FRACTION_DECIMAL_EXACT;
				po.interval_display = INTERVAL_DISPLAY_PLUSMINUS;
				po.preserve_precision = true;
				po.base = 10;
				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_output_other")), CALCULATOR->customOutputBase().print(po).c_str());
				break;
			}
			default: {
				g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_output_other_toggled, NULL);
				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other")), TRUE);
				g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_output_other_toggled, NULL);
				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_output_other")), i2s(printops.base).c_str());
			}
		}
		g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_combo_output_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_combo_output_other_changed, NULL);
	}
}
void input_base_updated_from_menu() {
	if(setbase_builder) {
		g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_combo_input_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_combo_input_other_changed, NULL);
		switch(evalops.parse_options.base) {
			case BASE_BINARY: {
				g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_binary"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_input_binary_toggled, NULL);
				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_binary")), TRUE);
				g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_binary"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_input_binary_toggled, NULL);
				break;
			}
			case BASE_OCTAL: {
				g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_octal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_input_octal_toggled, NULL);
				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_octal")), TRUE);
				g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_octal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_input_octal_toggled, NULL);
				break;
			}
			case BASE_DECIMAL: {
				g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_decimal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_input_decimal_toggled, NULL);
				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_decimal")), TRUE);
				g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_decimal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_input_decimal_toggled, NULL);
				break;
			}
			case 12: {
				g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_duodecimal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_input_duodecimal_toggled, NULL);
				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_duodecimal")), TRUE);
				g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_duodecimal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_input_duodecimal_toggled, NULL);
				break;
			}
			case BASE_HEXADECIMAL: {
				g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_hexadecimal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_input_hexadecimal_toggled, NULL);
				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_hexadecimal")), TRUE);
				g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_hexadecimal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_input_hexadecimal_toggled, NULL);
				break;
			}
			case BASE_UNICODE: {
				g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_input_other_toggled, NULL);
				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_other")), TRUE);
				g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_input_other_toggled, NULL);
				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_input_other")), "Unicode");
				break;
			}
			case BASE_E: {
				g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_input_other_toggled, NULL);
				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_other")), TRUE);
				g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_input_other_toggled, NULL);
				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_input_other")), "e");
				break;
			}
			case BASE_PI: {
				g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_input_other_toggled, NULL);
				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_other")), TRUE);
				g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_input_other_toggled, NULL);
				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_input_other")), "π");
				break;
			}
			case BASE_GOLDEN_RATIO: {
				g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_input_other_toggled, NULL);
				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_other")), TRUE);
				g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_input_other_toggled, NULL);
				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_input_other")), "φ");
				break;
			}
			case BASE_SUPER_GOLDEN_RATIO: {
				g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_input_other_toggled, NULL);
				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_other")), TRUE);
				g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_input_other_toggled, NULL);
				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_input_other")), "ψ");
				break;
			}
			case BASE_SQRT2: {
				g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_input_other_toggled, NULL);
				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_other")), TRUE);
				g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_input_other_toggled, NULL);
				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_input_other")), "√2");
				break;
			}
			case BASE_BIJECTIVE_26: {
				g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_input_other_toggled, NULL);
				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_other")), TRUE);
				g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_input_other_toggled, NULL);
				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_input_other")), _("Bijective base-26"));
				break;
			}
			case BASE_CUSTOM: {
				g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_input_other_toggled, NULL);
				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_other")), TRUE);
				g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_input_other_toggled, NULL);
				PrintOptions po = printops;
				po.number_fraction_format = FRACTION_DECIMAL_EXACT;
				po.interval_display = INTERVAL_DISPLAY_PLUSMINUS;
				po.preserve_precision = true;
				po.base = 10;
				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_input_other")), CALCULATOR->customInputBase().print(po).c_str());
				break;
			}
			default: {
				g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_input_other_toggled, NULL);
				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_other")), TRUE);
				g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_input_other_toggled, NULL);
				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_input_other")), i2s(evalops.parse_options.base).c_str());
			}
		}
		g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_combo_input_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_combo_input_other_changed, NULL);
	}
}


void on_menu_item_binary_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	to_base = 0;
	printops.base = BASE_BINARY;
	output_base_updated_from_menu();
	update_keypad_bases();
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_base"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_base_changed, NULL);
	gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_base")), 0);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_base"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_base_changed, NULL);
	result_format_updated();
}
void on_menu_item_octal_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	to_base = 0;
	printops.base = BASE_OCTAL;
	output_base_updated_from_menu();
	update_keypad_bases();
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_base"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_base_changed, NULL);
	gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_base")), 1);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_base"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_base_changed, NULL);
	result_format_updated();
}
void on_menu_item_decimal_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	to_base = 0;
	printops.base = BASE_DECIMAL;
	output_base_updated_from_menu();
	update_keypad_bases();
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_base"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_base_changed, NULL);
	gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_base")), 2);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_base"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_base_changed, NULL);
	result_format_updated();
}
void on_menu_item_duodecimal_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	to_base = 0;
	printops.base = 12;
	output_base_updated_from_menu();
	update_keypad_bases();
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_base"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_base_changed, NULL);
	gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_base")), 3);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_base"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_base_changed, NULL);
	result_format_updated();
}
void on_menu_item_hexadecimal_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	to_base = 0;
	printops.base = BASE_HEXADECIMAL;
	output_base_updated_from_menu();
	update_keypad_bases();
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_base"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_base_changed, NULL);
	gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_base")), 4);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_base"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_base_changed, NULL);
	result_format_updated();
}
void on_menu_item_custom_base_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	GtkWidget *dialog = get_set_base_dialog();
	gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")));
	gtk_widget_show(dialog);
	gtk_window_present(GTK_WINDOW(dialog));
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other")), TRUE);
	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(setbase_builder, "set_base_entry_output_other")));
}
void on_menu_item_roman_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	to_base = 0;
	printops.base = BASE_ROMAN_NUMERALS;
	output_base_updated_from_menu();
	update_keypad_bases();
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_base"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_base_changed, NULL);
	gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_base")), 7);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_base"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_base_changed, NULL);
	result_format_updated();
}
void on_menu_item_sexagesimal_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	to_base = 0;
	printops.base = BASE_SEXAGESIMAL;
	output_base_updated_from_menu();
	update_keypad_bases();
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_base"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_base_changed, NULL);
	gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_base")), 5);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_base"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_base_changed, NULL);
	result_format_updated();
}
void on_menu_item_time_format_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	to_base = 0;
	printops.base = BASE_TIME;
	output_base_updated_from_menu();
	update_keypad_bases();
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_base"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_base_changed, NULL);
	gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_base")), 6);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_base"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_base_changed, NULL);
	result_format_updated();
}
void on_set_base_combo_output_other_changed(GtkComboBox*, gpointer) {
	string str = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_output_other")));
	remove_blank_ends(str);
	if(str == "φ" || str == "ψ" || str == "π" || str == "√2" || str == "e" || str == "-3" || str == "-2" || str == "-10" || str == "20" || str == "36" || str == "62" || str == "Unicode" || str == _("Bijective base-26")) on_set_base_entry_output_other_activate(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_output_other")), NULL);
}
void on_set_base_entry_output_other_activate(GtkEntry *w, gpointer) {
	string str = gtk_entry_get_text(w);
	remove_blank_ends(str);
	if(str.empty() || str == prev_output_base) {prev_output_base = str; return;}
	if(equalsIgnoreCase(str, "golden") || equalsIgnoreCase(str, "golden ratio") || str == "φ") {set_output_base_from_dialog(BASE_GOLDEN_RATIO); return;}
	else if(equalsIgnoreCase(str, "Bijective base-26") || equalsIgnoreCase(str, _("Bijective base-26")) || str == "b26" || str == "B26") {set_output_base_from_dialog(BASE_BIJECTIVE_26); return;}
	else if(equalsIgnoreCase(str, "unicode")) {set_output_base_from_dialog(BASE_UNICODE); return;}
	else if(equalsIgnoreCase(str, "supergolden") || equalsIgnoreCase(str, "supergolden ratio") || str == "ψ") {set_output_base_from_dialog(BASE_SUPER_GOLDEN_RATIO); return;}
	else if(equalsIgnoreCase(str, "pi") || str == "π") {set_output_base_from_dialog(BASE_PI); return;}
	else if(str == "e") {set_output_base_from_dialog(BASE_E); return;}
	else if(str == "sqrt(2)" || str == "sqrt 2" || str == "sqrt2" || str == "√2") {set_output_base_from_dialog(BASE_SQRT2); return;}
	EvaluationOptions eo = evalops;
	eo.parse_options.base = 10;
	eo.approximation = APPROXIMATION_TRY_EXACT;
	int base;
	MathStructure m;
	CALCULATOR->beginTemporaryStopMessages();
	CALCULATOR->calculate(&m, CALCULATOR->unlocalizeExpression(str, eo.parse_options), 500, eo);
	if(CALCULATOR->endTemporaryStopMessages() || !m.isNumber() || !m.number().isReal() || (m.number().isNegative() && !m.number().isInteger()) || !(m.number() > 1 || m.number() < -1)) {
		prev_output_base = str;
		show_message(_("Unsupported base."), GTK_WIDGET(gtk_builder_get_object(setbase_builder, "set_base_dialog")));
		return;
	}
	if(m.isInteger() && m.number() >= 2 && m.number() <= 36) {
		base = m.number().intValue();
	} else {
		base = BASE_CUSTOM;
		CALCULATOR->setCustomOutputBase(m.number());
		prev_output_base = str;
	}
	set_output_base_from_dialog(base);
	if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other")))) {
		g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_combo_output_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_combo_output_other_changed, NULL);
		gtk_entry_set_text(w, "");
		g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_combo_output_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_combo_output_other_changed, NULL);
	}
}
gboolean on_set_base_entry_output_other_focus_out_event(GtkWidget *w, GdkEvent*, gpointer data) {
	on_set_base_entry_output_other_activate(GTK_ENTRY(w), data);
	return FALSE;
}
void on_set_base_radiobutton_output_binary_toggled(GtkToggleButton *w, gpointer) {
	if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) return;
	set_output_base_from_dialog(BASE_BINARY);
}
void on_set_base_radiobutton_output_octal_toggled(GtkToggleButton *w, gpointer) {
	if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) return;
	set_output_base_from_dialog(BASE_OCTAL);
}
void on_set_base_radiobutton_output_decimal_toggled(GtkToggleButton *w, gpointer) {
	if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) return;
	set_output_base_from_dialog(BASE_DECIMAL);
}
void on_set_base_radiobutton_output_duodecimal_toggled(GtkToggleButton *w, gpointer) {
	if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) return;
	set_output_base_from_dialog(12);
}
void on_set_base_radiobutton_output_hexadecimal_toggled(GtkToggleButton *w, gpointer) {
	if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) return;
	set_output_base_from_dialog(BASE_HEXADECIMAL);
}
void on_set_base_radiobutton_output_sexagesimal_toggled(GtkToggleButton *w, gpointer) {
	if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) return;
	set_output_base_from_dialog(BASE_SEXAGESIMAL);
}
void on_set_base_radiobutton_output_time_toggled(GtkToggleButton *w, gpointer) {
	if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) return;
	set_output_base_from_dialog(BASE_TIME);
}
void on_set_base_radiobutton_output_roman_toggled(GtkToggleButton *w, gpointer) {
	if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) return;
	set_output_base_from_dialog(BASE_ROMAN_NUMERALS);
}
void on_set_base_radiobutton_output_other_toggled(GtkToggleButton *w, gpointer) {
	if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) return;
	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(setbase_builder, "set_base_entry_output_other")));
	string str = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_output_other")));
	remove_blank_ends(str);
	if(str.empty()) {prev_output_base = str; return;}
	if(equalsIgnoreCase(str, "golden") || equalsIgnoreCase(str, "golden ratio") || str == "φ") {set_output_base_from_dialog(BASE_GOLDEN_RATIO); return;}
	else if(equalsIgnoreCase(str, "Bijective base-26") || equalsIgnoreCase(str, _("Bijective base-26")) || str == "b26" || str == "B26") {set_output_base_from_dialog(BASE_BIJECTIVE_26); return;}
	else if(equalsIgnoreCase(str, "unicode")) {set_output_base_from_dialog(BASE_UNICODE); return;}
	else if(equalsIgnoreCase(str, "supergolden") || equalsIgnoreCase(str, "supergolden ratio") || str == "ψ") {set_output_base_from_dialog(BASE_SUPER_GOLDEN_RATIO); return;}
	else if(equalsIgnoreCase(str, "pi") || str == "π") {set_output_base_from_dialog(BASE_PI); return;}
	else if(str == "e") {set_output_base_from_dialog(BASE_E); return;}
	else if(str == "sqrt(2)" || str == "sqrt 2" || str == "sqrt2" || str == "√2") {set_output_base_from_dialog(BASE_SQRT2); return;}
	EvaluationOptions eo = evalops;
	eo.parse_options.base = 10;
	eo.approximation = APPROXIMATION_TRY_EXACT;
	int base;
	MathStructure m;
	CALCULATOR->beginTemporaryStopMessages();
	CALCULATOR->calculate(&m, CALCULATOR->unlocalizeExpression(str, eo.parse_options), 500, eo);
	if(CALCULATOR->endTemporaryStopMessages() || !m.isNumber() || !m.number().isReal() || (m.number().isNegative() && !m.number().isInteger()) || !(m.number() > 1 || m.number() < -1)) {
		prev_output_base = str;
		show_message(_("Unsupported base."), GTK_WIDGET(gtk_builder_get_object(setbase_builder, "set_base_dialog")));
		return;
	}
	if(m.isInteger() && m.number() >= 2 && m.number() <= 36) {
		base = m.number().intValue();
	} else {
		base = BASE_CUSTOM;
		CALCULATOR->setCustomOutputBase(m.number());
		prev_output_base = str;
	}
	set_output_base_from_dialog(base);
	if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other")))) {
		g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_combo_output_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_combo_output_other_changed, NULL);
		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_output_other")), "");
		g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_combo_output_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_combo_output_other_changed, NULL);
	}
}
void on_menu_item_set_base_activate(GtkMenuItem*, gpointer) {
	GtkWidget *dialog = get_set_base_dialog();
	gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")));
	gtk_widget_show(dialog);
	gtk_window_present(GTK_WINDOW(dialog));
}
void on_set_base_radiobutton_input_binary_toggled(GtkToggleButton *w, gpointer) {
	if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) return;
	evalops.parse_options.base = BASE_BINARY;
	on_historyview_selection_changed(NULL, NULL);
	update_keypad_bases();
	expression_format_updated(true);
}
void on_set_base_radiobutton_input_octal_toggled(GtkToggleButton *w, gpointer) {
	if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) return;
	evalops.parse_options.base = BASE_OCTAL;
	on_historyview_selection_changed(NULL, NULL);
	update_keypad_bases();
	expression_format_updated(true);
}
void on_set_base_radiobutton_input_decimal_toggled(GtkToggleButton *w, gpointer) {
	if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) return;
	evalops.parse_options.base = BASE_DECIMAL;
	on_historyview_selection_changed(NULL, NULL);
	update_keypad_bases();
	expression_format_updated(true);
}
void on_set_base_radiobutton_input_duodecimal_toggled(GtkToggleButton *w, gpointer) {
	if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) return;
	evalops.parse_options.base = 12;
	on_historyview_selection_changed(NULL, NULL);
	update_keypad_bases();
	expression_format_updated(true);
}
void on_set_base_radiobutton_input_hexadecimal_toggled(GtkToggleButton *w, gpointer) {
	if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) return;
	evalops.parse_options.base = BASE_HEXADECIMAL;
	on_historyview_selection_changed(NULL, NULL);
	update_keypad_bases();
	expression_format_updated(true);
}
void on_set_base_radiobutton_input_other_toggled(GtkToggleButton *w, gpointer) {
	if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) return;
	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(setbase_builder, "set_base_entry_input_other")));
	string str = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_input_other")));
	remove_blank_ends(str);
	if(str.empty() || str == prev_input_base) {prev_input_base = str; return;}
	if(equalsIgnoreCase(str, "golden") || equalsIgnoreCase(str, "golden ratio") || str == "φ") {evalops.parse_options.base = BASE_GOLDEN_RATIO;}
	else if(equalsIgnoreCase(str, "Bijective base-26") || equalsIgnoreCase(str, _("Bijective base-26")) || str == "b26" || str == "B26") {evalops.parse_options.base = BASE_BIJECTIVE_26;}
	else if(equalsIgnoreCase(str, "unicode")) {evalops.parse_options.base = BASE_UNICODE;}
	else if(equalsIgnoreCase(str, "supergolden") || equalsIgnoreCase(str, "supergolden ratio") || str == "ψ") {evalops.parse_options.base = BASE_SUPER_GOLDEN_RATIO;}
	else if(equalsIgnoreCase(str, "pi") || str == "π") {evalops.parse_options.base = BASE_PI;}
	else if(str == "e") {evalops.parse_options.base = BASE_E;}
	else if(str == "sqrt(2)" || str == "sqrt 2" || str == "sqrt2" || str == "√2") {evalops.parse_options.base = BASE_SQRT2;}
	else {
		EvaluationOptions eo = evalops;
		eo.parse_options.base = 10;
		eo.approximation = APPROXIMATION_TRY_EXACT;
		MathStructure m;
		CALCULATOR->beginTemporaryStopMessages();
		CALCULATOR->calculate(&m, CALCULATOR->unlocalizeExpression(str, eo.parse_options), 500, eo);
		if(CALCULATOR->endTemporaryStopMessages() || !m.isNumber()) {
			prev_input_base = str;
			show_message(_("Unsupported base."), GTK_WIDGET(gtk_builder_get_object(setbase_builder, "set_base_dialog")));
			return;
		}
		if(m.isInteger() && m.number() >= 2 && m.number() <= 36) {
			evalops.parse_options.base = m.number().intValue();
			if(evalops.parse_options.base == 2 || evalops.parse_options.base == 8 || evalops.parse_options.base == 10 || evalops.parse_options.base == 12 || evalops.parse_options.base == 16) input_base_updated_from_menu();
		} else {
			evalops.parse_options.base = BASE_CUSTOM;
			CALCULATOR->setCustomInputBase(m.number());
		}
	}
	prev_input_base = str;
	on_historyview_selection_changed(NULL, NULL);
	update_keypad_bases();
	expression_format_updated(true);
	if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_other")))) {
		g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_combo_input_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_combo_input_other_changed, NULL);
		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_input_other")), "");
		g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_combo_input_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_combo_input_other_changed, NULL);
	}
}
void on_set_base_combo_input_other_changed(GtkComboBox*, gpointer) {
	string str = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_input_other")));
	remove_blank_ends(str);
	if(str == "φ" || str == "ψ" || str == "π" || str == "√2" || str == "e" || str == "-3" || str == "-2" || str == "-10" || str == "20" || str == "36" || str == "62" || str == "Unicode" || str == _("Bijective base-26")) on_set_base_entry_input_other_activate(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_input_other")), NULL);
}
void on_set_base_entry_input_other_activate(GtkEntry *w, gpointer) {
	string str = gtk_entry_get_text(w);
	remove_blank_ends(str);
	if(str.empty() || str == prev_input_base) {prev_input_base = str; return;}
	if(str.empty() || str == prev_input_base) {prev_input_base = str; return;}
	if(equalsIgnoreCase(str, "golden") || equalsIgnoreCase(str, "golden ratio") || str == "φ") {evalops.parse_options.base = BASE_GOLDEN_RATIO;}
	else if(equalsIgnoreCase(str, "Bijective base-26") || equalsIgnoreCase(str, _("Bijective base-26")) || str == "b26" || str == "B26") {evalops.parse_options.base = BASE_BIJECTIVE_26;}
	else if(equalsIgnoreCase(str, "unicode")) {evalops.parse_options.base = BASE_UNICODE;}
	else if(equalsIgnoreCase(str, "supergolden") || equalsIgnoreCase(str, "supergolden ratio") || str == "ψ") {evalops.parse_options.base = BASE_SUPER_GOLDEN_RATIO;}
	else if(equalsIgnoreCase(str, "pi") || str == "π") {evalops.parse_options.base = BASE_PI;}
	else if(str == "e") {evalops.parse_options.base = BASE_E;}
	else if(str == "sqrt(2)" || str == "sqrt 2" || str == "sqrt2" || str == "√2") {evalops.parse_options.base = BASE_SQRT2;}
	else {
		EvaluationOptions eo = evalops;
		eo.parse_options.base = 10;
		eo.approximation = APPROXIMATION_TRY_EXACT;
		MathStructure m;
		CALCULATOR->beginTemporaryStopMessages();
		CALCULATOR->calculate(&m, CALCULATOR->unlocalizeExpression(str, eo.parse_options), 500, eo);
		if(CALCULATOR->endTemporaryStopMessages() || !m.isNumber()) {
			prev_input_base = str;
			show_message(_("Unsupported base."), GTK_WIDGET(gtk_builder_get_object(setbase_builder, "set_base_dialog")));
			return;
		}
		if(m.isInteger() && m.number() >= 2 && m.number() <= 36) {
			evalops.parse_options.base = m.number().intValue();
			if(evalops.parse_options.base == 2 || evalops.parse_options.base == 8 || evalops.parse_options.base == 10 || evalops.parse_options.base == 12 || evalops.parse_options.base == 16) {
				input_base_updated_from_menu();
				g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_combo_input_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_combo_input_other_changed, NULL);
				gtk_entry_set_text(w, "");
				g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_combo_input_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_combo_input_other_changed, NULL);
			}
		} else {
			evalops.parse_options.base = BASE_CUSTOM;
			CALCULATOR->setCustomInputBase(m.number());
		}
	}
	if(evalops.parse_options.base != 2 && evalops.parse_options.base != 8 && evalops.parse_options.base != 10 && evalops.parse_options.base != 12 && evalops.parse_options.base != 16) {
		g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_input_other_toggled, NULL);
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_other")), TRUE);
		g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_other"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_set_base_radiobutton_input_other_toggled, NULL);
	}
	prev_input_base = str;
	on_historyview_selection_changed(NULL, NULL);
	update_keypad_bases();
	expression_format_updated(true);
}
gboolean on_set_base_entry_input_other_focus_out_event(GtkEntry *w, GdkEvent*, gpointer data) {
	on_set_base_entry_input_other_activate(w, data);
	return FALSE;
}
void on_set_base_radiobutton_input_roman_toggled(GtkToggleButton *w, gpointer) {
	if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) return;
	evalops.parse_options.base = BASE_ROMAN_NUMERALS;
	on_historyview_selection_changed(NULL, NULL);
	update_keypad_bases();
	expression_format_updated(true);
}
void on_menu_item_abbreviate_names_activate(GtkMenuItem *w, gpointer) {
	printops.abbreviate_names = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
	result_format_updated();
}
void on_menu_item_all_prefixes_activate(GtkMenuItem *w, gpointer) {
	to_prefix = 0;
	printops.use_all_prefixes = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
	result_format_updated();
}
void on_menu_item_denominator_prefixes_activate(GtkMenuItem *w, gpointer) {
	to_prefix = 0;
	printops.use_denominator_prefix = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
	result_format_updated();
}
void on_menu_item_place_units_separately_activate(GtkMenuItem *w, gpointer) {
	printops.place_units_separately = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
	result_format_updated();
}
void on_menu_item_post_conversion_none_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	evalops.auto_post_conversion = POST_CONVERSION_NONE;
	expression_calculation_updated();
}
void on_menu_item_post_conversion_base_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	evalops.auto_post_conversion = POST_CONVERSION_BASE;
	expression_calculation_updated();
}
void on_menu_item_post_conversion_optimal_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	evalops.auto_post_conversion = POST_CONVERSION_OPTIMAL;
	expression_calculation_updated();
}
void on_menu_item_post_conversion_optimal_si_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	evalops.auto_post_conversion = POST_CONVERSION_OPTIMAL_SI;
	expression_calculation_updated();
}
void on_menu_item_mixed_units_conversion_activate(GtkMenuItem *w, gpointer) {
	if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) evalops.mixed_units_conversion = MIXED_UNITS_CONVERSION_DEFAULT;
	else evalops.mixed_units_conversion = MIXED_UNITS_CONVERSION_NONE;
	expression_calculation_updated();
}
void on_menu_item_factorize_activate(GtkMenuItem*, gpointer) {
	executeCommand(COMMAND_FACTORIZE);
}
void on_menu_item_expand_partial_fractions_activate(GtkMenuItem*, gpointer) {
	executeCommand(COMMAND_EXPAND_PARTIAL_FRACTIONS);
}
void on_menu_item_simplify_activate(GtkMenuItem*, gpointer) {
	executeCommand(COMMAND_EXPAND);
}
void convert_number_bases(const gchar *initial_expression, bool b_result) {
	changing_in_nbases_dialog = false;
	GtkWidget *dialog = get_nbases_dialog();
	gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")));
	switch(b_result ? displayed_printops.base : evalops.parse_options.base) {
		case BASE_BINARY: {
			gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(nbases_builder, "nbases_entry_binary")), initial_expression);
			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_entry_binary")));
			break;
		}
		case BASE_OCTAL: {
			gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(nbases_builder, "nbases_entry_octal")), initial_expression);
			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_entry_octal")));
			break;
		}
		case BASE_HEXADECIMAL: {
			gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(nbases_builder, "nbases_entry_hexadecimal")), initial_expression);
			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_entry_hexadecimal")));
			break;
		}
		case BASE_DUODECIMAL: {
			gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(nbases_builder, "nbases_entry_duo")), initial_expression);
			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_entry_duo")));
			break;
		}
		case BASE_ROMAN_NUMERALS: {
			gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(nbases_builder, "nbases_entry_roman")), initial_expression);
			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_entry_roman")));
			break;
		}
		default: {
			gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(nbases_builder, "nbases_entry_decimal")), initial_expression);
			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_entry_decimal")));
		}
	}	
	gtk_widget_show(dialog);
	gtk_window_present(GTK_WINDOW(dialog));
}
void on_menu_item_convert_number_bases_activate(GtkMenuItem*, gpointer) {
	if(!result_text.empty()) return convert_number_bases(result_text.c_str(), true);
	string str = get_selected_expression_text(true), str2;
	CALCULATOR->separateToExpression(str, str2, evalops, true);
	convert_number_bases(str.c_str(), false);
}
void show_percentage_dialog(const gchar *initial_expression) {
	GtkWidget *dialog = get_percentage_dialog();
	gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")));
	on_percentage_button_clear_clicked(NULL, NULL);
	if(strlen(initial_expression) > 0 && strcmp(initial_expression, "0") != 0) gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(percentage_builder, "percentage_entry_1")), initial_expression);
	gtk_widget_show(dialog);
	gtk_window_present(GTK_WINDOW(dialog));
}
void on_menu_item_show_percentage_dialog_activate(GtkMenuItem*, gpointer) {
	if(!result_text.empty()) return show_percentage_dialog(result_text.c_str());
	string str = get_selected_expression_text(true), str2;
	CALCULATOR->separateToExpression(str, str2, evalops, true);
	show_percentage_dialog(str.c_str());
}
void show_calendarconversion_dialog() {
	GtkWidget *dialog = get_calendarconversion_dialog();
	gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")));
	gtk_widget_show(dialog);
	gtk_window_present(GTK_WINDOW(dialog));
}
bool block_calendar_conversion = false;
void calendar_changed(GtkWidget*, gpointer data) {
	if(block_calendar_conversion) return;
	block_calendar_conversion = true;
	gint i = GPOINTER_TO_INT(data);
	long int y;
	if(i == CALENDAR_CHINESE) {
		long int cy = chineseStemBranchToCycleYear((gtk_combo_box_get_active(GTK_COMBO_BOX(chinese_stem)) * 2) + 1, gtk_combo_box_get_active(GTK_COMBO_BOX(chinese_branch)) + 1);
		if(cy <= 0) {
			show_message(_("The selected Chinese year does not exist."), GTK_WIDGET(gtk_builder_get_object(calendarconversion_builder, "calendar_dialog")));
			block_calendar_conversion = false;
			return;
		}
		y = chineseCycleYearToYear(79, cy);
	} else {
		y = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(cal_year[(size_t) i]));
	}
	long int m = gtk_combo_box_get_active(GTK_COMBO_BOX(cal_month[(size_t) i])) + 1;
	long int d = gtk_combo_box_get_active(GTK_COMBO_BOX(cal_day[(size_t) i])) + 1;
	QalculateDateTime date;
	if(!calendarToDate(date, y, m, d, (CalendarSystem) i)) {
		show_message(_("Conversion to Gregorian calendar failed."), GTK_WIDGET(gtk_builder_get_object(calendarconversion_builder, "calendar_dialog")));
		block_calendar_conversion = false;
		return;
	}
	string failed_str;
	for(size_t i2 = 0; i2 < NUMBER_OF_CALENDARS; i2++) {
		if(cal_day.count(i2) > 0) {
			if(dateToCalendar(date, y, m, d, (CalendarSystem) i2) && y <= G_MAXINT && y >= G_MININT && m <= numberOfMonths((CalendarSystem) i2) && d <= 31) {
				if(i2 == CALENDAR_CHINESE) {
					long int cy, yc, st, br;
					chineseYearInfo(y, cy, yc, st, br);
					gtk_combo_box_set_active(GTK_COMBO_BOX(chinese_stem), (st - 1) / 2);
					gtk_combo_box_set_active(GTK_COMBO_BOX(chinese_branch), br - 1);
				} else {
					gtk_spin_button_set_value(GTK_SPIN_BUTTON(cal_year[i2]), y);
				}
				gtk_combo_box_set_active(GTK_COMBO_BOX(cal_month[i2]), m - 1);
				gtk_combo_box_set_active(GTK_COMBO_BOX(cal_day[i2]), d - 1);
			} else {
				if(!failed_str.empty()) failed_str += ", ";
				failed_str += gtk_label_get_text(GTK_LABEL(cal_label[i2]));
			}
		}
	}
	if(!failed_str.empty()) {
		gchar *gstr = g_strdup_printf(_("Calendar conversion failed for: %s."), failed_str.c_str());
		show_message(gstr, GTK_WIDGET(gtk_builder_get_object(calendarconversion_builder, "calendar_dialog")));
		g_free(gstr);
	}
	block_calendar_conversion = false;
}

void on_menu_item_show_calendarconversion_dialog_activate(GtkMenuItem*, gpointer) {
	show_calendarconversion_dialog();
	if(displayed_mstruct && mstruct && mstruct->isDateTime()) {
		gtk_spin_button_set_value(GTK_SPIN_BUTTON(cal_year[CALENDAR_GREGORIAN]), mstruct->datetime()->year());
		gtk_combo_box_set_active(GTK_COMBO_BOX(cal_month[CALENDAR_GREGORIAN]), mstruct->datetime()->month() - 1);
		gtk_combo_box_set_active(GTK_COMBO_BOX(cal_day[CALENDAR_GREGORIAN]), mstruct->datetime()->day() - 1);
	}
}
void on_popup_menu_item_calendarconversion_activate(GtkMenuItem *w, gpointer) {
	show_calendarconversion_dialog();
	if(mstruct && mstruct->isDateTime()) {
		gtk_spin_button_set_value(GTK_SPIN_BUTTON(cal_year[CALENDAR_GREGORIAN]), mstruct->datetime()->year());
		gtk_combo_box_set_active(GTK_COMBO_BOX(cal_month[CALENDAR_GREGORIAN]), mstruct->datetime()->month() - 1);
		gtk_combo_box_set_active(GTK_COMBO_BOX(cal_day[CALENDAR_GREGORIAN]), mstruct->datetime()->day() - 1);
	}
}
void on_popup_menu_item_to_utc_activate(GtkMenuItem *w, gpointer) {
	menu_to_utc(w, NULL);
}
void on_menu_item_periodic_table_activate(GtkMenuItem*, gpointer) {
	GtkWidget *dialog = get_periodic_dialog();
	gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")));
	gtk_widget_show(dialog);
	gtk_window_present(GTK_WINDOW(dialog));
}
void on_menu_item_plot_functions_activate(GtkMenuItem*, gpointer) {
	GtkWidget *dialog = get_plot_dialog();
	gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")));
	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_expression")), get_selected_expression_text(true).c_str());
	if(!gtk_widget_get_visible(dialog)) {
		gtk_list_store_clear(tPlotFunctions_store);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_button_modify")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_button_remove")), FALSE);

		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_checkbutton_grid")), default_plot_display_grid);
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_checkbutton_full_border")), default_plot_full_border);
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_checkbutton_rows")), default_plot_rows);
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_radiobutton_color")), default_plot_color);
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_radiobutton_mono")), !default_plot_color);
		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_min")), default_plot_min.c_str());
		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_max")), default_plot_max.c_str());
		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_step")), default_plot_step.c_str());
		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_variable")), default_plot_variable.c_str());
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_radiobutton_steps")), default_plot_use_sampling_rate);
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_radiobutton_step")), !default_plot_use_sampling_rate);
		switch(default_plot_type) {
			case 1: {gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_radiobutton_vector")), TRUE); break;}
			case 2: {gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_radiobutton_paired")), TRUE); break;}
			default: {gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_radiobutton_function")), TRUE); break;}
		}
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_checkbutton_rows")), default_plot_type == 1 || default_plot_type == 2);	
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_box_variable")), default_plot_type != 1 && default_plot_type != 2);	
		switch(default_plot_legend_placement) {
			case PLOT_LEGEND_NONE: {gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(plot_builder, "plot_combobox_legend_place")), PLOTLEGEND_MENU_NONE); break;}
			case PLOT_LEGEND_TOP_LEFT: {gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(plot_builder, "plot_combobox_legend_place")), PLOTLEGEND_MENU_TOP_LEFT); break;}
			case PLOT_LEGEND_TOP_RIGHT: {gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(plot_builder, "plot_combobox_legend_place")), PLOTLEGEND_MENU_TOP_RIGHT); break;}
			case PLOT_LEGEND_BOTTOM_LEFT: {gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(plot_builder, "plot_combobox_legend_place")), PLOTLEGEND_MENU_BOTTOM_LEFT); break;}
			case PLOT_LEGEND_BOTTOM_RIGHT: {gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(plot_builder, "plot_combobox_legend_place")), PLOTLEGEND_MENU_BOTTOM_RIGHT); break;}
			case PLOT_LEGEND_BELOW: {gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(plot_builder, "plot_combobox_legend_place")), PLOTLEGEND_MENU_BELOW); break;}
			case PLOT_LEGEND_OUTSIDE: {gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(plot_builder, "plot_combobox_legend_place")), PLOTLEGEND_MENU_OUTSIDE); break;}
		}
		switch(default_plot_smoothing) {
			case PLOT_SMOOTHING_NONE: {gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(plot_builder, "plot_combobox_smoothing")), SMOOTHING_MENU_NONE); break;}
			case PLOT_SMOOTHING_UNIQUE: {gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(plot_builder, "plot_combobox_smoothing")), SMOOTHING_MENU_UNIQUE); break;}
			case PLOT_SMOOTHING_CSPLINES: {gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(plot_builder, "plot_combobox_smoothing")), SMOOTHING_MENU_CSPLINES); break;}
			case PLOT_SMOOTHING_BEZIER: {gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(plot_builder, "plot_combobox_smoothing")), SMOOTHING_MENU_BEZIER); break;}
			case PLOT_SMOOTHING_SBEZIER: {gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(plot_builder, "plot_combobox_smoothing")), SMOOTHING_MENU_SBEZIER); break;}
		}
		switch(default_plot_style) {
			case PLOT_STYLE_LINES: {gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(plot_builder, "plot_combobox_style")), PLOTSTYLE_MENU_LINES); break;}
			case PLOT_STYLE_POINTS: {gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(plot_builder, "plot_combobox_style")), PLOTSTYLE_MENU_LINES); break;}
			case PLOT_STYLE_POINTS_LINES: {gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(plot_builder, "plot_combobox_style")), PLOTSTYLE_MENU_LINESPOINTS); break;}
			case PLOT_STYLE_BOXES: {gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(plot_builder, "plot_combobox_style")), PLOTSTYLE_MENU_BOXES); break;}
			case PLOT_STYLE_HISTOGRAM: {gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(plot_builder, "plot_combobox_style")), PLOTSTYLE_MENU_HISTEPS); break;}
			case PLOT_STYLE_STEPS: {gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(plot_builder, "plot_combobox_style")), PLOTSTYLE_MENU_STEPS); break;}
			case PLOT_STYLE_CANDLESTICKS: {gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(plot_builder, "plot_combobox_style")), PLOTSTYLE_MENU_CANDLESTICKS); break;}
			case PLOT_STYLE_DOTS: {gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(plot_builder, "plot_combobox_style")), PLOTSTYLE_MENU_DOTS); break;}
		}
		gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(plot_builder, "plot_spinbutton_steps")), default_plot_sampling_rate);
		gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(plot_builder, "plot_spinbutton_linewidth")), default_plot_linewidth);
		
		gtk_widget_show(dialog);
		gtk_notebook_set_current_page(GTK_NOTEBOOK(gtk_builder_get_object(plot_builder, "plot_notebook")), 2);
		gtk_notebook_set_current_page(GTK_NOTEBOOK(gtk_builder_get_object(plot_builder, "plot_notebook")), 1);
		gtk_notebook_set_current_page(GTK_NOTEBOOK(gtk_builder_get_object(plot_builder, "plot_notebook")), 0);
		
		gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_entry_expression")));
	} else {
		gtk_window_present(GTK_WINDOW(dialog));
	}
}
void on_plot_dialog_hide(GtkWidget*, gpointer) {
	default_plot_display_grid = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_checkbutton_grid")));
	default_plot_full_border = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_checkbutton_full_border")));
	default_plot_rows = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_checkbutton_rows")));
	default_plot_color = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_radiobutton_color")));
	default_plot_min = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_min")));
	default_plot_max = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_max")));
	default_plot_step = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_step")));
	default_plot_variable = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_variable")));
	default_plot_use_sampling_rate = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_radiobutton_steps")));
	if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_radiobutton_vector")))) {
		default_plot_type = 1;
	} else if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_radiobutton_paired")))) {
		default_plot_type = 2;
	} else {
		default_plot_type = 0;
	}
	switch(gtk_combo_box_get_active(GTK_COMBO_BOX(gtk_builder_get_object(plot_builder, "plot_combobox_legend_place")))) {
		case PLOTLEGEND_MENU_NONE: {default_plot_legend_placement = PLOT_LEGEND_NONE; break;}
		case PLOTLEGEND_MENU_TOP_LEFT: {default_plot_legend_placement = PLOT_LEGEND_TOP_LEFT; break;}
		case PLOTLEGEND_MENU_TOP_RIGHT: {default_plot_legend_placement = PLOT_LEGEND_TOP_RIGHT; break;}
		case PLOTLEGEND_MENU_BOTTOM_LEFT: {default_plot_legend_placement = PLOT_LEGEND_BOTTOM_LEFT; break;}
		case PLOTLEGEND_MENU_BOTTOM_RIGHT: {default_plot_legend_placement = PLOT_LEGEND_BOTTOM_RIGHT; break;}
		case PLOTLEGEND_MENU_BELOW: {default_plot_legend_placement = PLOT_LEGEND_BELOW; break;}
		case PLOTLEGEND_MENU_OUTSIDE: {default_plot_legend_placement = PLOT_LEGEND_OUTSIDE; break;}
	}
	switch(gtk_combo_box_get_active(GTK_COMBO_BOX(gtk_builder_get_object(plot_builder, "plot_combobox_smoothing")))) {
		case SMOOTHING_MENU_NONE: {default_plot_smoothing = PLOT_SMOOTHING_NONE; break;}
		case SMOOTHING_MENU_UNIQUE: {default_plot_smoothing = PLOT_SMOOTHING_UNIQUE; break;}
		case SMOOTHING_MENU_CSPLINES: {default_plot_smoothing = PLOT_SMOOTHING_CSPLINES; break;}
		case SMOOTHING_MENU_BEZIER: {default_plot_smoothing = PLOT_SMOOTHING_BEZIER; break;}
		case SMOOTHING_MENU_SBEZIER: {default_plot_smoothing = PLOT_SMOOTHING_SBEZIER; break;}
	}
	switch(gtk_combo_box_get_active(GTK_COMBO_BOX(gtk_builder_get_object(plot_builder, "plot_combobox_style")))) {
		case PLOTSTYLE_MENU_LINES: {default_plot_style = PLOT_STYLE_LINES; break;}
		case PLOTSTYLE_MENU_POINTS: {default_plot_style = PLOT_STYLE_POINTS; break;}
		case PLOTSTYLE_MENU_LINESPOINTS: {default_plot_style = PLOT_STYLE_POINTS_LINES; break;}
		case PLOTSTYLE_MENU_BOXES: {default_plot_style = PLOT_STYLE_BOXES; break;}
		case PLOTSTYLE_MENU_HISTEPS: {default_plot_style = PLOT_STYLE_HISTOGRAM; break;}
		case PLOTSTYLE_MENU_STEPS: {default_plot_style = PLOT_STYLE_STEPS; break;}
		case PLOTSTYLE_MENU_CANDLESTICKS: {default_plot_style = PLOT_STYLE_CANDLESTICKS; break;}
		case PLOTSTYLE_MENU_DOTS: {default_plot_style = PLOT_STYLE_DOTS; break;}
	}
	default_plot_sampling_rate = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_builder_get_object(plot_builder, "plot_spinbutton_steps")));
	default_plot_linewidth = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_builder_get_object(plot_builder, "plot_spinbutton_linewidth")));
	GtkTreeIter iter;
	bool b = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tPlotFunctions_store), &iter);
	while(b) {
		MathStructure *y_vector, *x_vector;
		gtk_tree_model_get(GTK_TREE_MODEL(tPlotFunctions_store), &iter, 7, &x_vector, 8, &y_vector, -1);
		if(y_vector) delete y_vector;
		if(x_vector) delete x_vector;
		b = gtk_tree_model_iter_next(GTK_TREE_MODEL(tPlotFunctions_store), &iter);
	}
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_button_save")), false);
	CALCULATOR->closeGnuplot();
}
void on_popup_menu_item_abort_activate(GtkMenuItem*, gpointer) {
	if(b_busy_expression) on_abort_calculation(NULL, 0, NULL);
	else if(b_busy_result) on_abort_display(NULL, 0, NULL);
	else if(b_busy_command) on_abort_command(NULL, 0, NULL);
}
void on_popup_menu_item_clear_activate(GtkMenuItem*, gpointer) {
	clear_expression_text();
	focus_keeping_selection();
}
void on_popup_menu_item_display_normal_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	printops.negative_exponents = false;
	printops.sort_options.minus_last = true;
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_display_normal")), TRUE);

	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_negative_exponents"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_negative_exponents_activate, NULL);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_sort_minus_last"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_sort_minus_last_activate, NULL);
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_negative_exponents")), printops.negative_exponents);
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_sort_minus_last")), printops.sort_options.minus_last);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_negative_exponents"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_negative_exponents_activate, NULL);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_sort_minus_last"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_sort_minus_last_activate, NULL);
}
void on_popup_menu_item_assume_nonzero_denominators_activate(GtkMenuItem *w, gpointer) {
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_assume_nonzero_denominators")), gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)));
}
void on_popup_menu_item_display_engineering_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_display_engineering")), TRUE);
}
void on_popup_menu_item_display_scientific_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	printops.negative_exponents = true;
	printops.sort_options.minus_last = false;
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_display_scientific")), TRUE);

	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_negative_exponents"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_negative_exponents_activate, NULL);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_sort_minus_last"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_sort_minus_last_activate, NULL);
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_negative_exponents")), printops.negative_exponents);
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_sort_minus_last")), printops.sort_options.minus_last);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_negative_exponents"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_negative_exponents_activate, NULL);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_sort_minus_last"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_sort_minus_last_activate, NULL);
}
void on_popup_menu_item_display_purely_scientific_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	printops.negative_exponents = true;
	printops.sort_options.minus_last = false;
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_display_purely_scientific")), TRUE);

	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_negative_exponents"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_negative_exponents_activate, NULL);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_sort_minus_last"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_sort_minus_last_activate, NULL);
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_negative_exponents")), printops.negative_exponents);
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_sort_minus_last")), printops.sort_options.minus_last);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_negative_exponents"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_negative_exponents_activate, NULL);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_sort_minus_last"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_sort_minus_last_activate, NULL);
}
void on_popup_menu_item_display_non_scientific_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	printops.negative_exponents = false;
	printops.sort_options.minus_last = true;
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_display_non_scientific")), TRUE);

	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_negative_exponents"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_negative_exponents_activate, NULL);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_sort_minus_last"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_sort_minus_last_activate, NULL);
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_negative_exponents")), printops.negative_exponents);
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_sort_minus_last")), printops.sort_options.minus_last);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_negative_exponents"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_negative_exponents_activate, NULL);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_sort_minus_last"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_sort_minus_last_activate, NULL);
}
void on_popup_menu_item_complex_rectangular_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_complex_rectangular")), TRUE);
}
void on_popup_menu_item_complex_exponential_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_complex_exponential")), TRUE);
}
void on_popup_menu_item_complex_polar_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_complex_polar")), TRUE);
}
void on_popup_menu_item_complex_angle_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_complex_angle")), TRUE);
}
void on_popup_menu_item_display_no_prefixes_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_display_no_prefixes")), TRUE);
}
void on_popup_menu_item_display_prefixes_for_selected_units_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_display_prefixes_for_selected_units")), TRUE);
}
void on_popup_menu_item_display_prefixes_for_all_units_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_display_prefixes_for_all_units")), TRUE);
}
void on_popup_menu_item_display_prefixes_for_currencies_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_display_prefixes_for_currencies")), TRUE);
}
void on_popup_menu_item_fraction_decimal_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_fraction_decimal")), TRUE);
}
void on_popup_menu_item_fraction_decimal_exact_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_fraction_decimal_exact")), TRUE);
}
void on_popup_menu_item_fraction_combined_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_fraction_combined")), TRUE);
}
void on_popup_menu_item_fraction_fraction_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_fraction_fraction")), TRUE);
}
void on_popup_menu_item_binary_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_binary")), TRUE);
}
void on_popup_menu_item_roman_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_roman")), TRUE);
}
void on_popup_menu_item_sexagesimal_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_sexagesimal")), TRUE);
}
void on_popup_menu_item_time_format_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_time_format")), TRUE);
}
void on_popup_menu_item_octal_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_octal")), TRUE);
}
void on_popup_menu_item_decimal_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_decimal")), TRUE);
}
void on_popup_menu_item_duodecimal_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_duodecimal")), TRUE);
}
void on_popup_menu_item_hexadecimal_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_hexadecimal")), TRUE);
}
void on_popup_menu_item_custom_base_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	gtk_menu_item_activate(GTK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_custom_base")));
}
void on_popup_menu_item_abbreviate_names_activate(GtkMenuItem *w, gpointer) {
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_abbreviate_names")), gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)));
}
void on_popup_menu_item_all_prefixes_activate(GtkMenuItem *w, gpointer) {
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_all_prefixes")), gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)));
}
void on_popup_menu_item_denominator_prefixes_activate(GtkMenuItem *w, gpointer) {
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_denominator_prefixes")), gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)));
}
void on_popup_menu_item_view_matrix_activate(GtkMenuItem*, gpointer) {
	insert_matrix(mstruct, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")), false, false, true);
}
void on_popup_menu_item_view_vector_activate(GtkMenuItem*, gpointer) {
	insert_matrix(mstruct, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")), true, false, true);
}

void on_menu_item_display_normal_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)))
		return;
	printops.min_exp = EXP_PRECISION;
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_numerical_display"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_numerical_display_changed, NULL);
	gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_numerical_display")), 0);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_numerical_display"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_numerical_display_changed, NULL);
	result_format_updated();
}
void on_menu_item_display_engineering_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)))
		return;
	printops.min_exp = EXP_BASE_3;
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_numerical_display"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_numerical_display_changed, NULL);
	gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_numerical_display")), 1);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_numerical_display"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_numerical_display_changed, NULL);
	result_format_updated();
}
void on_menu_item_display_scientific_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)))
		return;
	printops.min_exp = EXP_SCIENTIFIC;
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_numerical_display"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_numerical_display_changed, NULL);
	gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_numerical_display")), 2);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_numerical_display"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_numerical_display_changed, NULL);
	result_format_updated();
}
void on_menu_item_display_purely_scientific_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)))
		return;
	printops.min_exp = EXP_PURE;
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_numerical_display"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_numerical_display_changed, NULL);
	gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_numerical_display")), 3);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_numerical_display"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_numerical_display_changed, NULL);
	result_format_updated();
}
void on_menu_item_display_non_scientific_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)))
		return;
	printops.min_exp = EXP_NONE;
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_numerical_display"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_numerical_display_changed, NULL);
	gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_numerical_display")), 4);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_numerical_display"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_numerical_display_changed, NULL);
	result_format_updated();
}
void on_menu_item_display_no_prefixes_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	to_prefix = 0;
	printops.use_unit_prefixes = false;
	printops.use_prefixes_for_all_units = false;
	printops.use_prefixes_for_currencies = false;
	result_format_updated();
}
void on_menu_item_display_prefixes_for_selected_units_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	to_prefix = 0;
	printops.use_unit_prefixes = true;
	printops.use_prefixes_for_all_units = false;
	printops.use_prefixes_for_currencies = false;
	result_format_updated();
}
void on_menu_item_display_prefixes_for_currencies_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	to_prefix = 0;
	printops.use_unit_prefixes = true;
	printops.use_prefixes_for_all_units = false;
	printops.use_prefixes_for_currencies = true;
	result_format_updated();
}
void on_menu_item_display_prefixes_for_all_units_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	to_prefix = 0;
	printops.use_unit_prefixes = true;
	printops.use_prefixes_for_all_units = true;
	printops.use_prefixes_for_currencies = true;
	result_format_updated();
}
void on_menu_item_indicate_infinite_series_activate(GtkMenuItem *w, gpointer) {
	printops.indicate_infinite_series = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
	result_format_updated();
}
void on_menu_item_show_ending_zeroes_activate(GtkMenuItem *w, gpointer) {
	printops.show_ending_zeroes = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
	result_format_updated();
}
void on_menu_item_round_halfway_to_even_activate(GtkMenuItem *w, gpointer) {
	printops.round_halfway_to_even = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
	result_format_updated();
}
void on_menu_item_negative_exponents_activate(GtkMenuItem *w, gpointer) {
	printops.negative_exponents = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
	result_format_updated();
}
void on_menu_item_sort_minus_last_activate(GtkMenuItem *w, gpointer) {
	printops.sort_options.minus_last = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
	result_format_updated();
}
void on_menu_item_always_exact_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	evalops.approximation = APPROXIMATION_EXACT;

	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "button_exact"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_button_exact_toggled, NULL);
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "button_exact")), TRUE);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "button_exact"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_button_exact_toggled, NULL);
	
	if(printops.number_fraction_format == FRACTION_DECIMAL) {
		bool prev_block_result_update = block_result_update;
		if(!rpn_mode) block_result_update = true;
		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_fraction_decimal_exact")), TRUE);
		automatic_fraction = true;
		if(!rpn_mode) block_result_update = prev_block_result_update;
	}
	
	expression_calculation_updated();
}
void on_menu_item_interval_arithmetic_activate(GtkMenuItem *w, gpointer) {
	CALCULATOR->useIntervalArithmetic(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)));
	expression_calculation_updated();
}

void restore_automatic_fraction() {
	if(automatic_fraction && printops.number_fraction_format == FRACTION_DECIMAL_EXACT) {
		bool prev_block_result_update = block_result_update;
		if(!rpn_mode) block_result_update = true;
		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_fraction_decimal")), TRUE);
		automatic_fraction = false;
		if(!rpn_mode) block_result_update = prev_block_result_update;
	}
}

void on_menu_item_try_exact_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	evalops.approximation = APPROXIMATION_TRY_EXACT;

	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "button_exact"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_button_exact_toggled, NULL);
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "button_exact")), FALSE);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "button_exact"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_button_exact_toggled, NULL);
	
	restore_automatic_fraction();

	expression_calculation_updated();
}
void on_menu_item_approximate_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	evalops.approximation = APPROXIMATION_APPROXIMATE;
	
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "button_exact"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_button_exact_toggled, NULL);
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "button_exact")), FALSE);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "button_exact"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_button_exact_toggled, NULL);
	
	restore_automatic_fraction();
	
	expression_calculation_updated();
}
void on_menu_item_ic_none_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	evalops.interval_calculation = INTERVAL_CALCULATION_NONE;
	expression_calculation_updated();
}
void on_menu_item_ic_variance_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	evalops.interval_calculation = INTERVAL_CALCULATION_VARIANCE_FORMULA;
	expression_calculation_updated();
}
void on_menu_item_ic_interval_arithmetic_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	evalops.interval_calculation = INTERVAL_CALCULATION_INTERVAL_ARITHMETIC;
	expression_calculation_updated();
}
void on_menu_item_ic_simple_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	evalops.interval_calculation = INTERVAL_CALCULATION_SIMPLE_INTERVAL_ARITHMETIC;
	expression_calculation_updated();
}

void on_menu_item_fraction_decimal_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	to_fraction = false;
	printops.number_fraction_format = FRACTION_DECIMAL;
	printops.restrict_fraction_length = false;
	automatic_fraction = false;
	
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_fraction_mode"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_fraction_mode_changed, NULL);
	gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_fraction_mode")), 0);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_fraction_mode"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_fraction_mode_changed, NULL);

	result_format_updated();
}
void on_menu_item_fraction_decimal_exact_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	to_fraction = false;
	printops.number_fraction_format = FRACTION_DECIMAL_EXACT;
	printops.restrict_fraction_length = false;
	automatic_fraction = false;

	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_fraction_mode"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_fraction_mode_changed, NULL);
	gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_fraction_mode")), 1);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_fraction_mode"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_fraction_mode_changed, NULL);
	
	result_format_updated();
}
void on_menu_item_fraction_combined_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	to_fraction = false;
	printops.number_fraction_format = FRACTION_COMBINED;
	printops.restrict_fraction_length = false;
	automatic_fraction = false;

	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_fraction_mode"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_fraction_mode_changed, NULL);
	gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_fraction_mode")), 3);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_fraction_mode"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_fraction_mode_changed, NULL);
	
	result_format_updated();
}
void on_menu_item_fraction_fraction_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	to_fraction = false;
	printops.number_fraction_format = FRACTION_FRACTIONAL;
	printops.restrict_fraction_length = true;
	automatic_fraction = false;

	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_fraction_mode"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_fraction_mode_changed, NULL);
	gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_fraction_mode")), 2);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "combobox_fraction_mode"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_combobox_fraction_mode_changed, NULL);
	
	result_format_updated();
}
void on_menu_item_interval_adaptive_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	adaptive_interval_display = true;
	printops.interval_display = INTERVAL_DISPLAY_SIGNIFICANT_DIGITS;
	result_format_updated();
}
void on_menu_item_interval_significant_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	adaptive_interval_display = false;
	printops.interval_display = INTERVAL_DISPLAY_SIGNIFICANT_DIGITS;
	result_format_updated();
}
void on_menu_item_interval_interval_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	adaptive_interval_display = false;
	printops.interval_display = INTERVAL_DISPLAY_INTERVAL;
	result_format_updated();
}
void on_menu_item_interval_plusminus_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	adaptive_interval_display = false;
	printops.interval_display = INTERVAL_DISPLAY_PLUSMINUS;
	result_format_updated();
}
void on_menu_item_interval_midpoint_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	adaptive_interval_display = false;
	printops.interval_display = INTERVAL_DISPLAY_MIDPOINT;
	result_format_updated();
}

void on_menu_item_complex_rectangular_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	evalops.complex_number_form = COMPLEX_NUMBER_FORM_RECTANGULAR;
	complex_angle_form = false;
	expression_calculation_updated();
}
void on_menu_item_complex_exponential_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	evalops.complex_number_form = COMPLEX_NUMBER_FORM_EXPONENTIAL;
	complex_angle_form = false;
	expression_calculation_updated();
}
void on_menu_item_complex_polar_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	evalops.complex_number_form = COMPLEX_NUMBER_FORM_POLAR;
	complex_angle_form = false;
	expression_calculation_updated();
}
void on_menu_item_complex_angle_activate(GtkMenuItem *w, gpointer) {
	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
	evalops.complex_number_form = COMPLEX_NUMBER_FORM_CIS;
	complex_angle_form = true;
	expression_calculation_updated();
}

void on_menu_item_save_activate(GtkMenuItem*, gpointer) {
	add_as_variable();
}
void on_menu_item_save_image_activate(GtkMenuItem*, gpointer) {
	if(display_aborted || !displayed_mstruct) return;
	GtkWidget *d = gtk_file_chooser_dialog_new(_("Select file to save PNG image to"), GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), GTK_FILE_CHOOSER_ACTION_SAVE, _("_Cancel"), GTK_RESPONSE_CANCEL, _("_Save"), GTK_RESPONSE_ACCEPT, NULL);
	gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(d), TRUE);
	GtkFileFilter *filter = gtk_file_filter_new();
	gtk_file_filter_set_name(filter, _("Allowed File Types"));
	gtk_file_filter_add_mime_type(filter, "image/png");
	gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(d), filter);
	GtkFileFilter *filter_all = gtk_file_filter_new();
	gtk_file_filter_add_pattern(filter_all, "*");
	gtk_file_filter_set_name(filter_all, _("All Files"));
	gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(d), filter_all);
	gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(d), "qalculate.png");
	if(gtk_dialog_run(GTK_DIALOG(d)) == GTK_RESPONSE_ACCEPT) {
		GdkRGBA color;
		color.red = 0.0;
		color.green = 0.0;
		color.blue = 0.0;
		color.alpha = 1.0;
		cairo_surface_t *s = draw_structure(*displayed_mstruct, displayed_printops, displayed_caf, top_ips, NULL, 1, &color);
		if(s) {
			cairo_surface_flush(s);
			cairo_surface_write_to_png(s, gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(d)));
			cairo_surface_destroy(s);
		}
	}
	gtk_widget_destroy(d);
}
void on_menu_item_copy_activate(GtkMenuItem*, gpointer) {
	string copy_text = result_text;
	if(!copy_separator) {
		remove_separator(copy_text);
	}
	gtk_clipboard_set_text(gtk_clipboard_get(gdk_atom_intern("CLIPBOARD", FALSE)), copy_text.c_str(), -1);
}
void on_menu_item_precision_activate(GtkMenuItem*, gpointer) {
	GtkWidget *dialog = get_precision_dialog();
	gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")));
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(precision_builder, "precision_dialog_spinbutton_precision"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_precision_dialog_spinbutton_precision_value_changed, NULL);
	gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(precision_builder, "precision_dialog_spinbutton_precision")), PRECISION);	
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(precision_builder, "precision_dialog_spinbutton_precision"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_precision_dialog_spinbutton_precision_value_changed, NULL);
	gtk_widget_show(dialog);
}
void on_menu_item_decimals_activate(GtkMenuItem*, gpointer) {
	GtkWidget *dialog = get_decimals_dialog();
	gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")));
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(decimals_builder, "decimals_dialog_checkbutton_max"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_decimals_dialog_checkbutton_max_toggled, NULL);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(decimals_builder, "decimals_dialog_checkbutton_min"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_decimals_dialog_checkbutton_min_toggled, NULL);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(decimals_builder, "decimals_dialog_spinbutton_max"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_decimals_dialog_spinbutton_max_value_changed, NULL);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(decimals_builder, "decimals_dialog_spinbutton_min"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_decimals_dialog_spinbutton_min_value_changed, NULL);	
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (gtk_builder_get_object(decimals_builder, "decimals_dialog_checkbutton_min")), printops.use_min_decimals);
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (gtk_builder_get_object(decimals_builder, "decimals_dialog_checkbutton_max")), printops.use_max_decimals);	
	gtk_widget_set_sensitive (GTK_WIDGET(gtk_builder_get_object(decimals_builder, "decimals_dialog_spinbutton_min")), printops.use_min_decimals);
	gtk_widget_set_sensitive (GTK_WIDGET(gtk_builder_get_object(decimals_builder, "decimals_dialog_spinbutton_max")), printops.use_max_decimals);	
	gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(decimals_builder, "decimals_dialog_spinbutton_min")), printops.min_decimals);
	gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(decimals_builder, "decimals_dialog_spinbutton_max")), printops.max_decimals);	
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(decimals_builder, "decimals_dialog_checkbutton_max"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_decimals_dialog_checkbutton_max_toggled, NULL);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(decimals_builder, "decimals_dialog_checkbutton_min"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_decimals_dialog_checkbutton_min_toggled, NULL);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(decimals_builder, "decimals_dialog_spinbutton_max"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_decimals_dialog_spinbutton_max_value_changed, NULL);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(decimals_builder, "decimals_dialog_spinbutton_min"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_decimals_dialog_spinbutton_min_value_changed, NULL);	
	gtk_widget_show(dialog);
}

gboolean on_main_window_focus_in_event(GtkWidget*, GdkEventFocus*, gpointer) {
	//focus_keeping_selection();
	return FALSE;
}


void on_button_registerup_clicked(GtkButton*, gpointer) {
	GtkTreeModel *model;
	GtkTreeIter iter, iter2;
	GtkTreePath *path;
	gint index;
	if(!gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(stackview)), &model, &iter)) {
		model = gtk_tree_view_get_model(GTK_TREE_VIEW(stackview));
		if(!gtk_tree_model_get_iter_first(model, &iter)) return;
	}
	path = gtk_tree_model_get_path(model, &iter);
	index = gtk_tree_path_get_indices(path)[0];
	gtk_tree_path_free(path);
	g_signal_handlers_block_matched((gpointer) stackstore, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_stackstore_row_inserted, NULL);
	g_signal_handlers_block_matched((gpointer) stackstore, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_stackstore_row_deleted, NULL);
	if(index == 0) {
		CALCULATOR->moveRPNRegister(1, CALCULATOR->RPNStackSize());
		gtk_tree_model_iter_nth_child(model, &iter2, NULL, CALCULATOR->RPNStackSize() - 1);
		gtk_list_store_move_after(stackstore, &iter, &iter2);
	} else {
		CALCULATOR->moveRPNRegisterUp(index + 1);
		gtk_tree_model_iter_nth_child(model, &iter2, NULL, index - 1);
		gtk_list_store_swap(stackstore, &iter, &iter2);
	}
	g_signal_handlers_unblock_matched((gpointer) stackstore, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_stackstore_row_inserted, NULL);
	g_signal_handlers_unblock_matched((gpointer) stackstore, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_stackstore_row_deleted, NULL);
	if(index <= 1) {
		mstruct->unref();
		mstruct = CALCULATOR->getRPNRegister(1);
		mstruct->ref();
		setResult(NULL, true, false, false, "", 0, true);
	}
	updateRPNIndexes();
}
void on_button_registerdown_clicked(GtkButton*, gpointer) {
	GtkTreeModel *model;
	GtkTreeIter iter, iter2;
	GtkTreePath *path;
	gint index;
	if(!gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(stackview)), &model, &iter)) {
		model = gtk_tree_view_get_model(GTK_TREE_VIEW(stackview));
		if(CALCULATOR->RPNStackSize() == 0) return;
		if(!gtk_tree_model_iter_nth_child(model, &iter, NULL, CALCULATOR->RPNStackSize() - 1)) return;
	}
	path = gtk_tree_model_get_path(model, &iter);
	index = gtk_tree_path_get_indices(path)[0];
	gtk_tree_path_free(path);
	g_signal_handlers_block_matched((gpointer) stackstore, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_stackstore_row_inserted, NULL);
	g_signal_handlers_block_matched((gpointer) stackstore, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_stackstore_row_deleted, NULL);
	if(index + 1 == (int) CALCULATOR->RPNStackSize()) {
		CALCULATOR->moveRPNRegister(CALCULATOR->RPNStackSize(), 1);
		gtk_tree_model_get_iter_first(model, &iter2);
		gtk_list_store_move_before(stackstore, &iter, &iter2);
	} else {
		CALCULATOR->moveRPNRegisterDown(index + 1);
		gtk_tree_model_iter_nth_child(model, &iter2, NULL, index + 1);
		gtk_list_store_swap(stackstore, &iter, &iter2);
	}
	g_signal_handlers_unblock_matched((gpointer) stackstore, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_stackstore_row_inserted, NULL);
	g_signal_handlers_unblock_matched((gpointer) stackstore, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_stackstore_row_deleted, NULL);
	if(index == 0 || index == (int) CALCULATOR->RPNStackSize() - 1) {
		mstruct->unref();
		mstruct = CALCULATOR->getRPNRegister(1);
		mstruct->ref();
		setResult(NULL, true, false, false, "", 0, true);
	}
	updateRPNIndexes();
}
void on_button_registerswap_clicked(GtkButton*, gpointer) {
	GtkTreeModel *model;
	GtkTreeIter iter, iter2;
	GtkTreePath *path;
	gint index;
	if(!gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(stackview)), &model, &iter)) {
		model = gtk_tree_view_get_model(GTK_TREE_VIEW(stackview));
		if(!gtk_tree_model_get_iter_first(model, &iter)) return;
	}
	path = gtk_tree_model_get_path(model, &iter);
	index = gtk_tree_path_get_indices(path)[0];
	gtk_tree_path_free(path);
	g_signal_handlers_block_matched((gpointer) stackstore, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_stackstore_row_inserted, NULL);
	g_signal_handlers_block_matched((gpointer) stackstore, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_stackstore_row_deleted, NULL);
	if(index == 0) {
		if(!gtk_tree_model_iter_nth_child(model, &iter2, NULL, 1)) return;
		CALCULATOR->moveRPNRegister(1, 2);
		gtk_list_store_swap(stackstore, &iter, &iter2);
	} else {
		CALCULATOR->moveRPNRegister(index + 1, 1);
		gtk_tree_model_get_iter_first(model, &iter2);
		gtk_list_store_move_before(stackstore, &iter, &iter2);
	}
	g_signal_handlers_unblock_matched((gpointer) stackstore, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_stackstore_row_inserted, NULL);
	g_signal_handlers_unblock_matched((gpointer) stackstore, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_stackstore_row_deleted, NULL);
	mstruct->unref();
	mstruct = CALCULATOR->getRPNRegister(1);
	mstruct->ref();
	setResult(NULL, true, false, false, "", 0, true);
	updateRPNIndexes();
}
void on_button_lastx_clicked(GtkButton*, gpointer) {
	if(expression_has_changed) {
		if(get_expression_text().find_first_not_of(SPACES) != string::npos) {
			execute_expression(true);
		}
	}
	CALCULATOR->RPNStackEnter(new MathStructure(lastx));
	RPNRegisterAdded("", 0);
	mstruct->unref();
	mstruct = CALCULATOR->getRPNRegister(1);
	mstruct->ref();
	setResult(NULL, true, true, false, "", 0, false);
}
void on_button_copyregister_clicked(GtkButton*, gpointer) {
	GtkTreeModel *model;
	GtkTreeIter iter;
	GtkTreePath *path;
	gchar *text_copy = NULL;
	gint index;
	if(!gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(stackview)), &model, &iter)) {
		model = gtk_tree_view_get_model(GTK_TREE_VIEW(stackview));
		if(!gtk_tree_model_get_iter_first(model, &iter)) return;
	}
	path = gtk_tree_model_get_path(model, &iter);
	index = gtk_tree_path_get_indices(path)[0];
	gtk_tree_path_free(path);
	CALCULATOR->RPNStackEnter(new MathStructure(*CALCULATOR->getRPNRegister(index + 1)));
	gtk_tree_model_get(model, &iter, 1, &text_copy, -1);
	RPNRegisterAdded(text_copy, 0);
	g_free(text_copy);
	mstruct->unref();
	mstruct = CALCULATOR->getRPNRegister(1);
	mstruct->ref();
	setResult(NULL, true, false, false, "", 0, true);
}
void on_button_editregister_clicked(GtkButton*, gpointer) {
	GtkTreeModel *model;
	GtkTreeIter iter;
	GtkTreePath *path;
	if(gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(stackview)), &model, &iter)) {
		path = gtk_tree_model_get_path(model, &iter);
		gtk_tree_view_set_cursor_on_cell(GTK_TREE_VIEW(stackview), path, register_column, register_renderer, TRUE);
		gtk_tree_path_free(path);
	}
}
void on_button_deleteregister_clicked(GtkButton*, gpointer) {
	GtkTreeModel *model;
	GtkTreeIter iter;
	GtkTreePath *path;
	gint index;
	if(!gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(stackview)), &model, &iter)) {
		model = gtk_tree_view_get_model(GTK_TREE_VIEW(stackview));
		if(!gtk_tree_model_get_iter_first(model, &iter)) return; 
	}
	path = gtk_tree_model_get_path(model, &iter);
	index = gtk_tree_path_get_indices(path)[0];
	gtk_tree_path_free(path);
	CALCULATOR->deleteRPNRegister(index + 1);
	RPNRegisterRemoved(index);
	if(CALCULATOR->RPNStackSize() == 0) {
		clearresult();
		mstruct->clear();
	} else if(index == 0) {
		mstruct->unref();
		mstruct = CALCULATOR->getRPNRegister(1);
		mstruct->ref();
		setResult(NULL, true, false, false, "", 0, true);
	}
}
void on_button_clearstack_clicked(GtkButton*, gpointer) {
	CALCULATOR->clearRPNStack();
	g_signal_handlers_block_matched((gpointer) stackstore, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_stackstore_row_deleted, NULL);
	gtk_list_store_clear(stackstore);
	g_signal_handlers_unblock_matched((gpointer) stackstore, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_stackstore_row_deleted, NULL);
	clearresult();
	mstruct->clear();
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_clearstack")), FALSE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_copyregister")), FALSE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_deleteregister")), FALSE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_registerdown")), FALSE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_registerup")), FALSE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_registerswap")), FALSE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_sqrt")), FALSE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_reciprocal")), FALSE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_negate")), FALSE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_sum")), FALSE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_add")), FALSE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_sub")), FALSE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_times")), FALSE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_divide")), FALSE);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_xy")), FALSE);
}
void on_stackview_selection_changed(GtkTreeSelection *treeselection, gpointer) {
	GtkTreeModel *model;
	GtkTreeIter iter;
	if(gtk_tree_selection_get_selected(treeselection, &model, &iter)) {
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_editregister")), TRUE);
	} else {
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_editregister")), FALSE);
	}
}
void on_stackview_item_edited(GtkCellRendererText*, gchar *path, gchar *new_text, gpointer) {
	int index = s2i(path);
	GtkTreeIter iter;
	gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(stackstore), &iter, NULL, index);
	gtk_list_store_set(stackstore, &iter, 1, new_text, -1);
	execute_expression(true, false, OPERATION_ADD, NULL, true, index);
	b_editing_stack = false;
}
void on_stackview_item_editing_started(GtkCellRenderer*, GtkCellEditable*, gchar*, gpointer) {
	b_editing_stack = true;
}
void on_stackview_item_editing_canceled(GtkCellRenderer*, gpointer) {
	b_editing_stack = false;
}
int inserted_stack_index = -1;
void on_stackstore_row_inserted(GtkTreeModel*, GtkTreePath *path, GtkTreeIter*, gpointer) {
	inserted_stack_index = gtk_tree_path_get_indices(path)[0];
}
void on_stackstore_row_deleted(GtkTreeModel*, GtkTreePath *path, gpointer) {
	if(inserted_stack_index >= 0) {
		CALCULATOR->moveRPNRegister(gtk_tree_path_get_indices(path)[0] + 1, inserted_stack_index + 1);
		inserted_stack_index = -1;
		updateRPNIndexes();
	}
}

void selected_register_function(MathFunction *f) {
	if(!f) return;
	GtkTreeModel *model;
	GtkTreeIter iter;
	if(!gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(stackview)), &model, &iter)) return;
	GtkTreePath *path = gtk_tree_model_get_path(model, &iter);
	gint index = gtk_tree_path_get_indices(path)[0];
	gtk_tree_path_free(path);
	execute_expression(true, true, OPERATION_ADD, f, true, index);
}
void on_popup_menu_item_stack_copytext_activate(GtkMenuItem*, gpointer) {
	GtkTreeModel *model;
	GtkTreeIter iter;
	if(!gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(stackview)), &model, &iter)) return;
	gchar *gstr;
	gtk_tree_model_get(model, &iter, 1, &gstr, -1);
	gtk_clipboard_set_text(gtk_clipboard_get(gdk_atom_intern("CLIPBOARD", FALSE)), gstr, -1);
	g_free(gstr);
}
void on_popup_menu_item_stack_inserttext_activate(GtkMenuItem*, gpointer) {
	GtkTreeModel *model;
	GtkTreeIter iter;
	if(!gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(stackview)), &model, &iter)) return;
	gchar *gstr;
	gtk_tree_model_get(model, &iter, 1, &gstr, -1);
	insert_text(gstr);
	g_free(gstr);
}
void on_popup_menu_item_stack_negate_activate(GtkMenuItem*, gpointer) {
	selected_register_function(CALCULATOR->getActiveFunction("neg"));
}
void on_popup_menu_item_stack_invert_activate(GtkMenuItem*, gpointer) {
	selected_register_function(CALCULATOR->getActiveFunction("inv"));
}
void on_popup_menu_item_stack_square_activate(GtkMenuItem*, gpointer) {
	selected_register_function(CALCULATOR->f_sq);
}
void on_popup_menu_item_stack_sqrt_activate(GtkMenuItem*, gpointer) {
	selected_register_function(CALCULATOR->f_sqrt);
}
void on_popup_menu_item_stack_copy_activate(GtkMenuItem*, gpointer) {
	on_button_copyregister_clicked(NULL, NULL);
}
void on_popup_menu_item_stack_movetotop_activate(GtkMenuItem*, gpointer) {
	GtkTreeModel *model;
	GtkTreeIter iter, iter2;
	GtkTreePath *path;
	gint index;
	if(!gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(stackview)), &model, &iter)) return;
	path = gtk_tree_model_get_path(model, &iter);
	index = gtk_tree_path_get_indices(path)[0];
	gtk_tree_path_free(path);
	g_signal_handlers_block_matched((gpointer) stackstore, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_stackstore_row_inserted, NULL);
	g_signal_handlers_block_matched((gpointer) stackstore, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_stackstore_row_deleted, NULL);
	CALCULATOR->moveRPNRegister(index + 1, 1);
	gtk_tree_model_get_iter_first(model, &iter2);
	gtk_list_store_move_before(stackstore, &iter, &iter2);
	g_signal_handlers_unblock_matched((gpointer) stackstore, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_stackstore_row_inserted, NULL);
	g_signal_handlers_unblock_matched((gpointer) stackstore, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_stackstore_row_deleted, NULL);
	mstruct->unref();
	mstruct = CALCULATOR->getRPNRegister(1);
	mstruct->ref();
	setResult(NULL, true, false, false, "", 0, true);
	updateRPNIndexes();
}
void on_popup_menu_item_stack_up_activate(GtkMenuItem*, gpointer) {
	on_button_registerup_clicked(NULL, NULL);
}
void on_popup_menu_item_stack_down_activate(GtkMenuItem*, gpointer) {
	on_button_registerdown_clicked(NULL, NULL);
}
void on_popup_menu_item_stack_swap_activate(GtkMenuItem*, gpointer) {
	on_button_registerswap_clicked(NULL, NULL);
}
void on_popup_menu_item_stack_edit_activate(GtkMenuItem*, gpointer) {
	on_button_editregister_clicked(NULL, NULL);
}
void on_popup_menu_item_stack_delete_activate(GtkMenuItem*, gpointer) {
	on_button_deleteregister_clicked(NULL, NULL);
}
void on_popup_menu_item_stack_clear_activate(GtkMenuItem*, gpointer) {
	on_button_clearstack_clicked(NULL, NULL);
}
void update_stackview_popup() {
	GtkTreeModel *model;
	GtkTreeIter iter;
	bool b_sel = gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(stackview)), &model, &iter);
	gint index = -1;
	if(b_sel) {
		GtkTreePath *path = gtk_tree_model_get_path(model, &iter);
		index = gtk_tree_path_get_indices(path)[0];
		gtk_tree_path_free(path);
	}
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_stack_inserttext")), b_sel);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_stack_copytext")), b_sel);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_stack_copy")), b_sel);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_stack_movetotop")), b_sel && index != 0);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_stack_moveup")), b_sel);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_stack_movedown")), b_sel);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_stack_swap")), b_sel);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_stack_edit")), b_sel);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_stack_negate")), b_sel);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_stack_invert")), b_sel);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_stack_square")), b_sel);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_stack_sqrt")), b_sel);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_stack_delete")), b_sel);
}
gboolean on_stackview_button_press_event(GtkWidget*, GdkEventButton *event, gpointer) {
	GtkTreePath *path = NULL;
	GtkTreeSelection *select = NULL;
	if(gdk_event_triggers_context_menu((GdkEvent*) event) && event->type == GDK_BUTTON_PRESS) {
		if(b_busy) return TRUE;
		if(gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(stackview), event->x, event->y, &path, NULL, NULL, NULL)) {
			select = gtk_tree_view_get_selection(GTK_TREE_VIEW(stackview));
			if(!gtk_tree_selection_path_is_selected(select, path)) {
				gtk_tree_selection_unselect_all(select);
				gtk_tree_selection_select_path(select, path);
			}
			gtk_tree_path_free(path);
		}
		update_stackview_popup();
#if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 22
		gtk_menu_popup_at_pointer(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_stackview")), (GdkEvent*) event);
#else
		gtk_menu_popup(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_stackview")), NULL, NULL, NULL, NULL, event->button, event->time);
#endif
		return TRUE;
	}
	return FALSE;
}
gboolean on_stackview_popup_menu(GtkWidget*, gpointer) {
	if(b_busy) return TRUE;
	update_stackview_popup();
#if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 22
	gtk_menu_popup_at_pointer(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_stackview")), NULL);
#else
	gtk_menu_popup(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_stackview")), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time());
#endif
	return TRUE;
}

void on_unit_edit_entry_relation_changed(GtkEditable *w, gpointer) {
	string str = gtk_entry_get_text(GTK_ENTRY(w));
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_box_reversed")), str.find("\\x") != string::npos);
}

void correct_name_entry(GtkEditable *editable, ExpressionItemType etype, gpointer function) {
	string str = gtk_entry_get_text(GTK_ENTRY(editable));
	if(str.empty()) return;
	remove_blank_ends(str);
	bool b = false;
	if(!str.empty()) {
		switch(etype) {
			case TYPE_FUNCTION: {
				b = CALCULATOR->functionNameIsValid(str);
				if(!b) str = CALCULATOR->convertToValidFunctionName(str);
				break;
			}
			case TYPE_UNIT: {
				b = CALCULATOR->unitNameIsValid(str);
				if(!b) str = CALCULATOR->convertToValidUnitName(str);
				break;
			}
			case TYPE_VARIABLE: {
				b = CALCULATOR->variableNameIsValid(str);
				if(!b) str = CALCULATOR->convertToValidVariableName(str);
				break;
			}
		}
	}
	if(!b) {
		g_signal_handlers_block_matched((gpointer) editable, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, function, NULL);
		gtk_entry_set_text(GTK_ENTRY(editable), str.c_str());
		g_signal_handlers_unblock_matched((gpointer) editable, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, function, NULL);
	}
}

/*
	check if entered unit name is valid, if not modify
*/
void on_unit_edit_entry_name_changed(GtkEditable *editable, gpointer) {
	correct_name_entry(editable, TYPE_UNIT, (gpointer) on_unit_edit_entry_name_changed);
}
/*
	selected unit type in edit/new unit dialog has changed
*/
void on_unit_edit_combobox_class_changed(GtkComboBox *om, gpointer) {

	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_label_relation_title")), gtk_combo_box_get_active(om) != UNIT_CLASS_BASE_UNIT);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_label_base")), gtk_combo_box_get_active(om) != UNIT_CLASS_BASE_UNIT);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_base")), gtk_combo_box_get_active(om) != UNIT_CLASS_BASE_UNIT);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_checkbutton_use_prefixes")), gtk_combo_box_get_active(om) != UNIT_CLASS_COMPOSITE_UNIT);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_label_exp")), gtk_combo_box_get_active(om) == UNIT_CLASS_ALIAS_UNIT);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_spinbutton_exp")), gtk_combo_box_get_active(om) == UNIT_CLASS_ALIAS_UNIT);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_label_relation")), gtk_combo_box_get_active(om) == UNIT_CLASS_ALIAS_UNIT);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_relation")), gtk_combo_box_get_active(om) == UNIT_CLASS_ALIAS_UNIT);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_checkbutton_exact")), gtk_combo_box_get_active(om) == UNIT_CLASS_ALIAS_UNIT);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_label_reversed")), gtk_combo_box_get_active(om) == UNIT_CLASS_ALIAS_UNIT);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_reversed")), gtk_combo_box_get_active(om) == UNIT_CLASS_ALIAS_UNIT);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_frame_mix")), gtk_combo_box_get_active(om) == UNIT_CLASS_ALIAS_UNIT && gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_spinbutton_exp"))) == 1);
	if(gtk_combo_box_get_active(om) != UNIT_CLASS_ALIAS_UNIT) {
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_checkbutton_mix")), FALSE);
		on_unit_edit_checkbutton_mix_toggled(GTK_TOGGLE_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_checkbutton_mix")), NULL);		
		gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_spinbutton_exp")), 1);
	}
}

void on_unit_edit_checkbutton_mix_toggled(GtkToggleButton *w, gpointer) {
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_label_mix_priority")), gtk_toggle_button_get_active(w));
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_label_mix_min")), gtk_toggle_button_get_active(w));
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_spinbutton_mix_priority")), gtk_toggle_button_get_active(w));
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_spinbutton_mix_min")), gtk_toggle_button_get_active(w));
}

void on_unit_edit_spinbutton_exp_value_changed(GtkSpinButton *w, gpointer) {
	if(gtk_combo_box_get_active(GTK_COMBO_BOX(gtk_builder_get_object(unitedit_builder, "unit_edit_combobox_class"))) != UNIT_CLASS_ALIAS_UNIT) return;
	if(gtk_spin_button_get_value_as_int(w) != 1) {
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_checkbutton_mix")), FALSE);
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_frame_mix")), FALSE);
	} else {
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_frame_mix")), TRUE);
	}
}

/*
	selected unit system in edit/new unit dialog has changed
*/
void on_unit_edit_combo_system_changed(GtkComboBox *om, gpointer) {
	string str = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(om));
	if(str == "SI" || str == "CGS") {
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_checkbutton_use_prefixes")), TRUE);
	}
}

/*
	"New" button clicked in unit manager -- open new unit dialog
*/
void on_units_button_new_clicked(GtkButton*, gpointer) {
	if(selected_unit_category.empty() || selected_unit_category[0] != '/') {
		edit_unit("", NULL, GTK_WIDGET(gtk_builder_get_object(units_builder, "units_dialog")));
	} else {
		//fill in category field with selected category
		edit_unit(selected_unit_category.substr(1, selected_unit_category.length() - 1).c_str(), NULL, GTK_WIDGET(gtk_builder_get_object(units_builder, "units_dialog")));
	}
}

/*
	"Edit" button clicked in unit manager -- open edit unit dialog for selected unit
*/
void on_units_button_edit_clicked(GtkButton*, gpointer) {
	Unit *u = get_selected_unit();
	if(u) {
		edit_unit("", u, GTK_WIDGET(gtk_builder_get_object(units_builder, "units_dialog")));
	}
}

/*
	"Insert" button clicked in unit manager -- insert selected unit in expression entry
*/
void on_units_button_insert_clicked(GtkButton*, gpointer) {
	Unit *u = get_selected_unit();
	if(u) {
		if(u->subtype() == SUBTYPE_COMPOSITE_UNIT) {
			insert_text(((CompositeUnit*) u)->print(true, printops.abbreviate_names, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) expressiontext).c_str());
		} else {
			insert_text(u->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, true, false, &can_display_unicode_string_function, (void*) expressiontext).name.c_str());
		}
	}
}

/*
	"Convert" button clicked in unit manager -- convert result to selected unit
*/
void on_units_button_convert_to_clicked(GtkButton*, gpointer) {
	if(b_busy) return;
	Unit *u = get_selected_unit();
	if(u) {
		executeCommand(COMMAND_CONVERT_UNIT, true, "", u);
		focus_keeping_selection();
	}
}

/*
	deletion of unit requested
*/
void on_units_button_delete_clicked(GtkButton*, gpointer) {
	GtkTreeModel *model;
	GtkTreeIter iter;
	Unit *u = get_selected_unit();
	if(u && u->isLocal()) {
		if(u->isUsedByOtherUnits()) {
			//do not delete units that are used by other units
			show_message(_("Cannot delete unit as it is needed by other units."), GTK_WIDGET(gtk_builder_get_object(units_builder, "units_dialog")));
			return;
		}
		for(size_t i = 0; i < recent_units.size(); i++) {
			if(recent_units[i] == u) {
				recent_units.erase(recent_units.begin() + i);
				gtk_widget_destroy(recent_unit_items[i]);
				recent_unit_items.erase(recent_unit_items.begin() + i);
				break;
			}
		}
		//ensure that all references to the unit is removed in Calculator
		u->destroy();
		//update menus and trees
		if(gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnits)), &model, &iter)) {
			//reselect selected unit category
			GtkTreePath *path = gtk_tree_model_get_path(model, &iter);
			string str = selected_unit_category;
			update_umenus();
			if(str == selected_unit_category) gtk_tree_selection_select_path(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnits)), path);
			gtk_tree_path_free(path);
		} else {
			update_umenus();
		}
	}
}

/*
	"New" button clicked in variable manager -- open new variable dialog
*/
void on_variables_button_new_clicked(GtkButton*, gpointer) {
	if(selected_variable_category.empty() || selected_variable_category[0] != '/') {
		edit_variable("", NULL, NULL, GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_dialog")));
	} else {
		//fill in category field with selected category
		edit_variable(selected_variable_category.substr(1, selected_variable_category.length() - 1).c_str(), NULL, NULL, GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_dialog")));
	}
}

/*
	"Edit" button clicked in variable manager -- open edit dialog for selected variable
*/
void on_variables_button_edit_clicked(GtkButton*, gpointer) {
	Variable *v = get_selected_variable();
	if(v) {
		if(!CALCULATOR->stillHasVariable(v)) {
			show_message(_("Variable does not exist anymore."), GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_dialog")));
			update_vmenu();
			return;
		}
		edit_variable("", v, NULL, GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_dialog")));
	}
}

/*
	"Insert" button clicked in variable manager -- insert variable name in expression entry
*/
void on_variables_button_insert_clicked(GtkButton*, gpointer) {
	Variable *v = get_selected_variable();
	if(v) {
		if(!CALCULATOR->stillHasVariable(v)) {
			show_message(_("Variable does not exist anymore."), GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_dialog")));
			update_vmenu();
			return;
		}
		gchar *gstr = g_strdup(v->preferredInputName(printops.abbreviate_names, true, false, false, &can_display_unicode_string_function, (void*) expressiontext).name.c_str());
		insert_text(gstr);
		g_free(gstr);
	}
}

/*
	"Delete" button clicked in variable manager -- deletion of selected variable requested
*/
void on_variables_button_delete_clicked(GtkButton*, gpointer) {
	GtkTreeModel *model;
	GtkTreeIter iter;
	Variable *v = get_selected_variable();
	if(v && !CALCULATOR->stillHasVariable(v)) {
		show_message(_("Variable does not exist anymore."), GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_dialog")));
		update_vmenu();
		return;
	}
	if(v && v->isLocal()) {
		for(size_t i = 0; i < recent_variables.size(); i++) {
			if(recent_variables[i] == v) {
				recent_variables.erase(recent_variables.begin() + i);
				gtk_widget_destroy(recent_variable_items[i]);
				recent_variable_items.erase(recent_variable_items.begin() + i);
				break;
			}
		}
		//ensure that all references are removed in Calculator
		v->destroy();

		//update menus and trees
		if(gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(tVariables)), &model, &iter)) {
			//reselect selected variable category
			GtkTreePath *path = gtk_tree_model_get_path(model, &iter);
			string str = selected_variable_category;
			update_vmenu();
			if(str == selected_variable_category) gtk_tree_selection_select_path(gtk_tree_view_get_selection(GTK_TREE_VIEW(tVariables)), path);
			gtk_tree_path_free(path);
		} else {
			update_vmenu();
		}
	}
}

void on_variables_button_export_clicked(GtkButton*, gpointer) {
	Variable *v = get_selected_variable();
	if(v && !CALCULATOR->stillHasVariable(v)) {
		show_message(_("Variable does not exist anymore."), GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_dialog")));
		update_vmenu();
		return;
	}
	if(v && v->isKnown()) {
		export_csv_file((KnownVariable*) v, GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_dialog")));
	}
}

/*
	"Close" button clicked in variable manager -- hide
*/
void on_variables_button_close_clicked(GtkButton*, gpointer) {
	gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_dialog")));
}

/*
	"New" button clicked in function manager -- open new function dialog
*/
void on_functions_button_new_clicked(GtkButton*, gpointer) {
	if(selected_function_category.empty() || selected_function_category[0] != '/') {
		edit_function("", NULL, GTK_WIDGET(gtk_builder_get_object(functions_builder, "functions_dialog")));
	} else {
		//fill in category field with selected category
		edit_function(selected_function_category.substr(1, selected_function_category.length() - 1).c_str(), NULL, GTK_WIDGET(gtk_builder_get_object(functions_builder, "functions_dialog")));
	}
}

/*
	"Edit" button clicked in function manager -- open edit function dialog for selected function
*/
void on_functions_button_edit_clicked(GtkButton*, gpointer) {
	MathFunction *f = get_selected_function();
	if(f) {
		edit_function("", f, GTK_WIDGET(gtk_builder_get_object(functions_builder, "functions_dialog")));
	}
}

/*
	"Insert" button clicked in function manager -- open dialog for insertion of function in expression entry
*/
void on_functions_button_insert_clicked(GtkButton*, gpointer) {
	insert_function(get_selected_function(), GTK_WIDGET(gtk_builder_get_object(functions_builder, "functions_dialog")));
}

/*
	"Apply" button clicked in function manager -- apply function to current result
*/
void on_functions_button_apply_clicked(GtkButton*, gpointer) {
	apply_function(get_selected_function(), GTK_WIDGET(gtk_builder_get_object(functions_builder, "functions_dialog")));
}

/*
	"Delete" button clicked in function manager -- deletion of selected function requested
*/
void on_functions_button_delete_clicked(GtkButton*, gpointer) {
	GtkTreeModel *model;
	GtkTreeIter iter;
	MathFunction *f = get_selected_function();
	if(f && f->isLocal()) {
		for(size_t i = 0; i < recent_functions.size(); i++) {
			if(recent_functions[i] == f) {
				recent_functions.erase(recent_functions.begin() + i);
				gtk_widget_destroy(recent_function_items[i]);
				recent_function_items.erase(recent_function_items.begin() + i);
				break;
			}
		}
		//ensure removal of all references in Calculator
		f->destroy();
		//update menus and trees
		if(gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(tFunctions)), &model, &iter)) {
			//reselected selected function category
			GtkTreePath *path = gtk_tree_model_get_path(model, &iter);
			string str = selected_function_category;
			update_fmenu();
			if(str == selected_function_category) {
				gtk_tree_selection_select_path(gtk_tree_view_get_selection(GTK_TREE_VIEW(tFunctions)), path);
			}
			gtk_tree_path_free(path);
		} else {
			update_fmenu();
		}
	}
}

/*
	"Close" button clicked in function manager -- hide
*/
void on_functions_button_close_clicked(GtkButton*, gpointer) {
	gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(functions_builder, "functions_dialog")));
}

void on_datasets_button_newset_clicked(GtkButton*, gpointer) {	
	edit_dataset(NULL, GTK_WIDGET(gtk_builder_get_object(datasets_builder, "datasets_dialog")));
}
void on_datasets_button_editset_clicked(GtkButton*, gpointer) {
	edit_dataset(selected_dataset, GTK_WIDGET(gtk_builder_get_object(datasets_builder, "datasets_dialog")));
}
void on_datasets_button_delset_clicked(GtkButton*, gpointer) {
	if(selected_dataset && selected_dataset->isLocal()) {
		for(size_t i = 0; i < recent_functions.size(); i++) {
			if(recent_functions[i] == selected_dataset) {
				recent_functions.erase(recent_functions.begin() + i);
				gtk_widget_destroy(recent_function_items[i]);
				recent_function_items.erase(recent_function_items.begin() + i);
				break;
			}
		}
		selected_dataset->destroy();
		selected_dataobject = NULL;		
		update_datasets_tree();
		on_tDatasets_selection_changed(gtk_tree_view_get_selection(GTK_TREE_VIEW(tDatasets)), NULL);
	}
}
void on_datasets_button_newobject_clicked(GtkButton*, gpointer) {
	edit_dataobject(selected_dataset, NULL, GTK_WIDGET(gtk_builder_get_object(datasets_builder, "datasets_dialog")));
}
void on_datasets_button_editobject_clicked(GtkButton*, gpointer) {
	edit_dataobject(selected_dataset, selected_dataobject, GTK_WIDGET(gtk_builder_get_object(datasets_builder, "datasets_dialog")));
}
void on_datasets_button_delobject_clicked(GtkButton*, gpointer) {
	if(selected_dataset && selected_dataobject) {
		selected_dataset->delObject(selected_dataobject);
		selected_dataobject = NULL;
		update_dataobjects();
	}
}
void on_datasets_button_close_clicked(GtkButton*, gpointer) {
	gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(datasets_builder, "datasets_dialog")));
}


/*
	check if entered function name is valid, if not modify
*/
void on_function_edit_entry_name_changed(GtkEditable *editable, gpointer) {
	correct_name_entry(editable, TYPE_FUNCTION, (gpointer) on_function_edit_entry_name_changed);
}
/*
	check if entered variable name is valid, if not modify
*/
void on_variable_edit_entry_name_changed(GtkEditable *editable, gpointer) {
	correct_name_entry(editable, TYPE_VARIABLE, (gpointer) on_variable_edit_entry_name_changed);
}

void on_variable_changed() {
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(variableedit_builder, "variable_edit_button_ok")), TRUE);
}
void on_function_changed() {
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_button_ok")), TRUE);
}
void on_simple_function_changed() {
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(simplefunctionedit_builder, "simple_function_edit_button_ok")), TRUE);
}
void on_argument_changed() {
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(argumentrules_builder, "argument_rules_button_ok")), TRUE);
}
void on_unit_changed() {
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_button_ok")), TRUE);
}
void on_dataset_changed() {
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasetedit_builder, "dataset_edit_button_ok")), TRUE);
}
void on_dataobject_changed() {
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasets_builder, "dataobject_edit_button_ok")), TRUE);
}
void on_dataproperty_changed() {
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_button_ok")), TRUE);
}
void on_matrix_changed() {
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_button_ok")), TRUE);
}
void on_unknown_changed() {
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unknownedit_builder, "unknown_edit_button_ok")), TRUE);
}

void on_tMatrixEdit_edited(GtkCellRendererText *cell, gchar *path_string, gchar *new_text, gpointer model) {
	GtkTreeIter iter;
	gint i_column = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cell), "column"));
	gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL(model), &iter, path_string);
	gtk_list_store_set(GTK_LIST_STORE (model), &iter, i_column, new_text, -1);
	on_matrix_changed();
}
gboolean on_tMatrixEdit_editable_key_press_event(GtkWidget *w, GdkEventKey *event, gpointer renderer) {
	switch(event->keyval) {
		case GDK_KEY_Up: {}
		case GDK_KEY_Down: {}
		case GDK_KEY_Tab: {}
		case GDK_KEY_ISO_Enter: {}
		case GDK_KEY_KP_Enter: {}
		case GDK_KEY_Return: {
			gtk_cell_editable_editing_done(GTK_CELL_EDITABLE(w));
			GtkTreeViewColumn *column = NULL;
			GtkTreePath *path = NULL;
			gtk_tree_view_get_cursor(GTK_TREE_VIEW(tMatrixEdit), &path, &column);
			if(path) {
				if(column) {
					for(size_t i = 0; i < matrix_edit_columns.size(); i++) {
						if(matrix_edit_columns[i] == column) {
							if(event->keyval == GDK_KEY_Tab) {
								i++;
								if(i >= matrix_edit_columns.size()) {
									gtk_tree_path_next(path);
									GtkTreeIter iter;
									if(!gtk_tree_model_get_iter(GTK_TREE_MODEL(tMatrixEdit_store), &iter, path)) {
										gtk_tree_path_free(path);
										path = gtk_tree_path_new_first();
									}
									i = 0;
								}
							} else {
								if(event->keyval == GDK_KEY_Up) {
									if(!gtk_tree_path_prev(path)) {
										gtk_tree_path_free(path);
										path = gtk_tree_path_new_from_indices(gtk_tree_model_iter_n_children(GTK_TREE_MODEL(tMatrixEdit_store), NULL) - 1, -1);
									}
								} else {
									gtk_tree_path_next(path);
									GtkTreeIter iter;
									if(!gtk_tree_model_get_iter(GTK_TREE_MODEL(tMatrixEdit_store), &iter, path)) {
										gtk_tree_path_free(path);
										if(event->keyval != GDK_KEY_Up) return TRUE;
										path = gtk_tree_path_new_first();
									}
								}
							}
							gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(tMatrixEdit), path, matrix_edit_columns[i], FALSE, 0.0, 0.0);
							while(gtk_events_pending()) gtk_main_iteration();
							gtk_tree_view_set_cursor(GTK_TREE_VIEW(tMatrixEdit), path, matrix_edit_columns[i], TRUE);
							on_tMatrixEdit_cursor_changed(GTK_TREE_VIEW(tMatrixEdit), NULL);
							break;
						}
					}
				}
				gtk_tree_path_free(path);
			}
			return TRUE;
		}
	}
	return FALSE;
}
void on_tMatrixEdit_editing_started(GtkCellRenderer *renderer, GtkCellEditable *editable, gchar *path, gpointer user_data) {
	g_signal_connect(G_OBJECT(editable), "key-press-event", G_CALLBACK(on_tMatrixEdit_editable_key_press_event), renderer);
}
gboolean on_tMatrixEdit_key_press_event(GtkWidget*, GdkEventKey *event, gpointer) {
	switch(event->keyval) {
		case GDK_KEY_Return: {break;}
		case GDK_KEY_Tab: {
			GtkTreeViewColumn *column = NULL;
			GtkTreePath *path = NULL;
			gtk_tree_view_get_cursor(GTK_TREE_VIEW(tMatrixEdit), &path, &column);
			if(path) {
				if(column) {
					for(size_t i = 0; i < matrix_edit_columns.size(); i++) {
						if(matrix_edit_columns[i] == column) {
							i++;
							if(i < matrix_edit_columns.size()) {
								gtk_tree_view_set_cursor(GTK_TREE_VIEW(tMatrixEdit), path, matrix_edit_columns[i], FALSE);
								while(gtk_events_pending()) gtk_main_iteration();
								gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(tMatrixEdit), path, matrix_edit_columns[i], FALSE, 0.0, 0.0);
							} else {
								gtk_tree_path_next(path);
								GtkTreeIter iter;
								if(!gtk_tree_model_get_iter(GTK_TREE_MODEL(tMatrixEdit_store), &iter, path)) {
									gtk_tree_path_free(path);
									path = gtk_tree_path_new_first();
								}
								gtk_tree_view_set_cursor(GTK_TREE_VIEW(tMatrixEdit), path, matrix_edit_columns[0], FALSE);
								while(gtk_events_pending()) gtk_main_iteration();
								gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(tMatrixEdit), path, matrix_edit_columns[0], FALSE, 0.0, 0.0);
							}
							gtk_tree_path_free(path);
							on_tMatrixEdit_cursor_changed(GTK_TREE_VIEW(tMatrixEdit), NULL);
							return TRUE;
						}
					}
				}
				gtk_tree_path_free(path);
			}
			break;
		}
		default: {
			if(event->length == 0) return FALSE;
			GtkTreeViewColumn *column = NULL;
			GtkTreePath *path = NULL;
			gtk_tree_view_get_cursor(GTK_TREE_VIEW(tMatrixEdit), &path, &column);
			if(path) {
				if(column) {
					gtk_tree_view_set_cursor(GTK_TREE_VIEW(tMatrixEdit), path, column, TRUE);
					while(gtk_events_pending()) gtk_main_iteration();
					gboolean return_val = FALSE;
					g_signal_emit_by_name((gpointer) gtk_builder_get_object(matrixedit_builder, "matrix_edit_dialog"), "key_press_event", event, &return_val);
					gtk_tree_path_free(path);
					return TRUE;
				}
				gtk_tree_path_free(path);
			}
		}
	}
	return FALSE;
}
gboolean on_tMatrixEdit_button_press_event(GtkWidget*, GdkEventButton *event, gpointer) {
	if(event->button != 1) return FALSE;
	GtkTreeViewColumn *column = NULL;
	GtkTreePath *path = NULL;
	if(gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(tMatrixEdit), (gint) event->x, (gint) event->y, &path, &column, NULL, NULL) && path && column) {
		gtk_tree_view_set_cursor(GTK_TREE_VIEW(tMatrixEdit), path, column, TRUE);
		gtk_tree_path_free(path);
		return TRUE;
	}
	if(path) gtk_tree_path_free(path);
	return FALSE;
}
GtkTreeIter matrix_edit_prev_iter;
gint matrix_edit_prev_column;
bool block_matrix_edit_update_cursor = false;
gboolean on_tMatrixEdit_cursor_changed(GtkTreeView*, gpointer) {
	if(block_matrix_edit_update_cursor) return FALSE;
	GtkTreeViewColumn *column = NULL;
	GtkTreePath *path = NULL;
	GtkTreeIter iter;
	gtk_tree_view_get_cursor(GTK_TREE_VIEW(tMatrixEdit), &path, &column);
	bool b = false;
	if(path) {
		if(column) {
			if(gtk_tree_model_get_iter(GTK_TREE_MODEL(tMatrixEdit_store), &iter, path)) {
				gint i_column = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column"));
				matrix_edit_prev_iter = iter;
				matrix_edit_prev_column = i_column;
				gchar *pos_str;
				if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(matrixedit_builder, "matrix_edit_radiobutton_matrix")))) {
					pos_str = g_strdup_printf("(%i, %i)", i_column + 1, gtk_tree_path_get_indices(path)[0] + 1);
				} else {
					pos_str = g_strdup_printf("%i", (int) (i_column + 1 + matrix_edit_columns.size() * gtk_tree_path_get_indices(path)[0]));
				}
				gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(matrixedit_builder, "matrix_edit_label_position")), pos_str);
				g_free(pos_str);
				b = true;
			}
		}
		gtk_tree_path_free(path);
	}
	if(!b) gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(matrixedit_builder, "matrix_edit_label_position")), _("none"));
	return FALSE;
}

void on_matrix_edit_spinbutton_columns_value_changed(GtkSpinButton *w, gpointer) {
	gint c = matrix_edit_columns.size();
	gint new_c = gtk_spin_button_get_value_as_int(w);
	if(new_c < c) {
		for(gint index_c = new_c; index_c < c; index_c++) {
			gtk_tree_view_remove_column(GTK_TREE_VIEW(tMatrixEdit), matrix_edit_columns[index_c]);
		}
		matrix_edit_columns.resize(new_c);
	} else {
		GtkTreeIter iter;
		for(gint index_c = c; index_c < new_c; index_c++) {
			GtkCellRenderer *matrix_edit_renderer = gtk_cell_renderer_text_new();
			g_object_set(G_OBJECT(matrix_edit_renderer), "editable", TRUE, NULL);
			g_object_set(G_OBJECT(matrix_edit_renderer), "xalign", 1.0, NULL);
			g_object_set_data(G_OBJECT(matrix_edit_renderer), "column", GINT_TO_POINTER(index_c));
			g_signal_connect(G_OBJECT(matrix_edit_renderer), "edited", G_CALLBACK(on_tMatrixEdit_edited), GTK_TREE_MODEL(tMatrixEdit_store));
			g_signal_connect(G_OBJECT(matrix_edit_renderer), "editing-started", G_CALLBACK(on_tMatrixEdit_editing_started), GTK_TREE_MODEL(tMatrixEdit_store));
			GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes(i2s(index_c).c_str(), matrix_edit_renderer, "text", index_c, NULL);
			g_object_set_data(G_OBJECT(column), "column", GINT_TO_POINTER(index_c));
			g_object_set_data(G_OBJECT(column), "renderer", (gpointer) matrix_edit_renderer);
			gtk_tree_view_column_set_min_width(column, 50);
			gtk_tree_view_column_set_alignment(column, 0.5);
			gtk_tree_view_append_column(GTK_TREE_VIEW(tMatrixEdit), column);
			gtk_tree_view_column_set_expand(column, TRUE);
			matrix_edit_columns.push_back(column);
		}
		if(!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tMatrixEdit_store), &iter)) return;
		bool b_matrix = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(matrixedit_builder, "matrix_edit_radiobutton_matrix")));
		while(true) {
			for(gint index_c = c; index_c < new_c; index_c++) {
				if(b_matrix) gtk_list_store_set(GTK_LIST_STORE(tMatrixEdit_store), &iter, index_c, "0", -1);
				else gtk_list_store_set(GTK_LIST_STORE(tMatrixEdit_store), &iter, index_c, "", -1);
			}
			if(!gtk_tree_model_iter_next(GTK_TREE_MODEL(tMatrixEdit_store), &iter)) break;
		}
	}
}
void on_matrix_edit_spinbutton_rows_value_changed(GtkSpinButton *w, gpointer) {
	gint new_r = gtk_spin_button_get_value_as_int(w);
	gint r = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(tMatrixEdit_store), NULL);
	gint c = matrix_edit_columns.size();
	bool b_matrix = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(matrixedit_builder, "matrix_edit_radiobutton_matrix")));
	GtkTreeIter iter;
	if(r < new_r) {
		while(r < new_r) {
			gtk_list_store_append(GTK_LIST_STORE(tMatrixEdit_store), &iter);
			for(gint i = 0; i < c; i++) {
				if(b_matrix) gtk_list_store_set(GTK_LIST_STORE(tMatrixEdit_store), &iter, i, "0", -1);
				else gtk_list_store_set(GTK_LIST_STORE(tMatrixEdit_store), &iter, i, "", -1);
			}
			r++;
		}
	} else if(new_r < r) {
		gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(tMatrixEdit_store), &iter, NULL, new_r);
		while(gtk_list_store_iter_is_valid(GTK_LIST_STORE(tMatrixEdit_store), &iter)) {
			gtk_list_store_remove(GTK_LIST_STORE(tMatrixEdit_store), &iter);
		}
	}
}

void on_tMatrix_edited(GtkCellRendererText *cell, gchar *path_string, gchar *new_text, gpointer model) {
	GtkTreeIter iter;
	gint i_column = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cell), "column"));
	gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(model), &iter, path_string);
	gtk_list_store_set(GTK_LIST_STORE(model), &iter, i_column, new_text, -1);
}
gboolean on_tMatrix_editable_key_press_event(GtkWidget *w, GdkEventKey *event, gpointer renderer) {
	switch(event->keyval) {
		case GDK_KEY_Up: {}
		case GDK_KEY_Down: {}
		case GDK_KEY_Tab: {}
		case GDK_KEY_ISO_Enter: {}
		case GDK_KEY_KP_Enter: {}
		case GDK_KEY_Return: {
			gtk_cell_editable_editing_done(GTK_CELL_EDITABLE(w));
			GtkTreeViewColumn *column = NULL;
			GtkTreePath *path = NULL;
			gtk_tree_view_get_cursor(GTK_TREE_VIEW(tMatrix), &path, &column);
			if(path) {
				if(column) {		
					for(size_t i = 0; i < matrix_columns.size(); i++) {
						if(matrix_columns[i] == column) {
							if(event->keyval == GDK_KEY_Tab) {
								i++;
								if(i >= matrix_columns.size()) {
									gtk_tree_path_next(path);
									GtkTreeIter iter;
									if(!gtk_tree_model_get_iter(GTK_TREE_MODEL(tMatrix_store), &iter, path)) {
										gtk_tree_path_free(path);
										path = gtk_tree_path_new_first();
									}
									i = 0;
								}
							} else {
								if(event->keyval == GDK_KEY_Up) {
									if(!gtk_tree_path_prev(path)) {
										gtk_tree_path_free(path);
										path = gtk_tree_path_new_from_indices(gtk_tree_model_iter_n_children(GTK_TREE_MODEL(tMatrix_store), NULL) - 1, -1);
									}
								} else {
									gtk_tree_path_next(path);
									GtkTreeIter iter;
									if(!gtk_tree_model_get_iter(GTK_TREE_MODEL(tMatrix_store), &iter, path)) {
										gtk_tree_path_free(path);
										if(event->keyval != GDK_KEY_Up) return TRUE;
										path = gtk_tree_path_new_first();
									}
								}
							}
							gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(tMatrix), path, matrix_columns[i], FALSE, 0.0, 0.0);
							while(gtk_events_pending()) gtk_main_iteration();
							gtk_tree_view_set_cursor(GTK_TREE_VIEW(tMatrix), path, matrix_columns[i], TRUE);
							on_tMatrix_cursor_changed(GTK_TREE_VIEW(tMatrix), NULL);
							break;
						}
					}
				}
				gtk_tree_path_free(path);
			}
			return TRUE;
		}
	}
	return FALSE;
}
void on_tMatrix_editing_started(GtkCellRenderer *renderer, GtkCellEditable *editable, gchar *path, gpointer user_data) {
	g_signal_connect(G_OBJECT(editable), "key-press-event", G_CALLBACK(on_tMatrix_editable_key_press_event), renderer);
}
gboolean on_tMatrix_key_press_event(GtkWidget*, GdkEventKey *event, gpointer) {
	switch(event->keyval) {
		case GDK_KEY_Return: {break;}
		case GDK_KEY_Tab: {
			GtkTreeViewColumn *column = NULL;
			GtkTreePath *path = NULL;
			gtk_tree_view_get_cursor(GTK_TREE_VIEW(tMatrix), &path, &column);
			if(path) {
				if(column) {
					for(size_t i = 0; i < matrix_columns.size(); i++) {
						if(matrix_columns[i] == column) {
							i++;
							if(i < matrix_columns.size()) {
								gtk_tree_view_set_cursor(GTK_TREE_VIEW(tMatrix), path, matrix_columns[i], FALSE);
								while(gtk_events_pending()) gtk_main_iteration();
								gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(tMatrix), path, matrix_columns[i], FALSE, 0.0, 0.0);
							} else {
								gtk_tree_path_next(path);
								GtkTreeIter iter;
								if(!gtk_tree_model_get_iter(GTK_TREE_MODEL(tMatrix_store), &iter, path)) {
									gtk_tree_path_free(path);
									path = gtk_tree_path_new_first();
								}
								gtk_tree_view_set_cursor(GTK_TREE_VIEW(tMatrix), path, matrix_columns[0], FALSE);
								while(gtk_events_pending()) gtk_main_iteration();
								gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(tMatrix), path, matrix_columns[0], FALSE, 0.0, 0.0);
							}
							gtk_tree_path_free(path);
							on_tMatrix_cursor_changed(GTK_TREE_VIEW(tMatrix), NULL);
							return TRUE;
						}
					}
				}
				gtk_tree_path_free(path);
			}
			break;
		}
		default: {
			if(event->length == 0) return FALSE;
			GtkTreeViewColumn *column = NULL;
			GtkTreePath *path = NULL;
			gtk_tree_view_get_cursor(GTK_TREE_VIEW(tMatrix), &path, &column);
			if(path) {
				if(column) {
					gtk_tree_view_set_cursor(GTK_TREE_VIEW(tMatrix), path, column, TRUE);
					while(gtk_events_pending()) gtk_main_iteration();
					gboolean return_val = FALSE;
					g_signal_emit_by_name((gpointer) gtk_builder_get_object(matrix_builder, "matrix_dialog"), "key_press_event", event, &return_val);
					gtk_tree_path_free(path);
					return TRUE;
				}
				gtk_tree_path_free(path);
			}
		}
	}
	return FALSE;
}
gboolean on_tMatrix_button_press_event(GtkWidget*, GdkEventButton *event, gpointer) {
	if(event->button != 1) return FALSE;
	GtkTreeViewColumn *column = NULL;
	GtkTreePath *path = NULL;
	if(gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(tMatrix), (gint) event->x, (gint) event->y, &path, &column, NULL, NULL) && path && column) {
		gtk_tree_view_set_cursor(GTK_TREE_VIEW(tMatrix), path, column, TRUE);
		gtk_tree_path_free(path);
		return TRUE;
	}
	if(path) gtk_tree_path_free(path);
	return FALSE;
}
GtkTreeIter matrix_prev_iter;
gint matrix_prev_column;
bool block_matrix_update_cursor = false;
gboolean on_tMatrix_cursor_changed(GtkTreeView*, gpointer) {
	if(block_matrix_update_cursor) return FALSE;
	GtkTreeViewColumn *column = NULL;
	GtkTreePath *path = NULL;
	GtkTreeIter iter;
	gtk_tree_view_get_cursor(GTK_TREE_VIEW(tMatrix), &path, &column);
	bool b = false;
	if(path) {
		if(column) {
			if(gtk_tree_model_get_iter(GTK_TREE_MODEL(tMatrix_store), &iter, path)) {
				gint i_column = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column"));
				matrix_prev_iter = iter;
				matrix_prev_column = i_column;
				gchar *pos_str;
				if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(matrix_builder, "matrix_radiobutton_matrix")))) {
					pos_str = g_strdup_printf("(%i, %i)", i_column + 1, gtk_tree_path_get_indices(path)[0] + 1);
				} else {
					pos_str = g_strdup_printf("%i", (int) (i_column + 1 + matrix_columns.size() * gtk_tree_path_get_indices(path)[0]));
				}
				gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(matrix_builder, "matrix_label_position")), pos_str);
				g_free(pos_str);
				b = true;
			}
		}
		gtk_tree_path_free(path);
	}
	if(!b) gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(matrix_builder, "matrix_label_position")), _("none"));
	return FALSE;
}

void on_matrix_spinbutton_columns_value_changed(GtkSpinButton *w, gpointer) {
	gint c = matrix_columns.size();
	gint new_c = gtk_spin_button_get_value_as_int(w);
	if(new_c < c) {
		for(gint index_c = new_c; index_c < c; index_c++) {
			gtk_tree_view_remove_column(GTK_TREE_VIEW(tMatrix), matrix_columns[index_c]);
		}
		matrix_columns.resize(new_c);
	} else {
		GtkTreeIter iter;
		for(gint index_c = c; index_c < new_c; index_c++) {
			GtkCellRenderer *matrix_renderer = gtk_cell_renderer_text_new();
			g_object_set(G_OBJECT(matrix_renderer), "editable", TRUE, NULL);
			g_object_set(G_OBJECT(matrix_renderer), "xalign", 1.0, NULL);
			g_object_set_data(G_OBJECT(matrix_renderer), "column", GINT_TO_POINTER(index_c));
			g_signal_connect(G_OBJECT(matrix_renderer), "edited", G_CALLBACK(on_tMatrix_edited), GTK_TREE_MODEL(tMatrix_store));
			g_signal_connect(G_OBJECT(matrix_renderer), "editing-started", G_CALLBACK(on_tMatrix_editing_started), GTK_TREE_MODEL(tMatrix_store));
			GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes(i2s(index_c).c_str(), matrix_renderer, "text", index_c, NULL);
			g_object_set_data (G_OBJECT(column), "column", GINT_TO_POINTER(index_c));
			gtk_tree_view_column_set_min_width(column, 50);
			gtk_tree_view_column_set_alignment(column, 0.5);
			gtk_tree_view_append_column(GTK_TREE_VIEW(tMatrix), column);
			gtk_tree_view_column_set_expand(column, TRUE);
			matrix_columns.push_back(column);
		}
		if(!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tMatrix_store), &iter)) return;
		bool b_matrix = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(matrix_builder, "matrix_radiobutton_matrix")));
		while(true) {
			for(gint index_c = c; index_c < new_c; index_c++) {
				if(b_matrix) gtk_list_store_set(GTK_LIST_STORE(tMatrix_store), &iter, index_c, "0", -1);
				else gtk_list_store_set(GTK_LIST_STORE(tMatrix_store), &iter, index_c, "", -1);
			}
			if(!gtk_tree_model_iter_next(GTK_TREE_MODEL(tMatrix_store), &iter)) break;
		}
	}
}
void on_matrix_spinbutton_rows_value_changed(GtkSpinButton *w, gpointer) {
	gint new_r = gtk_spin_button_get_value_as_int(w);
	gint r = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(tMatrix_store), NULL);
	gint c = matrix_columns.size();
	bool b_matrix = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(matrix_builder, "matrix_radiobutton_matrix")));
	GtkTreeIter iter;
	if(r < new_r) {
		while(r < new_r) {
			gtk_list_store_append(GTK_LIST_STORE(tMatrix_store), &iter);
			for(gint i = 0; i < c; i++) {
				if(b_matrix) gtk_list_store_set(GTK_LIST_STORE(tMatrix_store), &iter, i, "0", -1);
				else gtk_list_store_set(GTK_LIST_STORE(tMatrix_store), &iter, i, "", -1);
			}
			r++;
		}
	} else if(new_r < r) {
		gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(tMatrix_store), &iter, NULL, new_r);
		while(gtk_list_store_iter_is_valid(GTK_LIST_STORE(tMatrix_store), &iter)) {
			gtk_list_store_remove(GTK_LIST_STORE(tMatrix_store), &iter);
		}
	}
}

bool updating_percentage_entries = false;
void update_percentage_entries();
vector<int> percentage_entries_changes;
void on_percentage_button_calculate_clicked(GtkWidget*, gpointer) {
	update_percentage_entries();
}
void on_percentage_button_clear_clicked(GtkWidget*, gpointer) {
	percentage_entries_changes.clear();
	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(percentage_builder, "percentage_entry_1")), "");
	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(percentage_builder, "percentage_entry_2")), "");
	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(percentage_builder, "percentage_entry_3")), "");
	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(percentage_builder, "percentage_entry_4")), "");
	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(percentage_builder, "percentage_entry_5")), "");
	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(percentage_builder, "percentage_entry_6")), "");
	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(percentage_builder, "percentage_entry_7")), "");
}
void percentage_entry_changed(int entry_id, GtkEntry *w) {
	for(size_t i = 0; i < percentage_entries_changes.size(); i++) {
		if(percentage_entries_changes[i] == entry_id) {
			percentage_entries_changes.erase(percentage_entries_changes.begin() + i);
			break;
		}
	}
	if(gtk_entry_get_text_length(w) == 0) return;
	percentage_entries_changes.push_back(entry_id);
}
void on_percentage_entry_1_changed(GtkEditable *w, gpointer) {percentage_entry_changed(1, GTK_ENTRY(w));}
void on_percentage_entry_2_changed(GtkEditable *w, gpointer) {percentage_entry_changed(2, GTK_ENTRY(w));}
void on_percentage_entry_3_changed(GtkEditable *w, gpointer) {percentage_entry_changed(4, GTK_ENTRY(w));}
void on_percentage_entry_4_changed(GtkEditable *w, gpointer) {percentage_entry_changed(8, GTK_ENTRY(w));}
void on_percentage_entry_5_changed(GtkEditable *w, gpointer) {percentage_entry_changed(16, GTK_ENTRY(w));}
void on_percentage_entry_6_changed(GtkEditable *w, gpointer) {percentage_entry_changed(32, GTK_ENTRY(w));}
void on_percentage_entry_7_changed(GtkEditable *w, gpointer) {percentage_entry_changed(64, GTK_ENTRY(w));}
void on_percentage_entry_1_activate(GtkEditable *w, gpointer) {percentage_entry_changed(1, GTK_ENTRY(w)); update_percentage_entries();}
void on_percentage_entry_2_activate(GtkEditable *w, gpointer) {percentage_entry_changed(2, GTK_ENTRY(w)); update_percentage_entries();}
void on_percentage_entry_3_activate(GtkEditable *w, gpointer) {percentage_entry_changed(4, GTK_ENTRY(w)); update_percentage_entries();}
void on_percentage_entry_4_activate(GtkEditable *w, gpointer) {percentage_entry_changed(8, GTK_ENTRY(w)); update_percentage_entries();}
void on_percentage_entry_5_activate(GtkEditable *w, gpointer) {percentage_entry_changed(16, GTK_ENTRY(w)); update_percentage_entries();}
void on_percentage_entry_6_activate(GtkEditable *w, gpointer) {percentage_entry_changed(32, GTK_ENTRY(w)); update_percentage_entries();}
void on_percentage_entry_7_activate(GtkEditable *w, gpointer) {percentage_entry_changed(64, GTK_ENTRY(w)); update_percentage_entries();}
void update_percentage_entries() {
	if(updating_percentage_entries) return;
	if(percentage_entries_changes.size() < 2) return;
	int variant = percentage_entries_changes[percentage_entries_changes.size() - 1];
	int variant2 = percentage_entries_changes[percentage_entries_changes.size() - 2];
	if(variant > 4) {
		for(int i = percentage_entries_changes.size() - 3; i >= 0 && variant2 > 4; i--) {
			variant2 = percentage_entries_changes[(size_t) i];
		}
		if(variant2 > 4) return;
	}
	variant += variant2;
	updating_percentage_entries = true;
	GtkWidget *w1 = GTK_WIDGET(gtk_builder_get_object(percentage_builder, "percentage_entry_1"));
	GtkWidget *w2 = GTK_WIDGET(gtk_builder_get_object(percentage_builder, "percentage_entry_2"));
	GtkWidget *w3 = GTK_WIDGET(gtk_builder_get_object(percentage_builder, "percentage_entry_3"));
	GtkWidget *w4 = GTK_WIDGET(gtk_builder_get_object(percentage_builder, "percentage_entry_4"));
	GtkWidget *w5 = GTK_WIDGET(gtk_builder_get_object(percentage_builder, "percentage_entry_5"));
	GtkWidget *w6 = GTK_WIDGET(gtk_builder_get_object(percentage_builder, "percentage_entry_6"));
	GtkWidget *w7 = GTK_WIDGET(gtk_builder_get_object(percentage_builder, "percentage_entry_7"));
	g_signal_handlers_block_matched((gpointer) w1, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_percentage_entry_1_changed, NULL);
	g_signal_handlers_block_matched((gpointer) w2, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_percentage_entry_2_changed, NULL);
	g_signal_handlers_block_matched((gpointer) w3, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_percentage_entry_3_changed, NULL);
	g_signal_handlers_block_matched((gpointer) w4, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_percentage_entry_4_changed, NULL);
	g_signal_handlers_block_matched((gpointer) w5, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_percentage_entry_5_changed, NULL);
	g_signal_handlers_block_matched((gpointer) w6, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_percentage_entry_6_changed, NULL);
	g_signal_handlers_block_matched((gpointer) w7, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_percentage_entry_7_changed, NULL);
	MathStructure m1, m2, m3, m4, m5, m6, m7, m1_pre, m2_pre;
	string str1, str2;
	switch(variant) {
		case 3: {str1 = gtk_entry_get_text(GTK_ENTRY(w1)); str2 = gtk_entry_get_text(GTK_ENTRY(w2)); break;}
		case 5: {str1 = gtk_entry_get_text(GTK_ENTRY(w1)); str2 = gtk_entry_get_text(GTK_ENTRY(w3)); break;}
		case 9: {str1 = gtk_entry_get_text(GTK_ENTRY(w1)); str2 = gtk_entry_get_text(GTK_ENTRY(w4)); break;}
		case 17: {str1 = gtk_entry_get_text(GTK_ENTRY(w1)); str2 = gtk_entry_get_text(GTK_ENTRY(w5)); break;}
		case 33: {str1 = gtk_entry_get_text(GTK_ENTRY(w1)); str2 = gtk_entry_get_text(GTK_ENTRY(w6)); break;}
		case 65: {str1 = gtk_entry_get_text(GTK_ENTRY(w1)); str2 = gtk_entry_get_text(GTK_ENTRY(w7)); break;}
		case 6: {str1 = gtk_entry_get_text(GTK_ENTRY(w2)); str2 = gtk_entry_get_text(GTK_ENTRY(w3)); break;}
		case 10: {str1 = gtk_entry_get_text(GTK_ENTRY(w2)); str2 = gtk_entry_get_text(GTK_ENTRY(w4)); break;}
		case 18: {str1 = gtk_entry_get_text(GTK_ENTRY(w2)); str2 = gtk_entry_get_text(GTK_ENTRY(w5)); break;}
		case 34: {str1 = gtk_entry_get_text(GTK_ENTRY(w2)); str2 = gtk_entry_get_text(GTK_ENTRY(w6)); break;}
		case 66: {str1 = gtk_entry_get_text(GTK_ENTRY(w2)); str2 = gtk_entry_get_text(GTK_ENTRY(w7)); break;}
		case 12: {str1 = gtk_entry_get_text(GTK_ENTRY(w3)); str2 = gtk_entry_get_text(GTK_ENTRY(w4)); break;}
		case 20: {str1 = gtk_entry_get_text(GTK_ENTRY(w3)); str2 = gtk_entry_get_text(GTK_ENTRY(w5)); break;}
		case 36: {str1 = gtk_entry_get_text(GTK_ENTRY(w3)); str2 = gtk_entry_get_text(GTK_ENTRY(w6)); break;}
		case 68: {str1 = gtk_entry_get_text(GTK_ENTRY(w3)); str2 = gtk_entry_get_text(GTK_ENTRY(w7)); break;}
		default: {variant = 0;}
	}
	do_timeout = false;
	if(variant != 0) {
		m1_pre.set(CALCULATOR->parse(CALCULATOR->unlocalizeExpression(str1)));
		m2_pre.set(CALCULATOR->parse(CALCULATOR->unlocalizeExpression(str2)));
	}
	switch(variant) {
		case 3: {m1 = m1_pre; m2 = m2_pre; break;}
		case 5: {m1 = m1_pre; m2 = m2_pre; m2 += m1; break;}
		case 9: {m1 = m1_pre; m2 = m2_pre; m2 /= 100; m2 += 1; m2 *= m1; break;}
		case 17: {m1 = m1_pre; m2_pre /= 100; m2_pre += 1; m2 = m1; m2 /= m2_pre; break;}
		case 33: {m1 = m1_pre; m2 = m2_pre; m2 /= 100; m2 *= m1; break;}
		case 65: {m1 = m1_pre; m2_pre /= 100; m2 = m1; m2 /= m2_pre; break;}
		case 6: {m2 = m1_pre; m1 = m1_pre; m1 -= m2_pre; break;}
		case 10: {m2 = m1_pre; m2_pre /= 100; m2_pre += 1; m1 = m2; m1 /= m2_pre; break;}
		case 18: {m2 = m1_pre; m2_pre /= 100; m2_pre += 1; m1 = m2; m1 *= m2_pre; break;}
		case 34: {m2 = m1_pre; m2_pre /= 100; m1 = m2; m1 /= m2_pre; break;}
		case 66: {m2 = m1_pre; m2_pre /= 100; m1 = m2; m1 *= m2_pre; break;}
		case 12: {m1 = m1_pre; m2_pre /= 100; m1 /= m2_pre; m2 = m1; m2 += m1_pre; break;}
		case 20: {m1_pre.negate(); m2 = m1_pre; m2_pre /= 100; m2 /= m2_pre; m1 = m2; m1 += m1_pre; break;}
		case 36: {m1 = m1_pre; m2_pre /= 100; m2_pre -= 1; m1 /= m2_pre; m2 = m1; m2 += m1_pre; break;}
		case 68: {m1_pre.negate(); m2 = m1_pre; m2_pre /= 100; m2_pre -= 1; m2 /= m2_pre; m1 = m2; m1 += m1_pre; break;}
		default: {variant = 0;}
	}
	if(variant != 0) {
		m3 = m2; m3 -= m1;
		m6 = m2; m6 /= m1;
		m7 = m1; m7 /= m2;
		m4 = m6; m4 -= 1;
		m5 = m7; m5 -= 1;
		m4 *= 100; m5 *= 100; m6 *= 100; m7 *= 100;
		EvaluationOptions eo;
		eo.parse_options = evalops.parse_options;
		eo.parse_options.rpn = false;
		eo.parse_options.base = 10;
		eo.assume_denominators_nonzero = true;
		eo.warn_about_denominators_assumed_nonzero = false;
		CALCULATOR->calculate(&m1, 500, eo);
		CALCULATOR->calculate(&m2, 500, eo);
		CALCULATOR->calculate(&m3, 500, eo);
		CALCULATOR->calculate(&m4, 500, eo);
		CALCULATOR->calculate(&m5, 500, eo);
		CALCULATOR->calculate(&m6, 500, eo);
		CALCULATOR->calculate(&m7, 500, eo);
		PrintOptions po = printops;
		po.base = 10;
		po.number_fraction_format = FRACTION_DECIMAL;
		po.interval_display = INTERVAL_DISPLAY_SIGNIFICANT_DIGITS;
		gtk_entry_set_text(GTK_ENTRY(w1), m1.isAborted() ? CALCULATOR->timedOutString().c_str() : CALCULATOR->print(m1, 200, po).c_str());
		gtk_entry_set_text(GTK_ENTRY(w2), m2.isAborted() ? CALCULATOR->timedOutString().c_str() : CALCULATOR->print(m2, 200, po).c_str());
		gtk_entry_set_text(GTK_ENTRY(w3), m3.isAborted() ? CALCULATOR->timedOutString().c_str() : CALCULATOR->print(m3, 200, po).c_str());
		po.max_decimals = 2;
		po.use_max_decimals = true;
		gtk_entry_set_text(GTK_ENTRY(w4), m4.isAborted() ? CALCULATOR->timedOutString().c_str() : CALCULATOR->print(m4, 200, po).c_str());
		gtk_entry_set_text(GTK_ENTRY(w5), m5.isAborted() ? CALCULATOR->timedOutString().c_str() : CALCULATOR->print(m5, 200, po).c_str());
		gtk_entry_set_text(GTK_ENTRY(w6), m6.isAborted() ? CALCULATOR->timedOutString().c_str() : CALCULATOR->print(m6, 200, po).c_str());
		gtk_entry_set_text(GTK_ENTRY(w7), m7.isAborted() ? CALCULATOR->timedOutString().c_str() : CALCULATOR->print(m7, 200, po).c_str());
	}
	display_errors(NULL, GTK_WIDGET(gtk_builder_get_object(percentage_builder, "percentage_dialog")));
	do_timeout = true;
	g_signal_handlers_unblock_matched((gpointer) w1, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_percentage_entry_1_changed, NULL);
	g_signal_handlers_unblock_matched((gpointer) w2, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_percentage_entry_2_changed, NULL);
	g_signal_handlers_unblock_matched((gpointer) w3, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_percentage_entry_3_changed, NULL);
	g_signal_handlers_unblock_matched((gpointer) w4, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_percentage_entry_4_changed, NULL);
	g_signal_handlers_unblock_matched((gpointer) w5, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_percentage_entry_5_changed, NULL);
	g_signal_handlers_unblock_matched((gpointer) w6, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_percentage_entry_6_changed, NULL);
	g_signal_handlers_unblock_matched((gpointer) w7, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_percentage_entry_7_changed, NULL);
	updating_percentage_entries = false;
}

GtkWidget *nbases_get_entry() {
	if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(nbases_builder, "nbases_button_bin")))) return GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_entry_binary"));
	if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(nbases_builder, "nbases_button_oct")))) return GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_entry_octal"));
	if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(nbases_builder, "nbases_button_duo")))) return GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_entry_duo"));
	if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(nbases_builder, "nbases_button_hex")))) return GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_entry_hexadecimal"));
	if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(nbases_builder, "nbases_button_rom")))) return GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_entry_roman"));
	return GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_entry_decimal"));
}
int nbases_get_base() {
	if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(nbases_builder, "nbases_button_bin")))) return 2;
	if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(nbases_builder, "nbases_button_oct")))) return 8;
	if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(nbases_builder, "nbases_button_duo")))) return 12;
	if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(nbases_builder, "nbases_button_hex")))) return 16;
	if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(nbases_builder, "nbases_button_rom")))) return BASE_ROMAN_NUMERALS;
	return 10;
}

void update_nbases_entries(const MathStructure &value, int base) {
	GtkWidget *w_dec, *w_bin, *w_oct, *w_hex, *w_duo, *w_roman;
	w_dec = GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_entry_decimal"));
	w_bin = GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_entry_binary"));
	w_oct = GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_entry_octal"));
	w_hex = GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_entry_hexadecimal"));
	w_duo = GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_entry_duo"));
	w_roman = GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_entry_roman"));
	g_signal_handlers_block_matched((gpointer) w_dec, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_entry_decimal_changed, NULL);			
	g_signal_handlers_block_matched((gpointer) w_bin, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_entry_binary_changed, NULL);
	g_signal_handlers_block_matched((gpointer) w_oct, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_entry_octal_changed, NULL);
	g_signal_handlers_block_matched((gpointer) w_hex, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_entry_hexadecimal_changed, NULL);
	g_signal_handlers_block_matched((gpointer) w_duo, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_entry_duo_changed, NULL);
	g_signal_handlers_block_matched((gpointer) w_roman, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_entry_roman_changed, NULL);
	PrintOptions po;
	po.number_fraction_format = FRACTION_DECIMAL;
	po.interval_display = INTERVAL_DISPLAY_SIGNIFICANT_DIGITS;
	po.twos_complement = printops.twos_complement;
	po.hexadecimal_twos_complement = printops.hexadecimal_twos_complement;
	po.use_unicode_signs = printops.use_unicode_signs;
	po.lower_case_e = printops.lower_case_e;
	po.lower_case_numbers = printops.lower_case_numbers;
	po.base_display = BASE_DISPLAY_NONE;
	po.abbreviate_names = printops.abbreviate_names;
	po.digit_grouping = printops.digit_grouping;
	po.multiplication_sign = printops.multiplication_sign;
	po.division_sign = printops.division_sign;
	po.short_multiplication = printops.short_multiplication;
	po.excessive_parenthesis = printops.excessive_parenthesis;
	po.can_display_unicode_string_function = &can_display_unicode_string_function;
	po.can_display_unicode_string_arg = (void*) w_dec;
	po.spell_out_logical_operators = printops.spell_out_logical_operators;
	po.interval_display = INTERVAL_DISPLAY_SIGNIFICANT_DIGITS;
	string str;
	if(base != 10) {po.base = 10; str = value.isAborted() ? CALCULATOR->timedOutString().c_str() : CALCULATOR->print(value, 200, po); if(str.length() > 1000) {str = _("result is too long");} gtk_entry_set_text(GTK_ENTRY(w_dec), str.c_str());}
	if(base != 8) {po.base = 8; str = value.isAborted() ? CALCULATOR->timedOutString().c_str() : CALCULATOR->print(value, 200, po); if(str.length() > 1000) {str = _("result is too long");} gtk_entry_set_text(GTK_ENTRY(w_oct), str.c_str());}
	if(base != 12) {po.base = 12; str = value.isAborted() ? CALCULATOR->timedOutString().c_str() : CALCULATOR->print(value, 200, po); if(str.length() > 1000) {str = _("result is too long");} gtk_entry_set_text(GTK_ENTRY(w_duo), str.c_str());}
	if(base != 16) {po.base = 16; str = value.isAborted() ? CALCULATOR->timedOutString().c_str() : CALCULATOR->print(value, 200, po); if(str.length() > 1000) {str = _("result is too long");} gtk_entry_set_text(GTK_ENTRY(w_hex), str.c_str());}
	if(base != BASE_ROMAN_NUMERALS) {
		if(value.isAborted()) {
			gtk_entry_set_text(GTK_ENTRY(w_roman), CALCULATOR->timedOutString().c_str());
		} else if(!value.isNumber() || !value.number().isReal() || !(value.number() <= 9999) || !(value.number() >= -9999)) {
			gtk_entry_set_text(GTK_ENTRY(w_roman), "-");
		} else {
			Number nr = value.number(); nr.round(printops.round_halfway_to_even);
			po.base = BASE_ROMAN_NUMERALS;
			gtk_entry_set_text(GTK_ENTRY(w_roman), nr.print(po).c_str());
		}
	}
	if(base != 2) {po.base = 2; po.base_display = BASE_DISPLAY_NORMAL; str = value.isAborted() ? CALCULATOR->timedOutString().c_str() : CALCULATOR->print(value, 200, po); if(str.length() > 1000) {str = _("result is too long");} gtk_entry_set_text(GTK_ENTRY(w_bin), str.c_str());}
	g_signal_handlers_unblock_matched((gpointer) w_dec, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_entry_decimal_changed, NULL);
	g_signal_handlers_unblock_matched((gpointer) w_bin, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_entry_binary_changed, NULL);
	g_signal_handlers_unblock_matched((gpointer) w_oct, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_entry_octal_changed, NULL);
	g_signal_handlers_unblock_matched((gpointer) w_hex, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_entry_hexadecimal_changed, NULL);
	g_signal_handlers_unblock_matched((gpointer) w_duo, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_entry_duo_changed, NULL);
	g_signal_handlers_unblock_matched((gpointer) w_roman, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_entry_roman_changed, NULL);
	gtk_widget_set_tooltip_text(w_dec, "");
	gtk_widget_set_tooltip_text(w_bin, "");
	gtk_widget_set_tooltip_text(w_oct, "");
	gtk_widget_set_tooltip_text(w_duo, "");
	gtk_widget_set_tooltip_text(w_hex, "");
	gtk_widget_set_tooltip_text(w_roman, "");
	if(base == 2) gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_label_binary")), "");
	if(base == 8) gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_label_octal")), "");
	if(base == 10) gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_label_decimal")), "");
	if(base == 12) gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_label_duodecimal")), "");
	if(base == 16) gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_label_hexadecimal")), "");
	if(base == BASE_ROMAN_NUMERALS) gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_label_roman")), "");
	gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_binary")), _("Binary"));
		gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_octal")), _("Octal"));
		gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_decimal")), _("Decimal"));
		gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_duodecimal")), _("Duodecimal"));
		gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_hexadecimal")), _("Hexadecimal"));
		gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_roman")), _("Roman numerals"));
	if(CALCULATOR->message()) {
		string sfull;
		int index = 0;
		MessageType mtype_highest = MESSAGE_INFORMATION;
		while(true) {
			MessageType mtype = CALCULATOR->message()->type();
			if(index > 0) {
				if(index == 1) sfull = "• " + sfull;
				sfull += "\n• ";
			}
			sfull += CALCULATOR->message()->message();
			if(mtype > mtype_highest) {
				mtype_highest = mtype;
			}
			if(!CALCULATOR->nextMessage()) break;
			index++;
		}
		if(base == 2) gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_label_binary")), sfull.c_str());
		else if(base == 8) gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_label_octal")), sfull.c_str());
		else if(base == 10) gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_label_decimal")), sfull.c_str());
		else if(base == 12) gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_label_duodecimal")), sfull.c_str());
		else if(base == 16) gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_label_hexadecimal")), sfull.c_str());
		else if(base == BASE_ROMAN_NUMERALS) gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_label_roman")), sfull.c_str());
		if(base == 10) gtk_widget_set_tooltip_text(w_dec, sfull.c_str());
		else if(base == 2) gtk_widget_set_tooltip_text(w_bin, sfull.c_str());
		else if(base == 8) gtk_widget_set_tooltip_text(w_oct, sfull.c_str());
		else if(base == 12) gtk_widget_set_tooltip_text(w_duo, sfull.c_str());
		else if(base == 16) gtk_widget_set_tooltip_text(w_hex, sfull.c_str());
		else if(base == BASE_ROMAN_NUMERALS) gtk_widget_set_tooltip_text(w_roman, sfull.c_str());
		if(mtype_highest != MESSAGE_INFORMATION) {
			string str = "<span foreground=\"";
			if(mtype_highest == MESSAGE_ERROR) str += nbases_error_color;
			else str += nbases_warning_color;
			str += "\">";
			if(base == 2) str += _("Binary");
			else if(base == 8) str += _("Octal");
			else if(base == 10) str += _("Decimal");
			else if(base == 12) str += _("Duodecimal");
			else if(base == 16) str += _("Hexadecimal");
			else if(base == BASE_ROMAN_NUMERALS) str += _("Roman numerals");
			str += "</span>";
			if(base == 2) gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_binary")), str.c_str());
			else if(base == 8) gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_octal")), str.c_str());
			else if(base == 10) gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_decimal")), str.c_str());
			else if(base == 12) gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_duodecimal")), str.c_str());
			else if(base == 16) gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_hexadecimal")), str.c_str());
			else if(base == BASE_ROMAN_NUMERALS) gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_roman")), str.c_str());
		}
	}
}
void on_nbases_button_close_clicked(GtkButton*, gpointer) {
	gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_dialog")));
}
void on_nbases_entry_decimal_changed(GtkEditable *editable, gpointer) {	
	if(changing_in_nbases_dialog) return;
	string str = gtk_entry_get_text(GTK_ENTRY(editable));
	remove_blank_ends(str);
	if(str.empty()) return;
	if(last_is_operator(str, true)) return;
	changing_in_nbases_dialog = true;	
	EvaluationOptions eo;
	eo.parse_options.angle_unit = evalops.parse_options.angle_unit;
	eo.parse_options.unknowns_enabled = evalops.parse_options.unknowns_enabled;
	MathStructure value;
	do_timeout = false;
	CALCULATOR->calculate(&value, CALCULATOR->unlocalizeExpression(gtk_entry_get_text(GTK_ENTRY(editable)), evalops.parse_options), 1500, eo);
	update_nbases_entries(value, 10);
	do_timeout = true;
	changing_in_nbases_dialog = false;
}
void on_nbases_entry_binary_changed(GtkEditable *editable, gpointer) {
	if(changing_in_nbases_dialog) return;
	string str = gtk_entry_get_text(GTK_ENTRY(editable));
	remove_blank_ends(str);
	if(str.empty()) return;
	if(last_is_operator(str)) return;
	EvaluationOptions eo;
	eo.parse_options.unknowns_enabled = evalops.parse_options.unknowns_enabled;
	eo.parse_options.base = BASE_BINARY;
	eo.parse_options.angle_unit = evalops.parse_options.angle_unit;
	eo.parse_options.twos_complement = twos_complement_in;
	changing_in_nbases_dialog = true;
	MathStructure value;
	do_timeout = false;
	CALCULATOR->calculate(&value, CALCULATOR->unlocalizeExpression(gtk_entry_get_text(GTK_ENTRY(editable)), evalops.parse_options), 1500, eo);
	update_nbases_entries(value, 2);
	do_timeout = true;
	changing_in_nbases_dialog = false;
}
void on_nbases_entry_octal_changed(GtkEditable *editable, gpointer) {
	if(changing_in_nbases_dialog) return;
	string str = gtk_entry_get_text(GTK_ENTRY(editable));
	remove_blank_ends(str);
	if(str.empty()) return;	
	if(last_is_operator(str)) return;
	EvaluationOptions eo;
	eo.parse_options.unknowns_enabled = evalops.parse_options.unknowns_enabled;
	eo.parse_options.base = BASE_OCTAL;
	eo.parse_options.angle_unit = evalops.parse_options.angle_unit;
	changing_in_nbases_dialog = true;
	MathStructure value;
	do_timeout = false;
	CALCULATOR->calculate(&value, CALCULATOR->unlocalizeExpression(gtk_entry_get_text(GTK_ENTRY(editable)), evalops.parse_options), 1500, eo);
	update_nbases_entries(value, 8);
	do_timeout = true;
	changing_in_nbases_dialog = false;
}
void on_nbases_entry_hexadecimal_changed(GtkEditable *editable, gpointer) {
	if(changing_in_nbases_dialog) return;
	string str = gtk_entry_get_text(GTK_ENTRY(editable));
	remove_blank_ends(str);
	if(str.empty()) return;	
	if(last_is_operator(str)) return;
	EvaluationOptions eo;
	eo.parse_options.unknowns_enabled = evalops.parse_options.unknowns_enabled;
	eo.parse_options.base = BASE_HEXADECIMAL;
	eo.parse_options.angle_unit = evalops.parse_options.angle_unit;
	eo.parse_options.hexadecimal_twos_complement = hexadecimal_twos_complement_in;
	changing_in_nbases_dialog = true;	
	MathStructure value;
	do_timeout = false;
	str = CALCULATOR->unlocalizeExpression(gtk_entry_get_text(GTK_ENTRY(editable)), evalops.parse_options);
	CALCULATOR->calculate(&value, str, 1500, eo);
	update_nbases_entries(value, 16);
	do_timeout = true;
	changing_in_nbases_dialog = false;
}
void on_nbases_entry_duo_changed(GtkEditable *editable, gpointer) {
	if(changing_in_nbases_dialog) return;
	string str = gtk_entry_get_text(GTK_ENTRY(editable));
	remove_blank_ends(str);
	if(str.empty()) return;	
	if(last_is_operator(str)) return;
	EvaluationOptions eo;
	eo.parse_options.unknowns_enabled = evalops.parse_options.unknowns_enabled;
	eo.parse_options.base = BASE_DUODECIMAL;
	eo.parse_options.angle_unit = evalops.parse_options.angle_unit;
	changing_in_nbases_dialog = true;	
	MathStructure value;
	do_timeout = false;
	CALCULATOR->calculate(&value, CALCULATOR->unlocalizeExpression(gtk_entry_get_text(GTK_ENTRY(editable)), evalops.parse_options), 1500, eo);
	update_nbases_entries(value, 12);
	do_timeout = true;
	changing_in_nbases_dialog = false;
}
void on_nbases_entry_roman_changed(GtkEditable *editable, gpointer) {
	if(changing_in_nbases_dialog) return;
	string str = gtk_entry_get_text(GTK_ENTRY(editable));
	remove_blank_ends(str);
	if(str.empty()) return;
	if(last_is_operator(str) && (str[str.length() - 1] != '|' || str.find('|') == str.length() - 1)) return;
	EvaluationOptions eo;
	eo.parse_options.unknowns_enabled = evalops.parse_options.unknowns_enabled;
	eo.parse_options.base = BASE_ROMAN_NUMERALS;
	eo.parse_options.angle_unit = evalops.parse_options.angle_unit;
	changing_in_nbases_dialog = true;	
	MathStructure value;
	do_timeout = false;
	CALCULATOR->calculate(&value, CALCULATOR->unlocalizeExpression(gtk_entry_get_text(GTK_ENTRY(editable)), evalops.parse_options), 1500, eo);
	update_nbases_entries(value, BASE_ROMAN_NUMERALS);
	do_timeout = true;
	changing_in_nbases_dialog = false;
}

void on_nbases_button_bin_toggled(GtkToggleButton *w, gpointer);
void on_nbases_button_oct_toggled(GtkToggleButton *w, gpointer);
void on_nbases_button_dec_toggled(GtkToggleButton *w, gpointer);
void on_nbases_button_duo_toggled(GtkToggleButton *w, gpointer);
void on_nbases_button_hex_toggled(GtkToggleButton *w, gpointer);
void on_nbases_button_rom_toggled(GtkToggleButton *w, gpointer);

void update_nbases_keypad(int base) {
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(nbases_builder, "nbases_button_bin"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_button_bin_toggled, NULL);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(nbases_builder, "nbases_button_oct"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_button_oct_toggled, NULL);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(nbases_builder, "nbases_button_dec"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_button_dec_toggled, NULL);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(nbases_builder, "nbases_button_duo"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_button_duo_toggled, NULL);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(nbases_builder, "nbases_button_hex"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_button_hex_toggled, NULL);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(nbases_builder, "nbases_button_rom"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_button_rom_toggled, NULL);
	if(base != 2) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(nbases_builder, "nbases_button_bin")), FALSE);
	if(base != 8) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(nbases_builder, "nbases_button_oct")), FALSE);
	if(base != 10) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(nbases_builder, "nbases_button_dec")), FALSE);
	if(base != 12) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(nbases_builder, "nbases_button_duo")), FALSE);
	if(base != 16) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(nbases_builder, "nbases_button_hex")), FALSE);
	if(base != BASE_ROMAN_NUMERALS) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(nbases_builder, "nbases_button_rom")), FALSE);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(nbases_builder, "nbases_button_bin"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_button_bin_toggled, NULL);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(nbases_builder, "nbases_button_oct"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_button_oct_toggled, NULL);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(nbases_builder, "nbases_button_dec"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_button_dec_toggled, NULL);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(nbases_builder, "nbases_button_duo"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_button_duo_toggled, NULL);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(nbases_builder, "nbases_button_hex"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_button_hex_toggled, NULL);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(nbases_builder, "nbases_button_rom"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_button_rom_toggled, NULL);
	
	if(base == BASE_ROMAN_NUMERALS && strcmp(gtk_label_get_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_one"))), "1") != 0) return;
	
	if(base == 12) {
		if(strcmp(gtk_label_get_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_a"))), "A") == 0) {
			if(can_display_unicode_string_function("↊", (void*) gtk_builder_get_object(nbases_builder, "nbases_label_a"))) gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_a")), "↊");
			else gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_a")), "X");
			if(can_display_unicode_string_function("↋", (void*) gtk_builder_get_object(nbases_builder, "nbases_label_b"))) gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_b")), "↋");
			else gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_b")), "E");
		}
	} else if(strcmp(gtk_label_get_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_a"))), "A") != 0) {
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_a")), "A");
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_b")), "B");
	}
	bool uni_roman = (base == BASE_ROMAN_NUMERALS) && printops.use_unicode_signs && can_display_unicode_string_function("Ɔ", (void*) gtk_builder_get_object(nbases_builder, "nbases_label_9"));
	if(base == BASE_ROMAN_NUMERALS) {
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_zero")), "I");
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_one")), "V");
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_two")), "X");
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_three")), "L");
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_four")), "C");
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_five")), "D");
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_six")), "M");
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_eight")), "|");
		if(uni_roman) {
			gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_nine")), "Ɔ");
		} else {
			gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_seven")), "(");
			gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_nine")), ")");
		}
	} else if(strcmp(gtk_label_get_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_one"))), "1") != 0) {
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_zero")), "0");
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_one")), "1");
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_two")), "2");
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_three")), "3");
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_four")), "4");
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_five")), "5");
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_six")), "6");
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_seven")), "7");
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_eight")), "8");
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_nine")), "9");
	}
	
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_button_two")), base != 2);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_button_three")), base != 2);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_button_four")), base != 2);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_button_five")), base != 2);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_button_six")), base != 2);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_button_seven")), base != 2 && (base != BASE_ROMAN_NUMERALS || !uni_roman));
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_button_eight")), base != 2 && base != 8);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_button_nine")), base != 2 && base != 8);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_button_a")), base >= 12);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_button_b")), base >= 12);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_button_c")), base == 16);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_button_d")), base == 16);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_button_e")), base == 16);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_button_f")), base == 16);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_button_and")), base != BASE_ROMAN_NUMERALS);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_button_or")), base != BASE_ROMAN_NUMERALS);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_button_xor")), base != BASE_ROMAN_NUMERALS);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_button_not")), base != BASE_ROMAN_NUMERALS);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_button_left_shift")), base != BASE_ROMAN_NUMERALS);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_button_right_shift")), base != BASE_ROMAN_NUMERALS);
	
}

gboolean on_nbases_entry_binary_focus_in_event(GtkWidget*, GdkEventFocus*, gpointer);
gboolean on_nbases_entry_octal_focus_in_event(GtkWidget*, GdkEventFocus*, gpointer);
gboolean on_nbases_entry_decimal_focus_in_event(GtkWidget*, GdkEventFocus*, gpointer);
gboolean on_nbases_entry_duo_focus_in_event(GtkWidget*, GdkEventFocus*, gpointer);
gboolean on_nbases_entry_hexadecimal_focus_in_event(GtkWidget*, GdkEventFocus*, gpointer);
gboolean on_nbases_entry_roman_focus_in_event(GtkWidget*, GdkEventFocus*, gpointer);

void on_nbases_button_bin_toggled(GtkToggleButton *w, gpointer) {
	if(!gtk_toggle_button_get_active(w)) {
		g_signal_handlers_block_matched((gpointer) w, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_button_bin_toggled, NULL);
		gtk_toggle_button_set_active(w, TRUE);
		g_signal_handlers_unblock_matched((gpointer) w, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_button_bin_toggled, NULL);
		return;
	}
	update_nbases_keypad(2);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(nbases_builder, "nbases_entry_binary"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_entry_binary_focus_in_event, NULL);
	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_entry_binary")));
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(nbases_builder, "nbases_entry_binary"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_entry_binary_focus_in_event, NULL);
}
void on_nbases_button_oct_toggled(GtkToggleButton *w, gpointer) {
	if(!gtk_toggle_button_get_active(w)) {
		g_signal_handlers_block_matched((gpointer) w, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_button_oct_toggled, NULL);
		gtk_toggle_button_set_active(w, TRUE);
		g_signal_handlers_unblock_matched((gpointer) w, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_button_oct_toggled, NULL);
		return;
	}
	update_nbases_keypad(8);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(nbases_builder, "nbases_entry_octal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_entry_octal_focus_in_event, NULL);
	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_entry_octal")));
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(nbases_builder, "nbases_entry_octal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_entry_octal_focus_in_event, NULL);
}
void on_nbases_button_dec_toggled(GtkToggleButton *w, gpointer) {
	if(!gtk_toggle_button_get_active(w)) {
		g_signal_handlers_block_matched((gpointer) w, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_button_dec_toggled, NULL);
		gtk_toggle_button_set_active(w, TRUE);
		g_signal_handlers_unblock_matched((gpointer) w, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_button_dec_toggled, NULL);
		return;
	}
	update_nbases_keypad(10);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(nbases_builder, "nbases_entry_decimal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_entry_decimal_focus_in_event, NULL);
	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_entry_decimal")));
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(nbases_builder, "nbases_entry_decimal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_entry_decimal_focus_in_event, NULL);
}
void on_nbases_button_duo_toggled(GtkToggleButton *w, gpointer) {
	if(!gtk_toggle_button_get_active(w)) {
		g_signal_handlers_block_matched((gpointer) w, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_button_duo_toggled, NULL);
		gtk_toggle_button_set_active(w, TRUE);
		g_signal_handlers_unblock_matched((gpointer) w, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_button_duo_toggled, NULL);
		return;
	}
	update_nbases_keypad(12);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(nbases_builder, "nbases_entry_duo"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_entry_duo_focus_in_event, NULL);
	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_entry_duo")));
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(nbases_builder, "nbases_entry_duo"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_entry_duo_focus_in_event, NULL);
}
void on_nbases_button_hex_toggled(GtkToggleButton *w, gpointer) {
	if(!gtk_toggle_button_get_active(w)) {
		g_signal_handlers_block_matched((gpointer) w, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_button_hex_toggled, NULL);
		gtk_toggle_button_set_active(w, TRUE);
		g_signal_handlers_unblock_matched((gpointer) w, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_button_hex_toggled, NULL);
		return;
	}
	update_nbases_keypad(16);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(nbases_builder, "nbases_entry_hexadecimal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_entry_hexadecimal_focus_in_event, NULL);
	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_entry_hexadecimal")));
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(nbases_builder, "nbases_entry_hexadecimal"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_entry_hexadecimal_focus_in_event, NULL);
}
void on_nbases_button_rom_toggled(GtkToggleButton *w, gpointer) {
	if(!gtk_toggle_button_get_active(w)) {
		g_signal_handlers_block_matched((gpointer) w, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_button_rom_toggled, NULL);
		gtk_toggle_button_set_active(w, TRUE);
		g_signal_handlers_unblock_matched((gpointer) w, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_button_rom_toggled, NULL);
		return;
	}
	update_nbases_keypad(BASE_ROMAN_NUMERALS);
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(nbases_builder, "nbases_entry_roman"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_entry_roman_focus_in_event, NULL);
	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_entry_roman")));
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(nbases_builder, "nbases_entry_roman"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_entry_roman_focus_in_event, NULL);
}

gboolean on_nbases_entry_binary_focus_in_event(GtkWidget*, GdkEventFocus*, gpointer) {
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(nbases_builder, "nbases_button_bin"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_button_bin_toggled, NULL);
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(nbases_builder, "nbases_button_bin")), TRUE);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(nbases_builder, "nbases_button_bin"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_button_bin_toggled, NULL);
	update_nbases_keypad(2);
	return FALSE;
}
gboolean on_nbases_entry_octal_focus_in_event(GtkWidget*, GdkEventFocus*, gpointer) {
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(nbases_builder, "nbases_button_oct"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_button_oct_toggled, NULL);
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(nbases_builder, "nbases_button_oct")), TRUE);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(nbases_builder, "nbases_button_oct"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_button_oct_toggled, NULL);
	update_nbases_keypad(8);
	return FALSE;
}
gboolean on_nbases_entry_decimal_focus_in_event(GtkWidget*, GdkEventFocus*, gpointer) {
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(nbases_builder, "nbases_button_dec"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_button_dec_toggled, NULL);
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(nbases_builder, "nbases_button_dec")), TRUE);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(nbases_builder, "nbases_button_dec"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_button_dec_toggled, NULL);
	update_nbases_keypad(10);
	return FALSE;
}
gboolean on_nbases_entry_duo_focus_in_event(GtkWidget*, GdkEventFocus*, gpointer) {
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(nbases_builder, "nbases_button_duo"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_button_duo_toggled, NULL);
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(nbases_builder, "nbases_button_duo")), TRUE);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(nbases_builder, "nbases_button_duo"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_button_duo_toggled, NULL);
	update_nbases_keypad(12);
	return FALSE;
}
gboolean on_nbases_entry_hexadecimal_focus_in_event(GtkWidget*, GdkEventFocus*, gpointer) {
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(nbases_builder, "nbases_button_hex"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_button_hex_toggled, NULL);
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(nbases_builder, "nbases_button_hex")), TRUE);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(nbases_builder, "nbases_button_hex"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_button_hex_toggled, NULL);
	update_nbases_keypad(16);
	return FALSE;
}
gboolean on_nbases_entry_roman_focus_in_event(GtkWidget*, GdkEventFocus*, gpointer) {
	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(nbases_builder, "nbases_button_rom"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_button_rom_toggled, NULL);
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(nbases_builder, "nbases_button_rom")), TRUE);
	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(nbases_builder, "nbases_button_rom"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_button_rom_toggled, NULL);
	update_nbases_keypad(BASE_ROMAN_NUMERALS);
	return FALSE;
}

void nbases_insert_text(GtkWidget *w, const gchar *text) {
	changing_in_nbases_dialog = true;
	gtk_editable_delete_selection(GTK_EDITABLE(w));
	changing_in_nbases_dialog = false;
	gint pos = gtk_editable_get_position(GTK_EDITABLE(w));
	gtk_editable_insert_text(GTK_EDITABLE(w), text, -1, &pos);
	gtk_editable_set_position(GTK_EDITABLE(w), pos);
	gtk_widget_grab_focus(w);
	gtk_editable_select_region(GTK_EDITABLE(w), pos, pos);
}

void on_nbases_button_zero_clicked(GtkToggleButton*, gpointer) {
	nbases_insert_text(nbases_get_entry(), nbases_get_base() == BASE_ROMAN_NUMERALS ? "I" : "0");
}
void on_nbases_button_one_clicked(GtkToggleButton*, gpointer) {
	nbases_insert_text(nbases_get_entry(), nbases_get_base() == BASE_ROMAN_NUMERALS ? "V" : "1");
}
void on_nbases_button_two_clicked(GtkToggleButton*, gpointer) {
	nbases_insert_text(nbases_get_entry(), nbases_get_base() == BASE_ROMAN_NUMERALS ? "X" : "2");
}
void on_nbases_button_three_clicked(GtkToggleButton*, gpointer) {
	nbases_insert_text(nbases_get_entry(), nbases_get_base() == BASE_ROMAN_NUMERALS ? "L" : "3");
}
void on_nbases_button_four_clicked(GtkToggleButton*, gpointer) {
	nbases_insert_text(nbases_get_entry(), nbases_get_base() == BASE_ROMAN_NUMERALS ? "C" : "4");
}
void on_nbases_button_five_clicked(GtkToggleButton*, gpointer) {
	nbases_insert_text(nbases_get_entry(), nbases_get_base() == BASE_ROMAN_NUMERALS ? "D" : "5");
}
void on_nbases_button_six_clicked(GtkToggleButton*, gpointer) {
	nbases_insert_text(nbases_get_entry(), nbases_get_base() == BASE_ROMAN_NUMERALS ? "M" : "6");
}
void on_nbases_button_seven_clicked(GtkToggleButton*, gpointer) {
	nbases_insert_text(nbases_get_entry(), nbases_get_base() == BASE_ROMAN_NUMERALS ? "(" : "7");
}
void on_nbases_button_eight_clicked(GtkToggleButton*, gpointer) {
	nbases_insert_text(nbases_get_entry(), nbases_get_base() == BASE_ROMAN_NUMERALS ? "|" : "8");
}
void on_nbases_button_nine_clicked(GtkToggleButton*, gpointer) {
	nbases_insert_text(nbases_get_entry(), nbases_get_base() == BASE_ROMAN_NUMERALS ? (can_display_unicode_string_function("Ɔ", (void*) gtk_builder_get_object(nbases_builder, "nbases_entry_roman")) ? "Ɔ" : ")") : "9");
}
void on_nbases_button_a_clicked(GtkToggleButton*, gpointer) {
	nbases_insert_text(nbases_get_entry(), nbases_get_base() == 12 ? (can_display_unicode_string_function("↊", (void*) gtk_builder_get_object(nbases_builder, "nbases_entry_duo")) ? "↊" : "X") : (printops.lower_case_numbers ? "a" : "A"));
}
void on_nbases_button_b_clicked(GtkToggleButton*, gpointer) {
	nbases_insert_text(nbases_get_entry(), nbases_get_base() == 12 ? (can_display_unicode_string_function("↊", (void*) gtk_builder_get_object(nbases_builder, "nbases_entry_duo")) ? "↋" : "E") : (printops.lower_case_numbers ? "b" : "B"));
}
void on_nbases_button_c_clicked(GtkToggleButton*, gpointer) {
	nbases_insert_text(nbases_get_entry(), printops.lower_case_numbers ? "c" : "C");
}
void on_nbases_button_d_clicked(GtkToggleButton*, gpointer) {
	nbases_insert_text(nbases_get_entry(), printops.lower_case_numbers ? "d" : "D");
}
void on_nbases_button_e_clicked(GtkToggleButton*, gpointer) {
	nbases_insert_text(nbases_get_entry(), printops.lower_case_numbers ? "e" : "E");
}
void on_nbases_button_f_clicked(GtkToggleButton*, gpointer) {
	nbases_insert_text(nbases_get_entry(), printops.lower_case_numbers ? "f" : "F");
}
void on_nbases_button_add_clicked(GtkToggleButton*, gpointer) {
	nbases_insert_text(nbases_get_entry(), expression_add_sign());
}
void on_nbases_button_sub_clicked(GtkToggleButton*, gpointer) {
	nbases_insert_text(nbases_get_entry(), expression_sub_sign());
}
void on_nbases_button_times_clicked(GtkToggleButton*, gpointer) {
	nbases_insert_text(nbases_get_entry(), expression_times_sign());
}
void on_nbases_button_divide_clicked(GtkToggleButton*, gpointer) {
	nbases_insert_text(nbases_get_entry(), expression_divide_sign());
}
void on_nbases_button_and_clicked(GtkToggleButton*, gpointer) {
	nbases_insert_text(nbases_get_entry(), "&");
}
void on_nbases_button_or_clicked(GtkToggleButton*, gpointer) {
	nbases_insert_text(nbases_get_entry(), "|");
}
void on_nbases_button_xor_clicked(GtkToggleButton*, gpointer) {
	nbases_insert_text(nbases_get_entry(), " xor ");
}
void on_nbases_button_not_clicked(GtkToggleButton*, gpointer) {
	nbases_insert_text(nbases_get_entry(), "~");
}
void on_nbases_button_left_shift_clicked(GtkToggleButton*, gpointer) {
	nbases_insert_text(nbases_get_entry(), "<<");
}
void on_nbases_button_right_shift_clicked(GtkToggleButton*, gpointer) {
	nbases_insert_text(nbases_get_entry(), ">>");
}
void on_nbases_button_del_clicked(GtkToggleButton*, gpointer) {
	gint i1, i2;
	GtkWidget *w = nbases_get_entry();
	if(!gtk_editable_get_selection_bounds(GTK_EDITABLE(w), &i1, &i2)) {
		i1 = gtk_editable_get_position(GTK_EDITABLE(w));
		i2 = i1 + 1;
	}
	string str = gtk_entry_get_text(GTK_ENTRY(w));
	gtk_editable_delete_text(GTK_EDITABLE(w), i1, i2);
	if(str == gtk_entry_get_text(GTK_ENTRY(w))) gtk_editable_delete_text(GTK_EDITABLE(w), i1 - 1, i2 - 1);
	gtk_widget_grab_focus(w);
	gtk_editable_select_region(GTK_EDITABLE(w), i1, i1);
}
void on_nbases_button_ac_clicked(GtkToggleButton*, gpointer) {
	gtk_entry_set_text(GTK_ENTRY(nbases_get_entry()), "");
	gtk_widget_grab_focus(nbases_get_entry());
}

gboolean on_nbases_dialog_key_press_event(GtkWidget *o, GdkEventKey *event, gpointer) {
	if(b_busy) {
		if(event->keyval == GDK_KEY_Escape) {
			if(b_busy_expression) on_abort_calculation(NULL, 0, NULL);
			else if(b_busy_result) on_abort_display(NULL, 0, NULL);
			else if(b_busy_command) on_abort_command(NULL, 0, NULL);
		}
		return TRUE;
	}
	switch(event->keyval) {
		case GDK_KEY_asciicircum: {}
		case GDK_KEY_dead_circumflex: {
			bool input_xor = (caret_as_xor != ((event->state & GDK_CONTROL_MASK) > 0));
			nbases_insert_text(nbases_get_entry(), input_xor ? " xor " : "^");
			return TRUE;
		}
		case GDK_KEY_KP_Multiply: {}
		case GDK_KEY_asterisk: {
			nbases_insert_text(nbases_get_entry(), expression_times_sign());
			return TRUE;
		}
		case GDK_KEY_KP_Divide: {}
		case GDK_KEY_slash: {
			nbases_insert_text(nbases_get_entry(), expression_divide_sign());
			return TRUE;
		}
		case GDK_KEY_KP_Subtract: {}
		case GDK_KEY_minus: {
			nbases_insert_text(nbases_get_entry(), expression_sub_sign());
			return TRUE;
		}
		case GDK_KEY_KP_Add: {}
		case GDK_KEY_plus: {
			nbases_insert_text(nbases_get_entry(), expression_add_sign());
			return TRUE;
		}
		case GDK_KEY_braceleft: {}
		case GDK_KEY_braceright: {
			return TRUE;
		}
	}	
	return FALSE;
}


void on_button_functions_clicked(GtkButton*, gpointer) {
	manage_functions();
}
void on_button_variables_clicked(GtkButton*, gpointer) {
	manage_variables();
}
void on_button_units_clicked(GtkButton*, gpointer) {
	manage_units();
}
void on_button_bases_clicked(GtkButton*, gpointer) {
	on_menu_item_convert_number_bases_activate(NULL, NULL);
}
void on_button_convert_clicked(GtkButton*, gpointer user_data) {
	on_menu_item_convert_to_unit_expression_activate(NULL, user_data);
}


gboolean on_about_activate_link(GtkAboutDialog*, gchar *uri, gpointer) {
#ifdef _WIN32
	ShellExecuteA(NULL, "open", uri, NULL, NULL, SW_SHOWNORMAL);
	return TRUE;
#else
	return FALSE;
#endif
}

void on_menu_item_about_activate(GtkMenuItem*, gpointer) {
	const gchar *authors[] = {"Hanna Knutsson", NULL};
	GtkWidget *dialog = gtk_about_dialog_new();
	gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG(dialog), authors);
	gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(dialog), _("Powerful and easy to use calculator"));
	gtk_about_dialog_set_license_type(GTK_ABOUT_DIALOG(dialog), GTK_LICENSE_GPL_2_0);
	gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(dialog), "Copyright © 2003–2007, 2008, 2016-2019 Hanna Knutsson");
	gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(dialog), "Qalculate! (GTK+)");
	gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(dialog), VERSION);
	gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(dialog), "http://qalculate.github.io/");
	gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(mainwindow));
	g_signal_connect(G_OBJECT(dialog), "activate-link", G_CALLBACK(on_about_activate_link), NULL);
	gtk_dialog_run(GTK_DIALOG(dialog));
	gtk_widget_destroy(dialog);
}

void on_menu_item_help_activate(GtkMenuItem*, gpointer) {
	show_help("index.html", gtk_builder_get_object(main_builder, "main_window"));
}

/*
	precision has changed in precision dialog
*/
void on_precision_dialog_spinbutton_precision_value_changed(GtkSpinButton *w, gpointer) {
	CALCULATOR->setPrecision(gtk_spin_button_get_value_as_int(w));
}
void on_precision_dialog_button_recalculate_clicked(GtkButton*, gpointer) {
	CALCULATOR->setPrecision(gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_builder_get_object(precision_builder, "precision_dialog_spinbutton_precision"))));
	execute_expression(true, false, OPERATION_ADD, NULL, rpn_mode);
}


void on_decimals_dialog_spinbutton_max_value_changed(GtkSpinButton *w, gpointer) {
	printops.max_decimals = gtk_spin_button_get_value_as_int(w);
	result_format_updated();
}
void on_decimals_dialog_spinbutton_min_value_changed(GtkSpinButton *w, gpointer) {
	printops.min_decimals = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(w));
	result_format_updated();
}
void on_decimals_dialog_checkbutton_max_toggled(GtkToggleButton *w, gpointer) {
	printops.use_max_decimals = gtk_toggle_button_get_active(w);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(decimals_builder, "decimals_dialog_spinbutton_max")), printops.use_max_decimals);
	result_format_updated();
}
void on_decimals_dialog_checkbutton_min_toggled(GtkToggleButton *w, gpointer) {
	printops.use_min_decimals = gtk_toggle_button_get_active(w);
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(decimals_builder, "decimals_dialog_spinbutton_min")), printops.use_min_decimals);
	result_format_updated();
}

void on_unknown_edit_checkbutton_custom_assumptions_toggled(GtkToggleButton *w, gpointer) {
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unknownedit_builder, "unknown_edit_hbox_type")), gtk_toggle_button_get_active(w));
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unknownedit_builder, "unknown_edit_hbox_sign")), gtk_toggle_button_get_active(w));
}
void on_unknown_edit_combobox_type_changed(GtkComboBox *om, gpointer) {	
	if((AssumptionType) gtk_combo_box_get_active(om) + 2 <= ASSUMPTION_TYPE_COMPLEX && (AssumptionSign) gtk_combo_box_get_active(GTK_COMBO_BOX(gtk_builder_get_object(unknownedit_builder, "unknown_edit_combobox_sign"))) != ASSUMPTION_SIGN_NONZERO) {
		g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(unknownedit_builder, "unknown_edit_combobox_sign"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_unknown_edit_combobox_sign_changed, NULL);
		gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(unknownedit_builder, "unknown_edit_combobox_sign")), ASSUMPTION_SIGN_UNKNOWN);	
		g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(unknownedit_builder, "unknown_edit_combobox_sign"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_unknown_edit_combobox_sign_changed, NULL);
	}
}
void on_unknown_edit_combobox_sign_changed(GtkComboBox *om, gpointer) {	
	if((AssumptionSign) gtk_combo_box_get_active(om) != ASSUMPTION_SIGN_NONZERO && (AssumptionSign) gtk_combo_box_get_active(om) != ASSUMPTION_SIGN_UNKNOWN && (AssumptionType) gtk_combo_box_get_active(GTK_COMBO_BOX(gtk_builder_get_object(unknownedit_builder, "unknown_edit_combobox_type"))) <= ASSUMPTION_TYPE_COMPLEX - 2) {
		g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(unknownedit_builder, "unknown_edit_combobox_type"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_unknown_edit_combobox_type_changed, NULL);
		gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(unknownedit_builder, "unknown_edit_combobox_type")), ASSUMPTION_TYPE_REAL - 2);	
		g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(unknownedit_builder, "unknown_edit_combobox_type"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_unknown_edit_combobox_type_changed, NULL);
	}
}

gboolean on_variables_dialog_key_press_event(GtkWidget *o, GdkEventKey *event, gpointer) {
	if(gtk_widget_has_focus(GTK_WIDGET(tVariables)) && gdk_keyval_to_unicode(event->keyval) > 32) {
		gint start_pos = 0, end_pos = 0;
		gtk_editable_get_selection_bounds(GTK_EDITABLE(gtk_builder_get_object(variables_builder, "variables_entry_search")), &start_pos, &end_pos);
		gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_entry_search")));
		gtk_editable_select_region(GTK_EDITABLE(gtk_builder_get_object(variables_builder, "variables_entry_search")), start_pos, end_pos);
	}
	if(gtk_widget_has_focus(GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_entry_search")))) {
		if(event->keyval == GDK_KEY_Escape) {
			gtk_widget_hide(o);
			return TRUE;
		}
		if(event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_Down || event->keyval == GDK_KEY_Page_Up || event->keyval == GDK_KEY_Page_Down || event->keyval == GDK_KEY_KP_Page_Up || event->keyval == GDK_KEY_KP_Page_Down) {
			gtk_widget_grab_focus(GTK_WIDGET(tVariables));
		}
	}
	return FALSE;
}
gboolean on_functions_dialog_key_press_event(GtkWidget *o, GdkEventKey *event, gpointer) {
	if(gtk_widget_has_focus(GTK_WIDGET(tFunctions)) && gdk_keyval_to_unicode(event->keyval) > 32) {
		gint start_pos = 0, end_pos = 0;
		gtk_editable_get_selection_bounds(GTK_EDITABLE(gtk_builder_get_object(functions_builder, "functions_entry_search")), &start_pos, &end_pos);
		gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(functions_builder, "functions_entry_search")));
		gtk_editable_select_region(GTK_EDITABLE(gtk_builder_get_object(functions_builder, "functions_entry_search")), start_pos, end_pos);
	}
	if(gtk_widget_has_focus(GTK_WIDGET(gtk_builder_get_object(functions_builder, "functions_entry_search")))) {
		if(event->keyval == GDK_KEY_Escape) {
			gtk_widget_hide(o);
			return TRUE;
		}
		if(event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_Down || event->keyval == GDK_KEY_Page_Up || event->keyval == GDK_KEY_Page_Down || event->keyval == GDK_KEY_KP_Page_Up || event->keyval == GDK_KEY_KP_Page_Down) {
			gtk_widget_grab_focus(GTK_WIDGET(tFunctions));
		}
	}
	return FALSE;
}
gboolean on_units_dialog_key_press_event(GtkWidget *o, GdkEventKey *event, gpointer) {
	if(gtk_widget_has_focus(GTK_WIDGET(tUnits)) && gdk_keyval_to_unicode(event->keyval) > 32) {
		gint start_pos = 0, end_pos = 0;
		gtk_editable_get_selection_bounds(GTK_EDITABLE(gtk_builder_get_object(units_builder, "units_entry_search")), &start_pos, &end_pos);
		gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_entry_search")));
		gtk_editable_select_region(GTK_EDITABLE(gtk_builder_get_object(units_builder, "units_entry_search")), start_pos, end_pos);
	}
	if(gtk_widget_has_focus(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_entry_search")))) {
		if(event->keyval == GDK_KEY_Escape) {
			gtk_widget_hide(o);
			return TRUE;
		}
		if(event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_Down || event->keyval == GDK_KEY_Page_Up || event->keyval == GDK_KEY_Page_Down || event->keyval == GDK_KEY_KP_Page_Up || event->keyval == GDK_KEY_KP_Page_Down) {
			gtk_widget_grab_focus(GTK_WIDGET(tUnits));
		}
	}
	return FALSE;
}
gboolean on_units_convert_to_button_focus_out_event(GtkWidget*, GdkEvent*, gpointer) {
	gtk_widget_hide(completion_window);
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(units_builder, "units_convert_to_button")), FALSE);
	return FALSE;
}
gboolean on_units_convert_to_button_key_press_event(GtkWidget*, GdkEventKey *event, gpointer) {
	if(!gtk_widget_get_visible(units_convert_window)) return FALSE;
	switch(event->keyval) {
		case GDK_KEY_Escape: {
			gtk_widget_hide(units_convert_window);
			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(units_builder, "units_convert_to_button")), FALSE);
			return TRUE;
			break;
		}
		case GDK_KEY_KP_Enter: {}
		case GDK_KEY_ISO_Enter: {}
		case GDK_KEY_Return: {
			GtkTreeIter iter;
			if(gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(units_convert_view)), NULL, &iter)) {
				GtkTreePath *path = gtk_tree_model_get_path(units_convert_filter, &iter);
				on_units_convert_view_row_activated(GTK_TREE_VIEW(units_convert_view), path, NULL, NULL);
				gtk_tree_path_free(path);
				return TRUE;
			}
		}
		case GDK_KEY_BackSpace: {}
		case GDK_KEY_Delete: {
			string str = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(units_builder, "units_convert_search")));
			if(str.length() > 0) {
				str = str.substr(0, str.length() - 1);
				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(units_builder, "units_convert_search")), str.c_str());
			}
			return TRUE;
		}
		case GDK_KEY_Down: {}
		case GDK_KEY_End: {}
		case GDK_KEY_Home: {}
		case GDK_KEY_KP_Page_Up: {}
		case GDK_KEY_Page_Up: {}
		case GDK_KEY_KP_Page_Down: {}
		case GDK_KEY_Page_Down: {}
		case GDK_KEY_Up: {
			GtkTreeIter iter;
			GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(units_convert_view));
			bool b = false;
			if(event->keyval == GDK_KEY_Up) {
				if(gtk_tree_selection_get_selected(selection, NULL, &iter)) {
					if(gtk_tree_model_iter_previous(units_convert_filter, &iter)) b = true;
					else gtk_tree_selection_unselect_all(selection);
				} else {
					gint rows = gtk_tree_model_iter_n_children(units_convert_filter, NULL);
					if(rows > 0) {
						GtkTreePath *path = gtk_tree_path_new_from_indices(rows - 1, -1);
						gtk_tree_model_get_iter(units_convert_filter, &iter, path);
						gtk_tree_path_free(path);
						b = true;
					}
				}
			} else if(event->keyval == GDK_KEY_Down) {
				if(gtk_tree_selection_get_selected(selection, NULL, &iter)) {
					if(gtk_tree_model_iter_next(units_convert_filter, &iter)) b = true;
					else gtk_tree_selection_unselect_all(selection);
				} else {
					if(gtk_tree_model_get_iter_first(units_convert_filter, &iter)) b = true;
				}
			} else if(event->keyval == GDK_KEY_End) {
				gint rows = gtk_tree_model_iter_n_children(units_convert_filter, NULL);
				if(rows > 0) {
					GtkTreePath *path = gtk_tree_path_new_from_indices(rows - 1, -1);
					gtk_tree_model_get_iter(units_convert_filter, &iter, path);
					gtk_tree_path_free(path);
					b = true;
				}
			} else if(event->keyval == GDK_KEY_Home) {
				if(gtk_tree_model_get_iter_first(units_convert_filter, &iter)) b = true;
			} else if(event->keyval == GDK_KEY_KP_Page_Down || event->keyval == GDK_KEY_Page_Down) {
				if(gtk_tree_selection_get_selected(selection, NULL, &iter)) {
					b = true;
					for(size_t i = 0; i < 20; i++) {
						if(!gtk_tree_model_iter_next(units_convert_filter, &iter)) {
							b = false;
							gint rows = gtk_tree_model_iter_n_children(units_convert_filter, NULL);
							if(rows > 0) {
								GtkTreePath *path = gtk_tree_path_new_from_indices(rows - 1, -1);
								gtk_tree_model_get_iter(units_convert_filter, &iter, path);
								gtk_tree_path_free(path);
								b = true;
							}
							break;
						}
					}
				}
			} else if(event->keyval == GDK_KEY_KP_Page_Up || event->keyval == GDK_KEY_Page_Up) {
				if(gtk_tree_selection_get_selected(selection, NULL, &iter)) {
					b = true;
					for(size_t i = 0; i < 20; i++) {
						if(!gtk_tree_model_iter_previous(units_convert_filter, &iter)) {
							b = false;
							if(gtk_tree_model_get_iter_first(units_convert_filter, &iter)) b = true;
							break;
						}
					}
				}
			}
			if(b) {
				gtk_tree_view_set_hover_selection(GTK_TREE_VIEW(units_convert_view), FALSE);
				units_convert_hover_blocked = true;
				GtkTreePath *path = gtk_tree_model_get_path(units_convert_filter, &iter);
				gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(units_convert_view), path, NULL, FALSE, 0.0, 0.0);
				gtk_tree_selection_unselect_all(selection);
				gtk_tree_selection_select_iter(selection, &iter);
				gtk_tree_path_free(path);
			}
			return TRUE;
		}
	}
	if(gdk_keyval_to_unicode(event->keyval) > 32) {
		gchar buffer[10];
		buffer[g_unichar_to_utf8(gdk_keyval_to_unicode(event->keyval), buffer)] = '\0';
		string str = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(units_builder, "units_convert_search")));
		str += buffer;
		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(units_builder, "units_convert_search")), str.c_str());
		return TRUE;
	}
	return FALSE;
}

gboolean on_key_press_event(GtkWidget *o, GdkEventKey *event, gpointer) {
	if(gtk_widget_has_focus(expressiontext) || b_editing_stack) return FALSE;
	if(!b_busy && gtk_widget_has_focus(GTK_WIDGET(gtk_builder_get_object(main_builder, "mb_to"))) && !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "mb_to"))) && (event->keyval == GDK_KEY_Return || event->keyval == GDK_KEY_ISO_Enter || event->keyval == GDK_KEY_KP_Enter || event->keyval == GDK_KEY_space)) {update_mb_to_menu(); gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(main_builder, "mb_to")));}
	if(gtk_widget_has_focus(GTK_WIDGET(gtk_builder_get_object(main_builder, "convert_entry_unit")))) return FALSE;
	if(gtk_widget_has_focus(GTK_WIDGET(gtk_builder_get_object(main_builder, "convert_entry_search")))) {
		if(event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_Down || event->keyval == GDK_KEY_Page_Up || event->keyval == GDK_KEY_Page_Down || event->keyval == GDK_KEY_KP_Page_Up || event->keyval == GDK_KEY_KP_Page_Down) {
			gtk_widget_grab_focus(GTK_WIDGET(tUnitSelector));
		}
		return FALSE;
	}
	if(gtk_widget_has_focus(GTK_WIDGET(gtk_builder_get_object(main_builder, "convert_treeview_unit")))) {
		if(!(event->keyval >= GDK_KEY_KP_Multiply && event->keyval <= GDK_KEY_KP_9) && !(event->keyval >= GDK_KEY_parenleft && event->keyval <= GDK_KEY_A)) {
			if(gdk_keyval_to_unicode(event->keyval) > 32) {
				//gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(main_builder, "convert_entry_search")));
				gint start_pos = 0, end_pos = 0;
				gtk_editable_get_selection_bounds(GTK_EDITABLE(gtk_builder_get_object(main_builder, "convert_entry_search")), &start_pos, &end_pos);
				gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(main_builder, "convert_entry_search")));
				gtk_editable_select_region(GTK_EDITABLE(gtk_builder_get_object(main_builder, "convert_entry_search")), start_pos, end_pos);
			}
			return FALSE;
		}
	}
	if(gtk_widget_has_focus(GTK_WIDGET(gtk_builder_get_object(main_builder, "convert_treeview_category")))) {
		if(!(event->keyval >= GDK_KEY_KP_Multiply && event->keyval <= GDK_KEY_KP_9) && !(event->keyval >= GDK_KEY_parenleft && event->keyval <= GDK_KEY_A)) {
			return FALSE;
		}
	}
	if(event->keyval > GDK_KEY_Hyper_R || event->keyval < GDK_KEY_Shift_L) {
		GtkWidget *w = gtk_window_get_focus(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")));
		if(gtk_bindings_activate_event(G_OBJECT(o), event)) return TRUE;
		if(w && gtk_bindings_activate_event(G_OBJECT(w), event)) return TRUE;
		focus_keeping_selection();
	}
	return FALSE;
}

gboolean on_expressiontext_focus_out_event(GtkWidget*, GdkEvent*, gpointer) {
	gtk_widget_hide(completion_window);
	return FALSE;
}
gboolean on_expressiontext_key_press_event(GtkWidget*, GdkEventKey *event, gpointer) {
	if(b_busy) {
		if(event->keyval == GDK_KEY_Escape) {
			if(b_busy_expression) on_abort_calculation(NULL, 0, NULL);
			else if(b_busy_result) on_abort_display(NULL, 0, NULL);
			else if(b_busy_command) on_abort_command(NULL, 0, NULL);
		}
		return TRUE;
	}
	if(rpn_mode && event->state & GDK_CONTROL_MASK) {
		switch(event->keyval) {
			case GDK_KEY_Up: {
				on_button_registerup_clicked(NULL, NULL);
				return TRUE;
			}
			case GDK_KEY_Down: {
				on_button_registerdown_clicked(NULL, NULL);
				return TRUE;
			}
			case GDK_KEY_Right: {
				on_button_registerswap_clicked(NULL, NULL);
				return TRUE;
			}
			case GDK_KEY_Left: {
				on_button_lastx_clicked(NULL, NULL);
				return TRUE;
			}
			case GDK_KEY_Delete: {}
			case GDK_KEY_KP_Delete: {
				if(event->state & GDK_SHIFT_MASK) {
					on_button_clearstack_clicked(NULL, NULL);
				} else {
					on_button_deleteregister_clicked(NULL, NULL);
				}
				return TRUE;
			}
			case GDK_KEY_C: {
				if(event->state & GDK_SHIFT_MASK) {
					on_button_copyregister_clicked(NULL, NULL);
					return TRUE;
				}
				break;
			}
			case GDK_KEY_S: {
				if(event->state & GDK_SHIFT_MASK) {
					on_button_registerswap_clicked(NULL, NULL);
					return TRUE;
				}
				break;
			}
			case GDK_KEY_L: {
				if(event->state & GDK_SHIFT_MASK) {
					on_button_lastx_clicked(NULL, NULL);
					return TRUE;
				}
				break;
			}
			default: {}
		}
	}
	switch(event->keyval) {
		case GDK_KEY_Escape: {
			if(gtk_widget_get_visible(completion_window)) {
				gtk_widget_hide(completion_window);
				return TRUE;
			}
			break;
		}
		case GDK_KEY_KP_Enter: {}
		case GDK_KEY_ISO_Enter: {}
		case GDK_KEY_Return: {
			if(gtk_widget_get_visible(completion_window)) {
				GtkTreeIter iter;
				if(gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(completion_view)), NULL, &iter)) {
					GtkTreePath *path = gtk_tree_model_get_path(completion_sort, &iter);
					on_completion_match_selected(GTK_TREE_VIEW(completion_view), path, NULL, NULL);
					gtk_tree_path_free(path);
					return TRUE;
				}
			}
			execute_expression();
			return TRUE;
		}
		case GDK_KEY_asciicircum: {}
		case GDK_KEY_dead_circumflex: {
			bool input_xor = (caret_as_xor != ((event->state & GDK_CONTROL_MASK) > 0));
			if(rpn_mode && rpn_keys) {
				calculateRPN(input_xor ? OPERATION_BITWISE_XOR : OPERATION_RAISE);
				return TRUE;
			}
			if(!evalops.parse_options.rpn) {
				wrap_expression_selection();
			}
			overwrite_expression_selection(input_xor ? " xor " : "^");
			return TRUE;
		}
		case GDK_KEY_KP_Divide: {
			if(rpn_mode && rpn_keys) {
				calculateRPN(OPERATION_DIVIDE);
				return TRUE;
			}
			if(!evalops.parse_options.rpn) {
				wrap_expression_selection();
			}
			break;
		}
		case GDK_KEY_KP_Multiply: {
			if(event->state & GDK_CONTROL_MASK) {
				if(rpn_mode && rpn_keys) {
					calculateRPN(OPERATION_RAISE);
					return TRUE;
				}
				if(!evalops.parse_options.rpn) {
					wrap_expression_selection();
				}
				overwrite_expression_selection("^");
				return TRUE;
			}
			if(rpn_mode) {
				calculateRPN(OPERATION_MULTIPLY);
				return TRUE;
			}
			if(!evalops.parse_options.rpn) {
				wrap_expression_selection();
			}
			break;
		}
		case GDK_KEY_KP_Add: {
			if(rpn_mode && rpn_keys) {
				calculateRPN(OPERATION_ADD);
				return TRUE;
			}
			if(!evalops.parse_options.rpn) {
				wrap_expression_selection();
			}
			break;
		}
		case GDK_KEY_KP_Subtract: {
			if(rpn_mode && event->state & GDK_CONTROL_MASK) {
				insertButtonFunction(CALCULATOR->getActiveFunction("neg"));
				return TRUE;
			}
			if(rpn_mode && rpn_keys) {
				calculateRPN(OPERATION_SUBTRACT);
				return TRUE;
			}
			if(!evalops.parse_options.rpn) {
				wrap_expression_selection();
			}
			break;
		}
		case GDK_KEY_asterisk: {
			if(event->state & GDK_CONTROL_MASK) {
				if(rpn_mode && rpn_keys) {
					calculateRPN(OPERATION_RAISE);
					return TRUE;
				}
				if(!evalops.parse_options.rpn) {
					wrap_expression_selection();
				}
				overwrite_expression_selection("^");
				return TRUE;
			}
			if(rpn_mode && rpn_keys) {
				calculateRPN(OPERATION_MULTIPLY);
				return TRUE;
			}
		}
		case GDK_KEY_slash: {
			if(rpn_mode && rpn_keys) {
				calculateRPN(OPERATION_DIVIDE);
				return TRUE;
			}
		}
		case GDK_KEY_plus: {
			if(rpn_mode && rpn_keys) {
				calculateRPN(OPERATION_ADD);
				return TRUE;
			}
		}
		case GDK_KEY_minus: {
			if(rpn_mode && event->state & GDK_CONTROL_MASK) {
				insertButtonFunction(CALCULATOR->getActiveFunction("neg"));
				return TRUE;
			}
			if(rpn_mode && rpn_keys) {
				calculateRPN(OPERATION_SUBTRACT);
				return TRUE;
			}
			if(!evalops.parse_options.rpn) {
				wrap_expression_selection();
			}
			break;
		}
		case GDK_KEY_E: {
			if(event->state & GDK_CONTROL_MASK) {
				if(rpn_mode && rpn_keys) {
					calculateRPN(OPERATION_EXP10);
					return TRUE;
				}
				if((!evalops.parse_options.rpn && wrap_expression_selection()) || (evalops.parse_options.base != 10 && evalops.parse_options.base >= 2)) {
					insert_text((expression_times_sign() + i2s(evalops.parse_options.base) + "^").c_str());
				} else {
					if(printops.lower_case_e) insert_text("e");
					else insert_text("E");
				}
				return TRUE;
			}
			break;
		}
		case GDK_KEY_A: {
			if(event->state & GDK_CONTROL_MASK) {
				insert_angle_symbol();
				return TRUE;
			}
			break;
		}
		case GDK_KEY_End: {
			GtkTextIter iend;
			gtk_text_buffer_get_end_iter(expressionbuffer, &iend);
			if(event->state & GDK_SHIFT_MASK) {
				GtkTextIter iselstart, iselend, ipos;
				GtkTextMark *mark = gtk_text_buffer_get_insert(expressionbuffer);
				if(mark) gtk_text_buffer_get_iter_at_mark(expressionbuffer, &ipos, mark);
				if(!gtk_text_buffer_get_selection_bounds(expressionbuffer, &iselstart, &iselend)) gtk_text_buffer_select_range(expressionbuffer, &iend, &ipos);
				else if(gtk_text_iter_equal(&iselstart, &ipos)) gtk_text_buffer_select_range(expressionbuffer, &iend, &iselend);
				else gtk_text_buffer_select_range(expressionbuffer, &iend, &iselstart);
			} else {
				gtk_text_buffer_place_cursor(expressionbuffer, &iend);
			}
			return TRUE;
		}
		case GDK_KEY_Home: {
			GtkTextIter istart;
			gtk_text_buffer_get_start_iter(expressionbuffer, &istart);
			if(event->state & GDK_SHIFT_MASK) {
				GtkTextIter iselstart, iselend, ipos;
				GtkTextMark *mark = gtk_text_buffer_get_insert(expressionbuffer);
				if(mark) gtk_text_buffer_get_iter_at_mark(expressionbuffer, &ipos, mark);
				if(!gtk_text_buffer_get_selection_bounds(expressionbuffer, &iselstart, &iselend)) gtk_text_buffer_select_range(expressionbuffer, &istart, &ipos);
				else if(gtk_text_iter_equal(&iselend, &ipos)) gtk_text_buffer_select_range(expressionbuffer, &istart, &iselstart);
				else gtk_text_buffer_select_range(expressionbuffer, &istart, &iselend);
			} else {
				gtk_text_buffer_place_cursor(expressionbuffer, &istart);
			}
			return TRUE;
		}
		case GDK_KEY_Up: {
			if(gtk_widget_get_visible(completion_window)) {
				GtkTreeIter iter;
				GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(completion_view));
				bool b = false;
				if(gtk_tree_selection_get_selected(selection, NULL, &iter)) {
					if(gtk_tree_model_iter_previous(completion_sort, &iter)) {
						gint i_prio = 0;
						gtk_tree_model_get(GTK_TREE_MODEL(completion_sort), &iter, 4, &i_prio, -1);
						if(i_prio != 3 || gtk_tree_model_iter_previous(completion_sort, &iter)) b = true;
					} else {
						gtk_tree_selection_unselect_all(selection);
					}
				} else {
					gint rows = gtk_tree_model_iter_n_children(completion_sort, NULL);
					if(rows > 0) {
						GtkTreePath *path = gtk_tree_path_new_from_indices(rows - 1, -1);
						gtk_tree_model_get_iter(completion_sort, &iter, path);
						gtk_tree_path_free(path);
						b = true;
					}
				}
				if(b) {
					gtk_tree_view_set_hover_selection(GTK_TREE_VIEW(completion_view), FALSE);
					completion_hover_blocked = true;
					GtkTreePath *path = gtk_tree_model_get_path(completion_sort, &iter);
					gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(completion_view), path, NULL, FALSE, 0.0, 0.0);
					gtk_tree_selection_select_iter(selection, &iter);
					gtk_tree_path_free(path);
				}
				return TRUE;
			}
			GtkTextIter ipos;
			GtkTextMark *mark = gtk_text_buffer_get_insert(expressionbuffer);
			if(mark) {
				gtk_text_buffer_get_iter_at_mark(expressionbuffer, &ipos, mark);
				if(gtk_text_view_backward_display_line(GTK_TEXT_VIEW(expressiontext), &ipos)) break;
			}
		}
		case GDK_KEY_KP_Page_Up: {}
		case GDK_KEY_Page_Up: {
			if(expression_history_index + 1 < (int) expression_history.size()) {
				expression_history_index++;
				dont_change_index = true;
				block_completion();
				set_expression_text(expression_history[expression_history_index].c_str());
				unblock_completion();
				dont_change_index = false;
			}
			return TRUE;
		}
		case GDK_KEY_Down: {
			if(gtk_widget_get_visible(completion_window)) {
				GtkTreeIter iter;
				GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(completion_view));
				bool b = false;
				if(gtk_tree_selection_get_selected(selection, NULL, &iter)) {
					if(gtk_tree_model_iter_next(completion_sort, &iter)) {
						gint i_prio = 0;
						gtk_tree_model_get(GTK_TREE_MODEL(completion_sort), &iter, 4, &i_prio, -1);
						if(i_prio != 3 || gtk_tree_model_iter_next(completion_sort, &iter)) b = true;
					} else {
						gtk_tree_selection_unselect_all(selection);
					}
				} else {
					if(gtk_tree_model_get_iter_first(completion_sort, &iter)) b = true;
				}
				if(b) {
					gtk_tree_view_set_hover_selection(GTK_TREE_VIEW(completion_view), FALSE);
					completion_hover_blocked = true;
					GtkTreePath *path = gtk_tree_model_get_path(completion_sort, &iter);
					gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(completion_view), path, NULL, FALSE, 0.0, 0.0);
					gtk_tree_selection_select_iter(selection, &iter);
					gtk_tree_path_free(path);
				}
				return TRUE;
			}
			GtkTextIter ipos;
			GtkTextMark *mark = gtk_text_buffer_get_insert(expressionbuffer);
			if(mark) {
				gtk_text_buffer_get_iter_at_mark(expressionbuffer, &ipos, mark);
				if(gtk_text_view_forward_display_line(GTK_TEXT_VIEW(expressiontext), &ipos)) break;
			}
		}
		case GDK_KEY_KP_Page_Down: {}
		case GDK_KEY_Page_Down: {
			if(expression_history_index > -1) {
				expression_history_index--;
				dont_change_index = true;
				block_completion();
				if(expression_history_index < 0) {
					clear_expression_text();
				} else {
					set_expression_text(expression_history[expression_history_index].c_str());
				}
				unblock_completion();
				dont_change_index = false;
			}
			return TRUE;
		}
		case GDK_KEY_KP_Separator: {
			overwrite_expression_selection(CALCULATOR->getDecimalPoint().c_str());
			return TRUE;
		}
	}
	if(event->state & GDK_CONTROL_MASK) {
		switch(event->keyval) {
			case GDK_KEY_Z: {
				expression_redo();
				return TRUE;
			}
			case GDK_KEY_z: {
				expression_undo();
				return TRUE;
			}
			case GDK_KEY_parenleft: {}
			case GDK_KEY_parenright: {
				on_button_brace_wrap_clicked(NULL, NULL);
				return TRUE;
			}
		}
	}
	switch(event->keyval) {
		case GDK_KEY_KP_Multiply: {}
		case GDK_KEY_asterisk: {
			overwrite_expression_selection(expression_times_sign());
			return TRUE;
		}
		case GDK_KEY_KP_Divide: {}
		case GDK_KEY_slash: {
			overwrite_expression_selection(expression_divide_sign());
			return TRUE;
		}
		case GDK_KEY_KP_Subtract: {}
		case GDK_KEY_minus: {
			overwrite_expression_selection(expression_sub_sign());
			return TRUE;
		}
		case GDK_KEY_KP_Add: {}
		case GDK_KEY_plus: {
			overwrite_expression_selection(expression_add_sign());
			return TRUE;
		}
		case GDK_KEY_braceleft: {}
		case GDK_KEY_braceright: {
			return TRUE;
		}
	}	
	return FALSE;
}
gboolean on_resultview_draw(GtkWidget *widget, cairo_t *cr, gpointer) {
	if(exit_in_progress) return TRUE;
	gint scalefactor = gtk_widget_get_scale_factor(widget);
	gtk_render_background(gtk_widget_get_style_context(widget), cr, 0, 0, gtk_widget_get_allocated_width(widget), gtk_widget_get_allocated_height(widget));
	if(surface_result) {
		gint w = 0, h = 0;
		if(!first_draw_of_result) {
			if(b_busy) {
				if(b_busy_result) return TRUE;
			} else if(display_aborted || (!displayed_mstruct && result_too_long)) {
				PangoLayout *layout = gtk_widget_create_pango_layout(widget, NULL);
				pango_layout_set_markup(layout, display_aborted ? _("result processing was aborted") : _("result is too long\nsee history"), -1);
				pango_layout_get_pixel_size(layout, &w, &h);
				cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
				cairo_surface_set_device_scale(s, scalefactor, scalefactor);
				cairo_t *cr2 = cairo_create(s);
				GdkRGBA rgba;
				gtk_style_context_get_color(gtk_widget_get_style_context(widget), gtk_widget_get_state_flags(widget), &rgba);
				gdk_cairo_set_source_rgba(cr2, &rgba);
				pango_cairo_show_layout(cr2, layout);
				cairo_destroy(cr2);
				cairo_surface_destroy(surface_result);
				surface_result = s;
				tmp_surface = s;
			} else if(displayed_mstruct) {
				if(displayed_mstruct->isAborted()) {
					PangoLayout *layout = gtk_widget_create_pango_layout(widget, NULL);
					pango_layout_set_markup(layout, _("calculation was aborted"), -1);
					gint w = 0, h = 0;
					pango_layout_get_pixel_size(layout, &w, &h);
					tmp_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
					cairo_surface_set_device_scale(tmp_surface, scalefactor, scalefactor);
					cairo_t *cr2 = cairo_create(tmp_surface);
					GdkRGBA rgba;
					gtk_style_context_get_color(gtk_widget_get_style_context(widget), gtk_widget_get_state_flags(widget), &rgba);
					gdk_cairo_set_source_rgba(cr2, &rgba);
					pango_cairo_show_layout(cr2, layout);
					cairo_destroy(cr2);
					g_object_unref(layout);
				} else {
					tmp_surface = draw_structure(*displayed_mstruct, displayed_printops, displayed_caf, top_ips, NULL, scale_n);
				}
				surface_result = tmp_surface;
			}
		}
		w = cairo_image_surface_get_width(surface_result) / scalefactor;
		h = cairo_image_surface_get_height(surface_result) / scalefactor;
		gint sbw, sbh;
		gtk_widget_get_preferred_width(gtk_scrolled_window_get_vscrollbar(GTK_SCROLLED_WINDOW(gtk_builder_get_object(main_builder, "scrolled_result"))), NULL, &sbw);
		gtk_widget_get_preferred_height(gtk_scrolled_window_get_hscrollbar(GTK_SCROLLED_WINDOW(gtk_builder_get_object(main_builder, "scrolled_result"))), NULL, &sbh);
		gint rh = gtk_widget_get_allocated_height(GTK_WIDGET(gtk_builder_get_object(main_builder, "scrolled_result")));
		gint rw = gtk_widget_get_allocated_width(GTK_WIDGET(gtk_builder_get_object(main_builder, "scrolled_result")));
		if(first_draw_of_result || (!b_busy && result_font_updated)) {
			while(displayed_mstruct && !display_aborted && scale_n < 3 && (w > rw || h > (w > rw - sbw ? rh - sbh : rh))) {
				int scroll_diff = gtk_widget_get_allocated_height(GTK_WIDGET(gtk_builder_get_object(main_builder, "scrolled_result"))) - gtk_widget_get_allocated_height(GTK_WIDGET(gtk_builder_get_object(main_builder, "resultport")));
				double scale_div = (double) h / (gtk_widget_get_allocated_height(GTK_WIDGET(gtk_builder_get_object(main_builder, "resultport"))) + scroll_diff);
				if(scale_div > 1.44) {
					scale_n = 3;
				} else if(scale_n < 2 && scale_div > 1.2) {
					scale_n = 2;
				} else {
					scale_n++;
				}
				cairo_surface_destroy(surface_result);
				surface_result = draw_structure(*displayed_mstruct, displayed_printops, displayed_caf, top_ips, NULL, scale_n);
				w = cairo_image_surface_get_width(surface_result) / scalefactor;
				h = cairo_image_surface_get_height(surface_result) / scalefactor;
			}
			result_font_updated = FALSE;
		}
		gtk_widget_set_size_request(widget, w, h);
		if(h > sbh) rw -= sbw;
		if(rw >= w) {
			cairo_set_source_surface(cr, surface_result, rw >= w ? rw - w : rw - w - (rw - w) / 2, h < rh ? (rh - h) / 2 : 0);
		} else {
			if(h + ((rh - h) / 2) < rh - sbh) cairo_set_source_surface(cr, surface_result, 0, (rh - h) / 2);
			else cairo_set_source_surface(cr, surface_result, 0, (h > rh - sbh) ? 0 : (rh - h - sbh) / 2);
		}
		cairo_paint(cr);
		first_draw_of_result = FALSE;
	} else if(showing_first_time_message) {
		PangoLayout *layout = gtk_widget_create_pango_layout(GTK_WIDGET(gtk_builder_get_object(main_builder, "resultview")), NULL);
		GdkRGBA rgba;
		pango_layout_set_markup(layout, _("<span font=\"10\">Type a mathematical expression above, e.g. \"5 + 2 / 3\",\nand press the enter key.</span>"), -1);
		gtk_style_context_get_color(gtk_widget_get_style_context(GTK_WIDGET(gtk_builder_get_object(main_builder, "resultview"))), gtk_widget_get_state_flags(GTK_WIDGET(gtk_builder_get_object(main_builder, "resultview"))), &rgba);
		cairo_move_to(cr, 6, 0);
		gdk_cairo_set_source_rgba(cr, &rgba);
		pango_cairo_show_layout(cr, layout);
		g_object_unref(layout);
	}
	return TRUE;
}
void on_matrix_edit_radiobutton_matrix_toggled(GtkToggleButton *w, gpointer) {
	if(gtk_toggle_button_get_active(w)) {
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(matrixedit_builder, "matrix_edit_label_elements")), _("Elements"));
	} else {
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(matrixedit_builder, "matrix_edit_label_elements")), _("Elements (in horizontal order)"));
	}
	on_tMatrixEdit_cursor_changed(GTK_TREE_VIEW(tMatrixEdit), NULL);
}
void on_matrix_edit_radiobutton_vector_toggled(GtkToggleButton *w, gpointer) {
	if(!gtk_toggle_button_get_active(w)) {
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(matrixedit_builder, "matrix_edit_label_elements")), _("Elements"));
	} else {
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(matrixedit_builder, "matrix_edit_label_elements")), _("Elements (in horizontal order)"));
	}
	on_tMatrixEdit_cursor_changed(GTK_TREE_VIEW(tMatrixEdit), NULL);
}
void on_matrix_radiobutton_matrix_toggled(GtkToggleButton *w, gpointer) {
	if(gtk_toggle_button_get_active(w)) {
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(matrix_builder, "matrix_label_elements")), _("Elements"));
	} else {
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(matrix_builder, "matrix_label_elements")), _("Elements (in horizontal order)"));
	}
	on_tMatrix_cursor_changed(GTK_TREE_VIEW(tMatrix), NULL);
}
void on_matrix_radiobutton_vector_toggled(GtkToggleButton *w, gpointer) {
	if(!gtk_toggle_button_get_active(w)) {
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(matrix_builder, "matrix_label_elements")), _("Elements"));
	} else {
		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(matrix_builder, "matrix_label_elements")), _("Elements (in horizontal order)"));
	}
	on_tMatrix_cursor_changed(GTK_TREE_VIEW(tMatrix), NULL);
}

void on_csv_import_radiobutton_matrix_toggled(GtkToggleButton*, gpointer) {
}
void on_csv_import_radiobutton_vectors_toggled(GtkToggleButton*, gpointer) {
}
void on_csv_import_combobox_delimiter_changed(GtkComboBox *w, gpointer) {
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(csvimport_builder, "csv_import_entry_delimiter_other")), gtk_combo_box_get_active(w) == DELIMITER_OTHER);
}
void on_csv_import_button_file_clicked(GtkButton*, gpointer) {
	GtkWidget *d = gtk_file_chooser_dialog_new(_("Select file to import"), GTK_WINDOW(gtk_builder_get_object(csvimport_builder, "csv_import_dialog")), GTK_FILE_CHOOSER_ACTION_OPEN, _("_Cancel"), GTK_RESPONSE_CANCEL, _("_Open"), GTK_RESPONSE_ACCEPT, NULL);
	string filestr = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(csvimport_builder, "csv_import_entry_file")));
	remove_blank_ends(filestr);
	if(!filestr.empty()) gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(d), filestr.c_str());
	if(gtk_dialog_run(GTK_DIALOG(d)) == GTK_RESPONSE_ACCEPT) {
		const gchar *file_str = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(d));
		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(csvimport_builder, "csv_import_entry_file")), file_str);
		string name_str = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(csvimport_builder, "csv_import_entry_name")));
		remove_blank_ends(name_str);
		if(name_str.empty()) {
			name_str = file_str;
			size_t i = name_str.find_last_of("/");
			if(i != string::npos) name_str = name_str.substr(i + 1, name_str.length() - i);
			i = name_str.find_last_of(".");
			if(i != string::npos) name_str = name_str.substr(0, i);
			gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(csvimport_builder, "csv_import_entry_name")), name_str.c_str());
		}
	}
	gtk_widget_destroy(d);
}

void on_csv_export_combobox_delimiter_changed(GtkComboBox *w, gpointer) {
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(csvexport_builder, "csv_export_entry_delimiter_other")), gtk_combo_box_get_active(w) == DELIMITER_OTHER);
}
void on_csv_export_button_file_clicked(GtkButton*, gpointer) {
	GtkWidget *d = gtk_file_chooser_dialog_new(_("Select file to export to"), GTK_WINDOW(gtk_builder_get_object(csvexport_builder, "csv_export_dialog")), GTK_FILE_CHOOSER_ACTION_SAVE, _("_Cancel"), GTK_RESPONSE_CANCEL, _("_Open"), GTK_RESPONSE_ACCEPT, NULL);
	string filestr = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(csvexport_builder, "csv_export_entry_file")));
	remove_blank_ends(filestr);
	if(!filestr.empty()) gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(d), filestr.c_str());
	if(gtk_dialog_run(GTK_DIALOG(d)) == GTK_RESPONSE_ACCEPT) {
		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(csvexport_builder, "csv_export_entry_file")), gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(d)));
	}
	gtk_widget_destroy(d);
}
void on_csv_export_radiobutton_current_toggled(GtkToggleButton *w, gpointer) {
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(csvexport_builder, "csv_export_entry_matrix")), !gtk_toggle_button_get_active(w));
}
void on_csv_export_radiobutton_matrix_toggled(GtkToggleButton *w, gpointer) {
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(csvexport_builder, "csv_export_entry_matrix")), gtk_toggle_button_get_active(w));
}

void on_type_label_date_clicked(GtkButton *w, gpointer user_data) {
	GtkWidget *d = gtk_dialog_new_with_buttons(_("Select date"), GTK_WINDOW(gtk_widget_get_ancestor(GTK_WIDGET(w), GTK_TYPE_WINDOW)), (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT), _("_OK"), GTK_RESPONSE_OK, _("_Cancel"), GTK_RESPONSE_CANCEL, NULL);
	GtkWidget *date_w = gtk_calendar_new();
	gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(d))), date_w);
	gtk_widget_show_all(d);
	if(gtk_dialog_run(GTK_DIALOG(d)) == GTK_RESPONSE_OK) {
		guint year = 0, month = 0, day = 0;
		gtk_calendar_get_date(GTK_CALENDAR(date_w), &year, &month, &day);
		gchar *gstr = g_strdup_printf("%i-%02i-%02i", year, month + 1, day);
		gtk_entry_set_text(GTK_ENTRY(user_data), gstr);
		g_free(gstr);
	}
	gtk_widget_destroy(d);
}
void on_type_label_file_clicked(GtkButton*, gpointer user_data) {
	GtkWidget *d = gtk_file_chooser_dialog_new(_("Select file to import"), GTK_WINDOW(gtk_builder_get_object(csvimport_builder, "csv_import_dialog")), GTK_FILE_CHOOSER_ACTION_OPEN, _("_Cancel"), GTK_RESPONSE_CANCEL, _("_Open"), GTK_RESPONSE_ACCEPT, NULL);
	string filestr = gtk_entry_get_text(GTK_ENTRY(user_data));
	remove_blank_ends(filestr);
	if(!filestr.empty()) gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(d), filestr.c_str());
	gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(d), filestr.c_str());
	if(gtk_dialog_run(GTK_DIALOG(d)) == GTK_RESPONSE_ACCEPT) {
		gtk_entry_set_text(GTK_ENTRY(user_data), gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(d)));
	}
	gtk_widget_destroy(d);
}

void on_functions_button_deactivate_clicked(GtkButton*, gpointer) {
	MathFunction *f = get_selected_function();
	if(f) {
		f->setActive(!f->isActive());
		update_fmenu();
	}
}
void on_variables_button_deactivate_clicked(GtkButton*, gpointer) {
	Variable *v = get_selected_variable();
	if(v) {
		v->setActive(!v->isActive());
		update_vmenu();
	}
}
void on_units_button_deactivate_clicked(GtkButton*, gpointer) {
	Unit *u = get_selected_unit();
	if(u) {
		u->setActive(!u->isActive());
		update_umenus();
	}
}

void on_function_edit_button_subfunctions_clicked(GtkButton*, gpointer) {
	gtk_window_set_transient_for(GTK_WINDOW(gtk_builder_get_object(functionedit_builder, "function_edit_dialog_subfunctions")), GTK_WINDOW(gtk_builder_get_object(functionedit_builder, "function_edit_dialog")));
	gtk_dialog_run(GTK_DIALOG(gtk_builder_get_object(functionedit_builder, "function_edit_dialog_subfunctions")));
	gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_dialog_subfunctions")));
}
void on_function_edit_button_add_subfunction_clicked(GtkButton*, gpointer) {
	GtkTreeIter iter;	
	gtk_list_store_append(tSubfunctions_store, &iter);
	string str = "\\";
	last_subfunction_index++;
	str += i2s(last_subfunction_index);
	if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(functionedit_builder, "function_edit_checkbutton_precalculate")))) {
		gtk_list_store_set(tSubfunctions_store, &iter, 0, str.c_str(), 1, gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(functionedit_builder, "function_edit_entry_subexpression"))), 2, _("Yes"), 3, last_subfunction_index, 4, TRUE, -1);
	} else {
		gtk_list_store_set(tSubfunctions_store, &iter, 0, str.c_str(), 1, gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(functionedit_builder, "function_edit_entry_subexpression"))), 2, _("No"), 3, last_subfunction_index, 4, FALSE, -1);
	}
	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(functionedit_builder, "function_edit_entry_subexpression")), "");
	on_function_changed();
}
void on_function_edit_button_modify_subfunction_clicked(GtkButton*, gpointer) {
	GtkTreeModel *model;
	GtkTreeIter iter;
	if(gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(tSubfunctions)), &model, &iter)) {
		if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(functionedit_builder, "function_edit_checkbutton_precalculate")))) {
			gtk_list_store_set(tSubfunctions_store, &iter, 1, gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(functionedit_builder, "function_edit_entry_subexpression"))), 2, _("Yes"), 4, TRUE, -1);
		} else {
			gtk_list_store_set(tSubfunctions_store, &iter, 1, gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(functionedit_builder, "function_edit_entry_subexpression"))), 2, _("No"), 4, FALSE, -1);
		}
		on_function_changed();
	}
}
void on_function_edit_button_remove_subfunction_clicked(GtkButton*, gpointer) {
	GtkTreeModel *model;
	GtkTreeIter iter;
	if(gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(tSubfunctions)), &model, &iter)) {
		GtkTreeIter iter2 = iter;
		while(gtk_tree_model_iter_next(GTK_TREE_MODEL(tSubfunctions_store), &iter2)) {
			guint index;
			gtk_tree_model_get(GTK_TREE_MODEL(tSubfunctions_store), &iter2, 3, &index, -1);
			index--;
			string str = "\\";
			str += i2s(index);
			gtk_list_store_set(tSubfunctions_store, &iter2, 0, str.c_str(), 3, index, -1);
		}
		gtk_list_store_remove(tSubfunctions_store, &iter);
		last_subfunction_index--;
		on_function_changed();
	}
}
void on_function_edit_entry_subexpression_activate(GtkEntry*, gpointer) {
	if(gtk_widget_get_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_button_add_subfunction")))) {
		on_function_edit_button_add_subfunction_clicked(GTK_BUTTON(gtk_builder_get_object(functionedit_builder, "function_edit_button_add_subfunction")), NULL);
	} else if(gtk_widget_get_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_button_modify_subfunction")))) {
		on_function_edit_button_modify_subfunction_clicked(GTK_BUTTON(gtk_builder_get_object(functionedit_builder, "function_edit_button_modify_subfunction")), NULL);
	}
}
void on_function_edit_button_add_argument_clicked(GtkButton*, gpointer) {
	GtkTreeIter iter;	
	gtk_list_store_append(tFunctionArguments_store, &iter);
	Argument *arg;
	if(edited_function && edited_function->isBuiltin()) {
		arg = new Argument();
	} else {
		int menu_index = gtk_combo_box_get_active(GTK_COMBO_BOX(gtk_builder_get_object(functionedit_builder, "function_edit_combobox_argument_type")));
		switch(menu_index) {
			case MENU_ARGUMENT_TYPE_TEXT: {arg = new TextArgument(); break;}
			case MENU_ARGUMENT_TYPE_SYMBOLIC: {arg = new SymbolicArgument(); break;}
			case MENU_ARGUMENT_TYPE_DATE: {arg = new DateArgument(); break;}
			case MENU_ARGUMENT_TYPE_NONNEGATIVE_INTEGER: {arg = new IntegerArgument("", ARGUMENT_MIN_MAX_NONNEGATIVE); break;}
			case MENU_ARGUMENT_TYPE_POSITIVE_INTEGER: {arg = new IntegerArgument("", ARGUMENT_MIN_MAX_POSITIVE); break;}
			case MENU_ARGUMENT_TYPE_NONZERO_INTEGER: {arg = new IntegerArgument("", ARGUMENT_MIN_MAX_NONZERO); break;}
			case MENU_ARGUMENT_TYPE_INTEGER: {arg = new IntegerArgument(); break;}
			case MENU_ARGUMENT_TYPE_NONNEGATIVE: {arg = new NumberArgument("", ARGUMENT_MIN_MAX_NONNEGATIVE); break;}
			case MENU_ARGUMENT_TYPE_POSITIVE: {arg = new NumberArgument("", ARGUMENT_MIN_MAX_POSITIVE); break;}
			case MENU_ARGUMENT_TYPE_NONZERO: {arg = new NumberArgument("", ARGUMENT_MIN_MAX_NONZERO); break;}
			case MENU_ARGUMENT_TYPE_NUMBER: {arg = new NumberArgument(); break;}
			case MENU_ARGUMENT_TYPE_VECTOR: {arg = new VectorArgument(); break;}
			case MENU_ARGUMENT_TYPE_MATRIX: {arg = new MatrixArgument(); break;}
			case MENU_ARGUMENT_TYPE_EXPRESSION_ITEM: {arg = new ExpressionItemArgument(); break;}
			case MENU_ARGUMENT_TYPE_FUNCTION: {arg = new FunctionArgument(); break;}
			case MENU_ARGUMENT_TYPE_UNIT: {arg = new UnitArgument(); break;}
			case MENU_ARGUMENT_TYPE_VARIABLE: {arg = new VariableArgument(); break;}
			case MENU_ARGUMENT_TYPE_FILE: {arg = new FileArgument(); break;}
			case MENU_ARGUMENT_TYPE_BOOLEAN: {arg = new BooleanArgument(); break;}	
			case MENU_ARGUMENT_TYPE_ANGLE: {arg = new AngleArgument(); break;}	
			case MENU_ARGUMENT_TYPE_DATA_OBJECT: {arg = new DataObjectArgument(NULL, ""); break;}
			case MENU_ARGUMENT_TYPE_DATA_PROPERTY: {arg = new DataPropertyArgument(NULL, ""); break;}
			default: {arg = new Argument();}
		}
	}
	arg->setName(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(functionedit_builder, "function_edit_entry_argument_name"))));		
	gtk_list_store_set(tFunctionArguments_store, &iter, 0, arg->name().c_str(), 1, arg->printlong().c_str(), 2, arg, -1);
	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(functionedit_builder, "function_edit_entry_argument_name")), "");
	on_function_changed();
}
void on_function_edit_button_remove_argument_clicked(GtkButton*, gpointer) {
	GtkTreeModel *model;
	GtkTreeIter iter;
	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tFunctionArguments));
	if(gtk_tree_selection_get_selected(select, &model, &iter)) {
		if(selected_argument) {
			delete selected_argument;
			selected_argument = NULL;
		}
		gtk_list_store_remove(tFunctionArguments_store, &iter);
		on_function_changed();
	}
	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(functionedit_builder, "function_edit_entry_argument_name")), "");
}
void on_function_edit_button_modify_argument_clicked(GtkButton*, gpointer) {
	GtkTreeModel *model;
	GtkTreeIter iter;
	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tFunctionArguments));
	if(gtk_tree_selection_get_selected(select, &model, &iter)) {	
		int argtype = ARGUMENT_TYPE_FREE;
		if(edited_function && edited_function->isBuiltin()) {
			if(!selected_argument) {
				selected_argument = new Argument();
			}
		} else {
			int menu_index = gtk_combo_box_get_active(GTK_COMBO_BOX(gtk_builder_get_object(functionedit_builder, "function_edit_combobox_argument_type")));
			switch(menu_index) {
				case MENU_ARGUMENT_TYPE_TEXT: {argtype = ARGUMENT_TYPE_TEXT; break;}
				case MENU_ARGUMENT_TYPE_SYMBOLIC: {argtype = ARGUMENT_TYPE_SYMBOLIC; break;}
				case MENU_ARGUMENT_TYPE_DATE: {argtype = ARGUMENT_TYPE_DATE; break;}
				case MENU_ARGUMENT_TYPE_NONNEGATIVE_INTEGER: {}
				case MENU_ARGUMENT_TYPE_POSITIVE_INTEGER: {}
				case MENU_ARGUMENT_TYPE_NONZERO_INTEGER: {}
				case MENU_ARGUMENT_TYPE_INTEGER: {argtype = ARGUMENT_TYPE_INTEGER; break;}
				case MENU_ARGUMENT_TYPE_NONNEGATIVE: {}
				case MENU_ARGUMENT_TYPE_POSITIVE: {}
				case MENU_ARGUMENT_TYPE_NONZERO: {}
				case MENU_ARGUMENT_TYPE_NUMBER: {argtype = ARGUMENT_TYPE_NUMBER; break;}
				case MENU_ARGUMENT_TYPE_VECTOR: {argtype = ARGUMENT_TYPE_VECTOR; break;}
				case MENU_ARGUMENT_TYPE_MATRIX: {argtype = ARGUMENT_TYPE_MATRIX; break;}
				case MENU_ARGUMENT_TYPE_EXPRESSION_ITEM: {argtype = ARGUMENT_TYPE_EXPRESSION_ITEM; break;}
				case MENU_ARGUMENT_TYPE_FUNCTION: {argtype = ARGUMENT_TYPE_FUNCTION; break;}
				case MENU_ARGUMENT_TYPE_UNIT: {argtype = ARGUMENT_TYPE_UNIT; break;}
				case MENU_ARGUMENT_TYPE_VARIABLE: {argtype = ARGUMENT_TYPE_VARIABLE; break;}
				case MENU_ARGUMENT_TYPE_FILE: {argtype = ARGUMENT_TYPE_FILE; break;}
				case MENU_ARGUMENT_TYPE_BOOLEAN: {argtype = ARGUMENT_TYPE_BOOLEAN; break;}	
				case MENU_ARGUMENT_TYPE_ANGLE: {argtype = ARGUMENT_TYPE_ANGLE; break;}	
				case MENU_ARGUMENT_TYPE_DATA_OBJECT: {argtype = ARGUMENT_TYPE_DATA_OBJECT; break;}
				case MENU_ARGUMENT_TYPE_DATA_PROPERTY: {argtype = ARGUMENT_TYPE_DATA_PROPERTY; break;}	
			}			
			
			if(!selected_argument || argtype != selected_argument->type() || menu_index == MENU_ARGUMENT_TYPE_NONNEGATIVE_INTEGER || menu_index == MENU_ARGUMENT_TYPE_POSITIVE_INTEGER || menu_index == MENU_ARGUMENT_TYPE_NONZERO_INTEGER || menu_index == MENU_ARGUMENT_TYPE_NONZERO || menu_index == MENU_ARGUMENT_TYPE_POSITIVE || menu_index == MENU_ARGUMENT_TYPE_NONNEGATIVE) {
				if(selected_argument) {
					delete selected_argument;
				}
				switch(menu_index) {
					case MENU_ARGUMENT_TYPE_TEXT: {selected_argument = new TextArgument(); break;}
					case MENU_ARGUMENT_TYPE_SYMBOLIC: {selected_argument = new SymbolicArgument(); break;}
					case MENU_ARGUMENT_TYPE_DATE: {selected_argument = new DateArgument(); break;}
					case MENU_ARGUMENT_TYPE_NONNEGATIVE_INTEGER: {selected_argument = new IntegerArgument("", ARGUMENT_MIN_MAX_NONNEGATIVE); break;}
					case MENU_ARGUMENT_TYPE_POSITIVE_INTEGER: {selected_argument = new IntegerArgument("", ARGUMENT_MIN_MAX_POSITIVE); break;}
					case MENU_ARGUMENT_TYPE_NONZERO_INTEGER: {selected_argument = new IntegerArgument("", ARGUMENT_MIN_MAX_NONZERO); break;}
					case MENU_ARGUMENT_TYPE_INTEGER: {selected_argument = new IntegerArgument(); break;}
					case MENU_ARGUMENT_TYPE_NONNEGATIVE: {selected_argument = new NumberArgument("", ARGUMENT_MIN_MAX_NONNEGATIVE); break;}
					case MENU_ARGUMENT_TYPE_POSITIVE: {selected_argument = new NumberArgument("", ARGUMENT_MIN_MAX_POSITIVE); break;}
					case MENU_ARGUMENT_TYPE_NONZERO: {selected_argument = new NumberArgument("", ARGUMENT_MIN_MAX_NONZERO); break;}
					case MENU_ARGUMENT_TYPE_NUMBER: {selected_argument = new NumberArgument(); break;}
					case MENU_ARGUMENT_TYPE_VECTOR: {selected_argument = new VectorArgument(); break;}
					case MENU_ARGUMENT_TYPE_MATRIX: {selected_argument = new MatrixArgument(); break;}
					case MENU_ARGUMENT_TYPE_EXPRESSION_ITEM: {selected_argument = new ExpressionItemArgument(); break;}
					case MENU_ARGUMENT_TYPE_FUNCTION: {selected_argument = new FunctionArgument(); break;}
					case MENU_ARGUMENT_TYPE_UNIT: {selected_argument = new UnitArgument(); break;}
					case MENU_ARGUMENT_TYPE_VARIABLE: {selected_argument = new VariableArgument(); break;}
					case MENU_ARGUMENT_TYPE_FILE: {selected_argument = new FileArgument(); break;}
					case MENU_ARGUMENT_TYPE_BOOLEAN: {selected_argument = new BooleanArgument(); break;}	
					case MENU_ARGUMENT_TYPE_ANGLE: {selected_argument = new AngleArgument(); break;}
					case MENU_ARGUMENT_TYPE_DATA_OBJECT: {selected_argument = new DataObjectArgument(NULL, ""); break;}
					case MENU_ARGUMENT_TYPE_DATA_PROPERTY: {selected_argument = new DataPropertyArgument(NULL, ""); break;}
					default: {selected_argument = new Argument();}
				}			
			}
			
		}
		selected_argument->setName(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(functionedit_builder, "function_edit_entry_argument_name"))));
		gtk_list_store_set(tFunctionArguments_store, &iter, 0, selected_argument->name().c_str(), 1, selected_argument->printlong().c_str(), 2, (gpointer) selected_argument, -1);
		on_function_changed();
	}
}
void on_function_edit_entry_argument_name_activate(GtkEntry*, gpointer) {
	if(gtk_widget_get_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_button_add_argument")))) {
		on_function_edit_button_add_argument_clicked(GTK_BUTTON(gtk_builder_get_object(functionedit_builder, "function_edit_button_add_argument")), NULL);
	} else if(gtk_widget_get_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_button_modify_argument")))) {
		on_function_edit_button_modify_argument_clicked(GTK_BUTTON(gtk_builder_get_object(functionedit_builder, "function_edit_button_modify_argument")), NULL);
	}
}
void on_function_edit_button_rules_clicked(GtkButton*, gpointer) {
	if(edit_argument(get_selected_argument())) on_function_changed();
}
void on_argument_rules_checkbutton_enable_min_toggled(GtkToggleButton *w, gpointer) {
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(argumentrules_builder, "argument_rules_spinbutton_min")), gtk_toggle_button_get_active(w));
}
void on_argument_rules_checkbutton_enable_max_toggled(GtkToggleButton *w, gpointer) {
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(argumentrules_builder, "argument_rules_spinbutton_max")), gtk_toggle_button_get_active(w));
}
void on_argument_rules_checkbutton_enable_condition_toggled(GtkToggleButton *w, gpointer) {
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(argumentrules_builder, "argument_rules_entry_condition")), gtk_toggle_button_get_active(w));
}
#define SET_NAMES_LE(x,y,z)	GtkTreeIter iter;\
				string str;\
				if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tNames_store), &iter)) {\
					gchar *gstr;\
					gtk_tree_model_get(GTK_TREE_MODEL(tNames_store), &iter, NAMES_NAME_COLUMN, &gstr, -1);\
					if(strlen(gstr) > 0) {\
						gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(x, y)), gstr);\
					}\
					g_free(gstr);\
					if(gtk_tree_model_iter_next(GTK_TREE_MODEL(tNames_store), &iter)) {\
						str += "+ ";\
						while(true) {\
							gtk_tree_model_get(GTK_TREE_MODEL(tNames_store), &iter, NAMES_NAME_COLUMN, &gstr, -1);\
							str += gstr;\
							g_free(gstr);\
							if(!gtk_tree_model_iter_next(GTK_TREE_MODEL(tNames_store), &iter)) break;\
							str += ", ";\
						}\
					}\
				}\
				gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(x, z)), str.c_str());
				
void on_variable_edit_button_names_clicked(GtkButton*, gpointer) {
	edit_names(get_edited_variable(), gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(variableedit_builder, "variable_edit_entry_name"))), GTK_WIDGET(gtk_builder_get_object(variableedit_builder, "variable_edit_dialog")));
	SET_NAMES_LE(variableedit_builder, "variable_edit_entry_name", "variable_edit_label_names")
}
void on_unknown_edit_button_names_clicked(GtkButton*, gpointer) {
	edit_names(get_edited_unknown(), gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(unknownedit_builder, "unknown_edit_entry_name"))), GTK_WIDGET(gtk_builder_get_object(unknownedit_builder, "unknown_edit_dialog")));
	SET_NAMES_LE(unknownedit_builder, "unknown_edit_entry_name", "unknown_edit_label_names")
}
void on_matrix_edit_button_names_clicked(GtkButton*, gpointer) {
	edit_names(get_edited_matrix(), gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(matrixedit_builder, "matrix_edit_entry_name"))), GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_dialog")));
	SET_NAMES_LE(matrixedit_builder, "matrix_edit_entry_name", "matrix_edit_label_names")
}
void on_function_edit_button_names_clicked(GtkButton*, gpointer) {
	edit_names(get_edited_function(), gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(functionedit_builder, "function_edit_entry_name"))), GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_dialog")));
	SET_NAMES_LE(functionedit_builder, "function_edit_entry_name", "function_edit_label_names")
}
void on_unit_edit_button_names_clicked(GtkButton*, gpointer) {
	edit_names(get_edited_unit(), gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_name"))), GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_dialog")));
	SET_NAMES_LE(unitedit_builder, "unit_edit_entry_name", "unit_edit_label_names")
}

void on_names_edit_checkbutton_abbreviation_toggled(GtkToggleButton *w, gpointer) {
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_case_sensitive")), gtk_toggle_button_get_active(w));
}
void on_names_edit_button_add_clicked(GtkButton*, gpointer) {
	if(strlen(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(namesedit_builder, "names_edit_entry_name")))) == 0) {
		gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(namesedit_builder, "names_edit_entry_name")));
		show_message(_("Empty name field."), GTK_WIDGET(gtk_builder_get_object(namesedit_builder, "names_edit_dialog")));
		return;
	}
	bool name_taken = false;
	if(editing_variable && CALCULATOR->variableNameTaken(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(namesedit_builder, "names_edit_entry_name"))), get_edited_variable())) name_taken = true;
	else if(editing_unknown && CALCULATOR->variableNameTaken(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(namesedit_builder, "names_edit_entry_name"))), get_edited_unknown())) name_taken = true;
	else if(editing_matrix && CALCULATOR->variableNameTaken(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(namesedit_builder, "names_edit_entry_name"))), get_edited_matrix())) name_taken = true;
	else if(editing_unit && CALCULATOR->unitNameTaken(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(namesedit_builder, "names_edit_entry_name"))), get_edited_unit())) name_taken = true;
	else if(editing_function && CALCULATOR->functionNameTaken(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(namesedit_builder, "names_edit_entry_name"))), get_edited_function())) name_taken = true;
	else if(editing_dataset && CALCULATOR->functionNameTaken(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(namesedit_builder, "names_edit_entry_name"))), get_edited_dataset())) name_taken = true;
	if(name_taken) {
		if(!ask_question(_("A conflicting object with the same name exists. If you proceed and save changes, the conflicting object will be overwritten or deactivated.\nDo you want to proceed?"), GTK_WIDGET(gtk_builder_get_object(namesedit_builder, "names_edit_dialog")))) {
			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(namesedit_builder, "names_edit_entry_name")));
			return;
		}
	}
	GtkTreeIter iter;
	gtk_list_store_append(tNames_store, &iter);
	if(editing_dataproperty) gtk_list_store_set(tNames_store, &iter, NAMES_NAME_COLUMN, gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(namesedit_builder, "names_edit_entry_name"))), NAMES_ABBREVIATION_STRING_COLUMN, "-", NAMES_PLURAL_STRING_COLUMN, "-", NAMES_REFERENCE_STRING_COLUMN, b2yn(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_reference")))), NAMES_ABBREVIATION_COLUMN, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_abbreviation"))), NAMES_PLURAL_COLUMN, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_plural"))), NAMES_UNICODE_COLUMN, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_unicode"))), NAMES_REFERENCE_COLUMN, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_reference"))), NAMES_SUFFIX_COLUMN, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_suffix"))), NAMES_AVOID_INPUT_COLUMN, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_avoid_input"))), NAMES_COMPLETION_ONLY_COLUMN, 
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_completion_only"))), NAMES_CASE_SENSITIVE_COLUMN, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_case_sensitive"))), -1);
	else gtk_list_store_set(tNames_store, &iter, NAMES_NAME_COLUMN, gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(namesedit_builder, "names_edit_entry_name"))), NAMES_ABBREVIATION_STRING_COLUMN, b2yn(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_abbreviation")))), NAMES_PLURAL_STRING_COLUMN, b2yn(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_plural")))), NAMES_REFERENCE_STRING_COLUMN, b2yn(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_reference")))), NAMES_ABBREVIATION_COLUMN, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_abbreviation"))), NAMES_PLURAL_COLUMN, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_plural"))), NAMES_UNICODE_COLUMN, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_unicode"))), NAMES_REFERENCE_COLUMN, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_reference"))), NAMES_SUFFIX_COLUMN, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_suffix"))), NAMES_AVOID_INPUT_COLUMN, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_avoid_input"))), NAMES_COMPLETION_ONLY_COLUMN, 
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_completion_only"))), NAMES_CASE_SENSITIVE_COLUMN, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_case_sensitive"))), -1);
	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(namesedit_builder, "names_edit_entry_name")), "");
	on_name_changed();
}
void on_names_edit_button_modify_clicked(GtkButton*, gpointer) {
	GtkTreeModel *model;
	GtkTreeIter iter;
	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tNames));
	if(gtk_tree_selection_get_selected(select, &model, &iter)) {
		char *gstr;
		gtk_tree_model_get(GTK_TREE_MODEL(tNames_store), &iter, NAMES_NAME_COLUMN, &gstr, -1);
		if(strcmp(gstr, gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(namesedit_builder, "names_edit_entry_name")))) != 0) {
			bool name_taken = false;
			if(editing_variable && CALCULATOR->variableNameTaken(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(namesedit_builder, "names_edit_entry_name"))), get_edited_variable())) name_taken = true;
			else if(editing_unknown && CALCULATOR->variableNameTaken(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(namesedit_builder, "names_edit_entry_name"))), get_edited_unknown())) name_taken = true;
			else if(editing_matrix && CALCULATOR->variableNameTaken(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(namesedit_builder, "names_edit_entry_name"))), get_edited_matrix())) name_taken = true;
			else if(editing_unit && CALCULATOR->unitNameTaken(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(namesedit_builder, "names_edit_entry_name"))), get_edited_unit())) name_taken = true;
			else if(editing_function && CALCULATOR->functionNameTaken(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(namesedit_builder, "names_edit_entry_name"))), get_edited_function())) name_taken = true;
			else if(editing_dataset && CALCULATOR->functionNameTaken(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(namesedit_builder, "names_edit_entry_name"))), get_edited_dataset())) name_taken = true;
			if(name_taken) {
				if(!ask_question(_("A conflicting object with the same name exists. If you proceed and save changes, the conflicting object will be overwritten or deactivated.\nDo you want to proceed?"), GTK_WIDGET(gtk_builder_get_object(namesedit_builder, "names_edit_dialog")))) {
					g_free(gstr);
					return;
				}
			}
		}
		g_free(gstr);
		if(editing_dataproperty) gtk_list_store_set(tNames_store, &iter, NAMES_NAME_COLUMN, gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(namesedit_builder, "names_edit_entry_name"))), NAMES_ABBREVIATION_STRING_COLUMN, "-", NAMES_PLURAL_STRING_COLUMN, "-", NAMES_REFERENCE_STRING_COLUMN, b2yn(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_reference")))), NAMES_ABBREVIATION_COLUMN, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_abbreviation"))), NAMES_PLURAL_COLUMN, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_plural"))), NAMES_UNICODE_COLUMN, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_unicode"))), NAMES_REFERENCE_COLUMN, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_reference"))), NAMES_SUFFIX_COLUMN, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_suffix"))), NAMES_AVOID_INPUT_COLUMN, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_avoid_input"))), NAMES_COMPLETION_ONLY_COLUMN, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_completion_only"))), NAMES_CASE_SENSITIVE_COLUMN, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_case_sensitive"))), -1);
		else gtk_list_store_set(tNames_store, &iter, NAMES_NAME_COLUMN, gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(namesedit_builder, "names_edit_entry_name"))), NAMES_ABBREVIATION_STRING_COLUMN, b2yn(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_abbreviation")))), NAMES_PLURAL_STRING_COLUMN, b2yn(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_plural")))), NAMES_REFERENCE_STRING_COLUMN, b2yn(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_reference")))), NAMES_ABBREVIATION_COLUMN, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_abbreviation"))), NAMES_PLURAL_COLUMN, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_plural"))), NAMES_UNICODE_COLUMN, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_unicode"))), NAMES_REFERENCE_COLUMN, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_reference"))), NAMES_SUFFIX_COLUMN, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_suffix"))), NAMES_AVOID_INPUT_COLUMN, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_avoid_input"))), NAMES_COMPLETION_ONLY_COLUMN, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_completion_only"))), NAMES_CASE_SENSITIVE_COLUMN, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_case_sensitive"))), -1);
		on_name_changed();
	}
}
void on_name_changed() {
	if(editing_function) on_function_changed();
	if(editing_unknown) on_unknown_changed();
	if(editing_matrix) on_matrix_changed();
	if(editing_unit) on_unit_changed();
	if(editing_variable) on_variable_changed();
	if(editing_dataproperty) on_dataproperty_changed();
	else if(editing_dataset) on_dataset_changed();
}
void on_names_edit_button_remove_clicked(GtkButton*, gpointer) {
	GtkTreeModel *model;
	GtkTreeIter iter;
	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tNames));
	if(gtk_tree_selection_get_selected(select, &model, &iter)) {
		gtk_list_store_remove(tNames_store, &iter);
		on_name_changed();
	}
	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(namesedit_builder, "names_edit_entry_name")), "");
}
void on_names_edit_entry_name_activate(GtkEntry*, gpointer) {
	if(gtk_widget_get_sensitive(GTK_WIDGET(gtk_builder_get_object(namesedit_builder, "names_edit_button_add")))) {
		on_names_edit_button_add_clicked(GTK_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_button_add")), NULL);
	} else if(gtk_widget_get_sensitive(GTK_WIDGET(gtk_builder_get_object(namesedit_builder, "names_edit_button_modify")))) {
		on_names_edit_button_modify_clicked(GTK_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_button_modify")), NULL);
	}
}
void on_names_edit_entry_name_changed(GtkEditable *editable, gpointer) {
	int etype = -1;
	if(editing_unit) etype = TYPE_UNIT;
	else if(editing_function || editing_dataset) etype = TYPE_FUNCTION;
	else if(!editing_dataproperty) etype = TYPE_VARIABLE;
	if(etype >= 0) correct_name_entry(editable, (ExpressionItemType) etype, (gpointer) on_names_edit_entry_name_changed);
}


bool generate_plot(PlotParameters &pp, vector<MathStructure> &y_vectors, vector<MathStructure> &x_vectors, vector<PlotDataParameters*> &pdps) {
	GtkTreeIter iter;
	bool b = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tPlotFunctions_store), &iter);
	if(!b) {
		return false;
	}	
	while(b) {
		int count = 1;
		gchar *gstr1, *gstr2;
		gint type = 0, style = 0, smoothing = 0, axis = 1, rows = 0;
		MathStructure *y_vector, *x_vector;
		gtk_tree_model_get(GTK_TREE_MODEL(tPlotFunctions_store), &iter, 0, &gstr1, 1, &gstr2, 2, &style, 3, &smoothing, 4, &type, 5, &axis, 6, &rows, 7, &x_vector, 8, &y_vector, -1);
		if(type == 1) {
			if(y_vector->isMatrix()) {
				count = 0;
				if(rows) {
					for(size_t i = 1; i <= y_vector->rows(); i++) {
						y_vectors.push_back(m_undefined);
						y_vector->rowToVector(i, y_vectors[y_vectors.size() - 1]);
						x_vectors.push_back(m_undefined);
						count++;
					}
				} else {
					for(size_t i = 1; i <= y_vector->columns(); i++) {
						y_vectors.push_back(m_undefined);
						y_vector->columnToVector(i, y_vectors[y_vectors.size() - 1]);
						x_vectors.push_back(m_undefined);
						count++;
					}
				}
			} else if(y_vector->isVector()) {
				y_vectors.push_back(*y_vector);
				x_vectors.push_back(m_undefined);
			} else {
				y_vectors.push_back(*y_vector);
				y_vectors[y_vectors.size() - 1].transform(STRUCT_VECTOR);
				x_vectors.push_back(m_undefined);
			}
		} else if(type == 2) {
			if(y_vector->isMatrix()) {
				count = 0;
				if(rows) {
					for(size_t i = 1; i <= y_vector->rows(); i += 2) {
						y_vectors.push_back(m_undefined);
						y_vector->rowToVector(i, y_vectors[y_vectors.size() - 1]);
						x_vectors.push_back(m_undefined);
						y_vector->rowToVector(i + 1, x_vectors[x_vectors.size() - 1]);
						count++;
					}
				} else {
					for(size_t i = 1; i <= y_vector->columns(); i += 2) {
						y_vectors.push_back(m_undefined);
						y_vector->columnToVector(i, y_vectors[y_vectors.size() - 1]);
						x_vectors.push_back(m_undefined);
						y_vector->columnToVector(i + 1, x_vectors[x_vectors.size() - 1]);
						count++;
					}
				}
			} else if(y_vector->isVector()) {
				y_vectors.push_back(*y_vector);
				x_vectors.push_back(m_undefined);
			} else {
				y_vectors.push_back(*y_vector);
				y_vectors[y_vectors.size() - 1].transform(STRUCT_VECTOR);
				x_vectors.push_back(m_undefined);
			}
		} else {
			y_vectors.push_back(*y_vector);
			x_vectors.push_back(*x_vector);
		}
		for(int i = 0; i < count; i++) {
			PlotDataParameters *pdp = new PlotDataParameters();
			pdp->title = gstr1;
			if(count > 1) {
				pdp->title += " :";
				pdp->title += i2s(i + 1);
			}
			remove_blank_ends(pdp->title);
			if(pdp->title.empty()) {
				pdp->title = gstr2;
			}
			pdp->test_continuous = type != 1 && type != 2;
			switch(smoothing) {
				case SMOOTHING_MENU_NONE: {pdp->smoothing = PLOT_SMOOTHING_NONE; break;}
				case SMOOTHING_MENU_UNIQUE: {pdp->smoothing = PLOT_SMOOTHING_UNIQUE; break;}
				case SMOOTHING_MENU_CSPLINES: {pdp->smoothing = PLOT_SMOOTHING_CSPLINES; break;}
				case SMOOTHING_MENU_BEZIER: {pdp->smoothing = PLOT_SMOOTHING_BEZIER; break;}
				case SMOOTHING_MENU_SBEZIER: {pdp->smoothing = PLOT_SMOOTHING_SBEZIER; break;}
			}
			switch(style) {
				case PLOTSTYLE_MENU_LINES: {pdp->style = PLOT_STYLE_LINES; break;}
				case PLOTSTYLE_MENU_POINTS: {pdp->style = PLOT_STYLE_POINTS; break;}
				case PLOTSTYLE_MENU_LINESPOINTS: {pdp->style = PLOT_STYLE_POINTS_LINES; break;}
				case PLOTSTYLE_MENU_DOTS: {pdp->style = PLOT_STYLE_DOTS; break;}
				case PLOTSTYLE_MENU_BOXES: {pdp->style = PLOT_STYLE_BOXES; break;}
				case PLOTSTYLE_MENU_HISTEPS: {pdp->style = PLOT_STYLE_HISTOGRAM; break;}
				case PLOTSTYLE_MENU_STEPS: {pdp->style = PLOT_STYLE_STEPS; break;}
				case PLOTSTYLE_MENU_CANDLESTICKS: {pdp->style = PLOT_STYLE_CANDLESTICKS; break;}
			}
			pdp->yaxis2 = (axis == 2);
			pdps.push_back(pdp);
		}
		g_free(gstr1);
		g_free(gstr2);
		b = gtk_tree_model_iter_next(GTK_TREE_MODEL(tPlotFunctions_store), &iter);
	}
	switch(gtk_combo_box_get_active(GTK_COMBO_BOX(gtk_builder_get_object(plot_builder, "plot_combobox_legend_place")))) {
		case PLOTLEGEND_MENU_NONE: {pp.legend_placement = PLOT_LEGEND_NONE; break;}
		case PLOTLEGEND_MENU_TOP_LEFT: {pp.legend_placement = PLOT_LEGEND_TOP_LEFT; break;}
		case PLOTLEGEND_MENU_TOP_RIGHT: {pp.legend_placement = PLOT_LEGEND_TOP_RIGHT; break;}
		case PLOTLEGEND_MENU_BOTTOM_LEFT: {pp.legend_placement = PLOT_LEGEND_BOTTOM_LEFT; break;}
		case PLOTLEGEND_MENU_BOTTOM_RIGHT: {pp.legend_placement = PLOT_LEGEND_BOTTOM_RIGHT; break;}
		case PLOTLEGEND_MENU_BELOW: {pp.legend_placement = PLOT_LEGEND_BELOW; break;}
		case PLOTLEGEND_MENU_OUTSIDE: {pp.legend_placement = PLOT_LEGEND_OUTSIDE; break;}
	}
	pp.title = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_plottitle")));
	pp.x_label = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_xlabel")));
	pp.y_label = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_ylabel")));
	pp.grid = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_checkbutton_grid")));
	pp.x_log = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_checkbutton_xlog")));
	pp.y_log = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_checkbutton_ylog")));
	pp.x_log_base = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_builder_get_object(plot_builder, "plot_spinbutton_xlog_base")));
	pp.y_log_base = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_builder_get_object(plot_builder, "plot_spinbutton_ylog_base")));
	pp.auto_y_min = !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_checkbutton_ymin")));
	pp.auto_y_max = !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_checkbutton_ymax")));
	pp.y_min = gtk_spin_button_get_value(GTK_SPIN_BUTTON(gtk_builder_get_object(plot_builder, "plot_spinbutton_ymin")));
	pp.y_max = gtk_spin_button_get_value(GTK_SPIN_BUTTON(gtk_builder_get_object(plot_builder, "plot_spinbutton_ymax")));
	pp.color = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_radiobutton_color")));
	pp.show_all_borders = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_checkbutton_full_border")));
	pp.linewidth = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_builder_get_object(plot_builder, "plot_spinbutton_linewidth")));
	return true;
}
void on_plot_button_help_clicked(GtkButton, gpointer) {
	show_help("qalculate-plotting.html", gtk_builder_get_object(plot_builder, "plot_dialog")); 
}
void on_plot_button_save_clicked(GtkButton*, gpointer) {
	GtkWidget *d;
	d = gtk_file_chooser_dialog_new(_("Select file to export"), GTK_WINDOW(gtk_builder_get_object(plot_builder, "plot_dialog")), GTK_FILE_CHOOSER_ACTION_SAVE, _("_Cancel"), GTK_RESPONSE_CANCEL, _("_Save"), GTK_RESPONSE_ACCEPT, NULL);
	gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(d), TRUE);
	GtkFileFilter *filter = gtk_file_filter_new();
	gtk_file_filter_set_name(filter, _("Allowed File Types"));
	gtk_file_filter_add_mime_type(filter, "image/x-xfig");
	gtk_file_filter_add_mime_type(filter, "image/svg");
	gtk_file_filter_add_mime_type(filter, "text/x-tex");
	gtk_file_filter_add_mime_type(filter, "application/pdf");
	gtk_file_filter_add_mime_type(filter, "application/postscript");
	gtk_file_filter_add_mime_type(filter, "image/x-eps");
	gtk_file_filter_add_mime_type(filter, "image/png");
	gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(d), filter);
	GtkFileFilter *filter_all = gtk_file_filter_new();
	gtk_file_filter_add_pattern(filter_all, "*");
	gtk_file_filter_set_name(filter_all, _("All Files"));
	gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(d), filter_all);
	string title = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_plottitle")));
	if(title.empty()) {
		gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(d), "plot.png");
	} else {
		title += ".png";
		gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(d), title.c_str());
	}
	if(gtk_dialog_run(GTK_DIALOG(d)) == GTK_RESPONSE_ACCEPT) {
		vector<MathStructure> y_vectors;
		vector<MathStructure> x_vectors;
		vector<PlotDataParameters*> pdps;
		PlotParameters pp;
		if(generate_plot(pp, y_vectors, x_vectors, pdps)) {
			pp.filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(d));
			pp.filetype = PLOT_FILETYPE_AUTO;
			do_timeout = false;
			CALCULATOR->plotVectors(&pp, y_vectors, x_vectors, pdps);
			display_errors(NULL, GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_dialog")));
			do_timeout = true;
			for(size_t i = 0; i < pdps.size(); i++) {
				if(pdps[i]) delete pdps[i];
			}
		}
	}
	gtk_widget_destroy(d);
}
void update_plot() {
	vector<MathStructure> y_vectors;
	vector<MathStructure> x_vectors;
	vector<PlotDataParameters*> pdps;
	PlotParameters pp;
	if(!generate_plot(pp, y_vectors, x_vectors, pdps)) {
		CALCULATOR->closeGnuplot();
		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_button_save")), false);
		return;
	}
	do_timeout = false;
	CALCULATOR->plotVectors(&pp, y_vectors, x_vectors, pdps);
	display_errors(NULL, GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_dialog")));
	do_timeout = true;
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_button_save")), true);
	for(size_t i = 0; i < pdps.size(); i++) {
		if(pdps[i]) delete pdps[i];
	}
}

void generate_plot_series(MathStructure **x_vector, MathStructure **y_vector, int type, string str, string str_x) {
	CALCULATOR->beginTemporaryStopIntervalArithmetic();
	EvaluationOptions eo;
	eo.approximation = APPROXIMATION_APPROXIMATE;
	eo.parse_options = evalops.parse_options;
	eo.parse_options.read_precision = DONT_READ_PRECISION;
	do_timeout = false;
	if(type == 1 || type == 2) {
		*y_vector = new MathStructure();
		if(!CALCULATOR->calculate(*y_vector, CALCULATOR->unlocalizeExpression(str, evalops.parse_options), 5000, eo)) {
			GtkWidget *d = gtk_message_dialog_new (GTK_WINDOW(gtk_builder_get_object(plot_builder, "plot_dialog")), (GtkDialogFlags) 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("It took too long to generate the plot data."));
			gtk_dialog_run(GTK_DIALOG(d));
			gtk_widget_destroy(d);
		}
		*x_vector = NULL;
	} else {
		*x_vector = new MathStructure();
		(*x_vector)->clearVector();
		MathStructure min;
		if(!CALCULATOR->calculate(&min, CALCULATOR->unlocalizeExpression(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_min"))), evalops.parse_options), 1000, eo)) {
			GtkWidget *d = gtk_message_dialog_new (GTK_WINDOW(gtk_builder_get_object(plot_builder, "plot_dialog")), (GtkDialogFlags) 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("It took too long to generate the plot data."));
			gtk_dialog_run(GTK_DIALOG(d));
			gtk_widget_destroy(d);
			display_errors(NULL, GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_dialog")));
			do_timeout = true;
			return;
		}
		MathStructure max;
		if(!CALCULATOR->calculate(&max, CALCULATOR->unlocalizeExpression(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_max"))), evalops.parse_options), 1000, eo)) {
			GtkWidget *d = gtk_message_dialog_new (GTK_WINDOW(gtk_builder_get_object(plot_builder, "plot_dialog")), (GtkDialogFlags) 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("It took too long to generate the plot data."));
			gtk_dialog_run(GTK_DIALOG(d));
			gtk_widget_destroy(d);
			display_errors(NULL, GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_dialog")));
			do_timeout = true;
			return;
		}
		if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_radiobutton_step")))) {
			*y_vector = new MathStructure(CALCULATOR->expressionToPlotVector(str, min, max, CALCULATOR->calculate(CALCULATOR->unlocalizeExpression(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_step"))), evalops.parse_options), eo), *x_vector, str_x, evalops.parse_options, 5000));
		} else {
			*y_vector = new MathStructure(CALCULATOR->expressionToPlotVector(str, min, max, gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_builder_get_object(plot_builder, "plot_spinbutton_steps"))), *x_vector, str_x, evalops.parse_options, 5000));
		}
	}
	CALCULATOR->endTemporaryStopIntervalArithmetic();
	display_errors(NULL, GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_dialog")));
	do_timeout = true;
}
void on_plot_button_add_clicked(GtkButton*, gpointer) {
	string expression = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_expression")));
	if(expression.find_first_not_of(SPACES) == string::npos) {
		gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_entry_expression")));
		show_message(_("Empty expression."), GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_dialog")));
		return;
	}
	gint type = 0, axis = 1, rows = 0;
	string title = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_title")));
	if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_radiobutton_vector")))) {
		type = 1;
	} else if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_radiobutton_paired")))) {
		type = 2;
	}
	string str_x = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_variable")));
	remove_blank_ends(str_x);
	if(str_x.empty() && type == 0) {
		gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_entry_variable")));
		show_message(_("Empty x variable."), GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_dialog")));
		return;
	}
	if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_radiobutton_yaxis2")))) {
		axis = 2;
	}
	if((type == 1 || type == 2) && title.empty()) {
		Variable *v = CALCULATOR->getActiveVariable(expression);
		if(v) {
			title = v->title(false);
		}
	}
	MathStructure *x_vector, *y_vector;
	generate_plot_series(&x_vector, &y_vector, type, expression, str_x);
	rows = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_checkbutton_rows")));
	GtkTreeIter iter;	
	gtk_list_store_append(tPlotFunctions_store, &iter);
	gtk_list_store_set(tPlotFunctions_store, &iter, 0, title.c_str(), 1, expression.c_str(), 2, gtk_combo_box_get_active(GTK_COMBO_BOX(gtk_builder_get_object(plot_builder, "plot_combobox_style"))), 3, gtk_combo_box_get_active(GTK_COMBO_BOX(gtk_builder_get_object(plot_builder, "plot_combobox_smoothing"))), 4, type, 5, axis, 6, rows, 7, x_vector, 8, y_vector, 9, str_x.c_str(), -1);
	gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tPlotFunctions)), &iter);
	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_entry_expression")));
	update_plot();
}
void on_plot_button_modify_clicked(GtkButton*, gpointer) {

	GtkTreeModel *model;
	GtkTreeIter iter;
	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tPlotFunctions));
	if(gtk_tree_selection_get_selected(select, &model, &iter)) {	
		string expression = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_expression")));
		if(expression.find_first_not_of(SPACES) == string::npos) {
			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_entry_expression")));
			show_message(_("Empty expression."), GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_dialog")));
			return;
		}
		gint type = 0, axis = 1, rows = 0;
		string title = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_title")));
		if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_radiobutton_vector")))) {
			type = 1;
		} else if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_radiobutton_paired")))) {
			type = 2;
		}
		string str_x = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_variable")));
		remove_blank_ends(str_x);
		if(str_x.empty() && type == 0) {
			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_entry_variable")));
			show_message(_("Empty x variable."), GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_dialog")));
			return;
		}
		if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_radiobutton_yaxis2")))) {
			axis = 2;
		}
		if((type == 1 || type == 2) && title.empty()) {
			Variable *v = CALCULATOR->getActiveVariable(expression);
			if(v) {
				title = v->title(false);
			}
		}
		MathStructure *x_vector, *y_vector;
		gtk_tree_model_get(GTK_TREE_MODEL(tPlotFunctions_store), &iter, 7, &x_vector, 8, &y_vector, -1);
		if(x_vector) delete x_vector;
		if(y_vector) delete y_vector;
		x_vector = NULL;
		y_vector = NULL;
		generate_plot_series(&x_vector, &y_vector, type, expression, str_x);
		rows = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_checkbutton_rows")));
		gtk_list_store_set(tPlotFunctions_store, &iter, 0, title.c_str(), 1, expression.c_str(), 2, gtk_combo_box_get_active(GTK_COMBO_BOX(gtk_builder_get_object(plot_builder, "plot_combobox_style"))), 3, gtk_combo_box_get_active(GTK_COMBO_BOX(gtk_builder_get_object(plot_builder, "plot_combobox_smoothing"))), 4, type, 5, axis, 6, rows, 7, x_vector, 8, y_vector, 9, str_x.c_str(), -1);
		gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_entry_expression")));
		update_plot();
	}
}
void on_plot_button_remove_clicked(GtkButton*, gpointer) {
	GtkTreeModel *model;
	GtkTreeIter iter;
	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tPlotFunctions));
	if(gtk_tree_selection_get_selected(select, &model, &iter)) {
		MathStructure *x_vector, *y_vector;
		gtk_tree_model_get(GTK_TREE_MODEL(tPlotFunctions_store), &iter, 7, &x_vector, 8, &y_vector, -1);
		if(x_vector) delete x_vector;
		if(y_vector) delete y_vector;
		gtk_list_store_remove(tPlotFunctions_store, &iter);
		gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_entry_expression")));
		update_plot();
	}
}

void on_plot_checkbutton_xlog_toggled(GtkToggleButton *w, gpointer) {
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_spinbutton_xlog_base")), gtk_toggle_button_get_active(w));
}
void on_plot_checkbutton_ylog_toggled(GtkToggleButton *w, gpointer) {
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_spinbutton_ylog_base")), gtk_toggle_button_get_active(w));
}
void on_plot_checkbutton_ymin_toggled(GtkToggleButton *w, gpointer) {
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_spinbutton_ymin")), gtk_toggle_button_get_active(w));
}
void on_plot_checkbutton_ymax_toggled(GtkToggleButton *w, gpointer) {
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_spinbutton_ymax")), gtk_toggle_button_get_active(w));
}
void on_plot_radiobutton_step_toggled(GtkToggleButton *w, gpointer) {
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_entry_step")), gtk_toggle_button_get_active(w));
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_spinbutton_steps")), !gtk_toggle_button_get_active(w));
}
void on_plot_radiobutton_steps_toggled(GtkToggleButton *w, gpointer) {
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_entry_step")), !gtk_toggle_button_get_active(w));
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_spinbutton_steps")), gtk_toggle_button_get_active(w));
}
void on_plot_entry_expression_activate(GtkEntry*, gpointer) {
	GtkTreeModel *model;
	GtkTreeIter iter;
	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tPlotFunctions));
	if(gtk_tree_selection_get_selected(select, &model, &iter)) {
		on_plot_button_modify_clicked(GTK_BUTTON(gtk_builder_get_object(plot_builder, "plot_button_modify")), NULL);
	} else {
		on_plot_button_add_clicked(GTK_BUTTON(gtk_builder_get_object(plot_builder, "plot_button_add")), NULL);
	}
}

void on_plot_radiobutton_function_toggled(GtkToggleButton *w, gpointer) {
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_box_variable")), gtk_toggle_button_get_active(w));
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_checkbutton_rows")), !gtk_toggle_button_get_active(w));
}
void on_plot_radiobutton_vector_toggled(GtkToggleButton *w, gpointer) {
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_box_variable")), !gtk_toggle_button_get_active(w));
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_checkbutton_rows")), gtk_toggle_button_get_active(w));
}
void on_plot_radiobutton_paired_toggled(GtkToggleButton *w, gpointer) {
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_box_variable")), !gtk_toggle_button_get_active(w));
	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_checkbutton_rows")), gtk_toggle_button_get_active(w));
}
void on_plot_button_range_apply_clicked(GtkButton*, gpointer) {
	GtkTreeIter iter;
	bool b = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tPlotFunctions_store), &iter);
	while(b) {
		gchar *gstr2, *gstr3;
		gint type = 0;
		MathStructure *y_vector, *x_vector;
		gtk_tree_model_get(GTK_TREE_MODEL(tPlotFunctions_store), &iter, 1, &gstr2, 4, &type, 7, &x_vector, 8, &y_vector, 9, &gstr3, -1);
		if(y_vector) delete y_vector;
		if(x_vector) delete x_vector;
		x_vector = NULL;
		y_vector = NULL;
		generate_plot_series(&x_vector, &y_vector, type, gstr2, gstr3);
		g_free(gstr2);
		g_free(gstr3);
		gtk_list_store_set(tPlotFunctions_store, &iter, 7, x_vector, 8, y_vector, -1);
		b = gtk_tree_model_iter_next(GTK_TREE_MODEL(tPlotFunctions_store), &iter);
	}
	update_plot();
}
void on_plot_button_appearance_apply_clicked(GtkButton*, gpointer) {
	update_plot();
}

void convert_from_convert_entry_unit() {
	do_timeout = false;
	string ceu_str = CALCULATOR->unlocalizeExpression(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(main_builder, "convert_entry_unit"))), evalops.parse_options);
	if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "convert_button_set_missing_prefixes"))) && !ceu_str.empty()) {
		remove_blank_ends(ceu_str);
		if(!ceu_str.empty() && ceu_str[0] != '0' && ceu_str[0] != '?' && ceu_str[0] != '+' && ceu_str[0] != '-' && (ceu_str.length() == 1 || ceu_str[1] != '?')) {
			ceu_str = "?" + ceu_str;
		}
	}
	bool b_puup = printops.use_unit_prefixes;
	to_prefix = 0;
	printops.use_unit_prefixes = true;
	block_conversion_category_switch++;
	executeCommand(COMMAND_CONVERT_STRING, true, ceu_str);
	block_conversion_category_switch--;
	printops.use_unit_prefixes = b_puup;
	do_timeout = true;
}
void on_convert_button_set_missing_prefixes_toggled(GtkToggleButton *w, gpointer) {
	if(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(main_builder, "convert_entry_unit"))) != 0) {
		convert_from_convert_entry_unit();
	}
}
void on_convert_button_convert_clicked(GtkButton*, gpointer) {
	convert_from_convert_entry_unit();
	focus_keeping_selection();
}
void on_convert_entry_unit_activate(GtkEntry*, gpointer) {
	convert_from_convert_entry_unit();
	focus_keeping_selection();
}

vector<GtkWidget*> ewindows;
vector<DataObject*> eobjects;

void on_element_button_function_clicked(GtkButton *w, gpointer user_data) {
	DataProperty *dp = (DataProperty*) user_data;
	DataSet *ds = NULL;
	DataObject *o = NULL;
	GtkWidget *win = gtk_widget_get_toplevel(GTK_WIDGET(w));
	for(size_t i = 0; i < ewindows.size(); i++) {
		if(ewindows[i] == win) {
			o = eobjects[i];
			break;
		}
	}
	if(dp) ds = dp->parentSet();
	if(ds && o) {
		string str = ds->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext).name;
		str += "(";
		str += o->getProperty(ds->getPrimaryKeyProperty());
		str += CALCULATOR->getComma();
		str += " ";
		str += dp->getName();
		str += ")";
		insert_text(str.c_str());
	}
}
void on_element_button_close_clicked(GtkButton *w, gpointer user_data) {
	GtkWidget *win = gtk_widget_get_toplevel(GTK_WIDGET(w));
	for(size_t i = 0; i < ewindows.size(); i++) {
		if(ewindows[i] == win) {
			ewindows.erase(ewindows.begin() + i);
			eobjects.erase(eobjects.begin() + i);
			break;
		}
	}
	gtk_widget_destroy((GtkWidget*) user_data);
}
void on_element_button_clicked(GtkButton*, gpointer user_data) {
	DataObject *e = (DataObject*) user_data;
	if(e) {
		DataSet *ds = e->parentSet();
		if(!ds) return;
		GtkWidget *dialog = gtk_dialog_new();
		ewindows.push_back(dialog);
		eobjects.push_back(e);
		GtkWidget *close_button = gtk_dialog_add_button(GTK_DIALOG(dialog), _("_Close"), GTK_RESPONSE_CLOSE);
		g_signal_connect((gpointer) close_button, "clicked", G_CALLBACK(on_element_button_close_clicked), (gpointer) dialog);
		gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gtk_builder_get_object(periodictable_builder, "periodic_dialog")));
		gtk_window_set_title(GTK_WINDOW(dialog), _("Element Data"));
		gtk_container_set_border_width(GTK_CONTAINER(dialog), 5);
		GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 15);
		gtk_container_set_border_width(GTK_CONTAINER(vbox), 12);
		gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), vbox);
		
		GtkWidget *vbox2 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
		gtk_box_pack_start(GTK_BOX(vbox), vbox2, FALSE, TRUE, 0);
		
		DataProperty *p_number = ds->getProperty("number");
		DataProperty *p_symbol = ds->getProperty("symbol");
		DataProperty *p_class = ds->getProperty("class");
		DataProperty *p_name = ds->getProperty("name");

		GtkWidget *label;
		label = gtk_label_new(NULL);
		string str = "<span size=\"large\">"; str += e->getProperty(p_number); str += "</span>";
		gtk_label_set_markup(GTK_LABEL(label), str.c_str()); gtk_widget_set_halign(label, GTK_ALIGN_END); gtk_label_set_selectable(GTK_LABEL(label), TRUE);
		gtk_box_pack_start(GTK_BOX(vbox2), label, FALSE, TRUE, 0);
		label = gtk_label_new(NULL);
		str = "<span size=\"xx-large\">"; str += e->getProperty(p_symbol); str += "</span>";
		gtk_label_set_markup(GTK_LABEL(label), str.c_str()); gtk_widget_set_halign(label, GTK_ALIGN_START); gtk_label_set_selectable(GTK_LABEL(label), TRUE);
		gtk_box_pack_start(GTK_BOX(vbox2), label, FALSE, TRUE, 0);
		label = gtk_label_new(NULL);
		str = "<span size=\"x-large\">"; str += e->getProperty(p_name); str += "</span>  "; 
		gtk_label_set_markup(GTK_LABEL(label), str.c_str()); gtk_widget_set_halign(label, GTK_ALIGN_START); gtk_label_set_selectable(GTK_LABEL(label), TRUE);
		gtk_box_pack_start(GTK_BOX(vbox2), label, FALSE, TRUE, 0);

		GtkWidget *button;
		GtkWidget *ptable = gtk_grid_new();
		gtk_grid_set_column_spacing(GTK_GRID(ptable), 6);
		gtk_box_pack_start(GTK_BOX(vbox), ptable, FALSE, TRUE, 0);
		int rows = 0;

		int group = s2i(e->getProperty(p_class));
		if(group > 0) {
			rows++;
			label = gtk_label_new(NULL);
			str = "<span weight=\"bold\">"; str += _("Classification"); str += ":"; str += "</span>";
			gtk_label_set_markup(GTK_LABEL(label), str.c_str()); gtk_widget_set_halign(label, GTK_ALIGN_START); gtk_label_set_selectable(GTK_LABEL(label), FALSE);
			gtk_grid_attach(GTK_GRID(ptable), label, 0, rows - 1, 1, 1);
			label = gtk_label_new(NULL);
			switch(group) {
				case ALKALI_METALS: {gtk_label_set_markup(GTK_LABEL(label), _("Alkali Metal")); break;}
				case ALKALI_EARTH_METALS: {gtk_label_set_markup(GTK_LABEL(label), _("Alkaline-Earth Metal")); break;}
				case LANTHANIDES: {gtk_label_set_markup(GTK_LABEL(label), _("Lanthanide")); break;}
				case ACTINIDES: {gtk_label_set_markup(GTK_LABEL(label), _("Actinide")); break;}
				case TRANSITION_METALS: {gtk_label_set_markup(GTK_LABEL(label), _("Transition Metal")); break;}
				case METALS: {gtk_label_set_markup(GTK_LABEL(label), _("Metal")); break;}
				case METALLOIDS: {gtk_label_set_markup(GTK_LABEL(label), _("Metalloid")); break;}
				case NONMETALS: {gtk_label_set_markup(GTK_LABEL(label), _("Polyatomic Non-Metal")); break;}
				case HALOGENS: {gtk_label_set_markup(GTK_LABEL(label), _("Diatomic Non-Metal")); break;}
				case NOBLE_GASES: {gtk_label_set_markup(GTK_LABEL(label), _("Noble Gas")); break;}
				case TRANSACTINIDES: {gtk_label_set_markup(GTK_LABEL(label), _("Unknown chemical properties")); break;}
				default: {gtk_label_set_markup(GTK_LABEL(label), _("Unknown")); break;}
			}
			gtk_widget_set_halign(label, GTK_ALIGN_START); gtk_label_set_selectable(GTK_LABEL(label), TRUE);
			gtk_widget_set_margin_end(label, 10);
			gtk_grid_attach(GTK_GRID(ptable), label, 1, rows - 1, 1, 1);
		}
		
		DataPropertyIter it;
		DataProperty *dp = ds->getFirstProperty(&it);
		string sval;
		while(dp) {
			if(!dp->isHidden() && dp != p_number && dp != p_class && dp != p_symbol && dp != p_name) {
				sval = e->getPropertyDisplayString(dp);
				if(!sval.empty()) {
					rows++;
					label = gtk_label_new(NULL);
					str = "<span weight=\"bold\">"; str += dp->title(); str += ":"; str += "</span>";
					gtk_label_set_markup(GTK_LABEL(label), str.c_str()); gtk_widget_set_halign(label, GTK_ALIGN_START); gtk_label_set_selectable(GTK_LABEL(label), FALSE);
					gtk_grid_attach(GTK_GRID(ptable), label, 0, rows - 1, 1, 1);
					label = gtk_label_new(NULL);
					gtk_label_set_markup(GTK_LABEL(label), sval.c_str()); gtk_widget_set_halign(label, GTK_ALIGN_START); gtk_label_set_selectable(GTK_LABEL(label), TRUE);
					gtk_grid_attach(GTK_GRID(ptable), label, 1, rows - 1, 1, 1);
					button = gtk_button_new();
					gtk_container_add(GTK_CONTAINER(button), gtk_image_new_from_icon_name("edit-paste", GTK_ICON_SIZE_BUTTON));
					gtk_grid_attach(GTK_GRID(ptable), button, 2, rows - 1, 1, 1);
					g_signal_connect((gpointer) button, "clicked", G_CALLBACK(on_element_button_function_clicked), (gpointer) dp);
				}
			}
			dp = ds->getNextProperty(&it);
		}
		
		gtk_widget_show_all(dialog);
		
	}
}

void on_dataset_edit_entry_name_changed(GtkEditable *editable, gpointer) {
	correct_name_entry(editable, TYPE_FUNCTION,  (gpointer) on_dataset_edit_entry_name_changed);
}
void on_dataset_edit_button_new_property_clicked(GtkButton*, gpointer) {
	DataProperty *dp = new DataProperty(edited_dataset);
	dp->setUserModified(true);
	if(edit_dataproperty(dp, true)) {
		tmp_props.push_back(dp);
		tmp_props_orig.push_back(NULL);
		update_dataset_property_list(edited_dataset);
		on_dataset_changed();
	} else {
		delete dp;
	}
}
void on_dataset_edit_button_edit_property_clicked(GtkButton*, gpointer) {
	if(selected_dataproperty) {
		if(edit_dataproperty(selected_dataproperty, false)) {
			update_dataset_property_list(edited_dataset);
			on_dataset_changed();
		}
	}
}
void on_dataset_edit_button_del_property_clicked(GtkButton*, gpointer) {
	if(edited_dataset && selected_dataproperty && selected_dataproperty->isUserModified()) {
		for(size_t i = 0; i < tmp_props.size(); i++) {
			if(tmp_props[i] == selected_dataproperty) {
				if(tmp_props_orig[i]) {
					tmp_props[i] = NULL;
				} else {
					tmp_props.erase(tmp_props.begin() + i);
					tmp_props_orig.erase(tmp_props_orig.begin() + i);
				}
				break;
			}
		}
		update_dataset_property_list(edited_dataset);
		on_dataset_changed();
	}
}
void on_dataset_edit_button_names_clicked(GtkButton*, gpointer) {
	edit_names(get_edited_dataset(), gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataset_edit_entry_name"))), GTK_WIDGET(gtk_builder_get_object(datasetedit_builder, "dataset_edit_dialog")));
	SET_NAMES_LE(datasetedit_builder, "dataset_edit_entry_name", "dataset_edit_label_names")
}

void on_dataproperty_edit_button_names_clicked(GtkButton*, gpointer) {
	edit_names(NULL, gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_entry_name"))), GTK_WIDGET(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_dialog")), TRUE, get_edited_dataproperty());
	SET_NAMES_LE(datasetedit_builder, "dataproperty_edit_entry_name", "dataproperty_edit_label_names")
}

void on_menu_item_set_unknowns_activate(GtkMenuItem*, gpointer) {
	if(expression_has_changed && !rpn_mode) execute_expression(true);
	MathStructure unknowns;
	mstruct->findAllUnknowns(unknowns);
	if(unknowns.size() == 0) {
		show_message(_("No unknowns in result."), GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")));
		return;
	}
	unknowns.setType(STRUCT_ADDITION);
	unknowns.sort();
	
	GtkWidget *dialog = gtk_dialog_new_with_buttons(_("Set Unknowns"), GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT), _("_OK"), GTK_RESPONSE_ACCEPT, _("_Apply"), GTK_RESPONSE_APPLY, _("_Cancel"), GTK_RESPONSE_REJECT, NULL);
	gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_MOUSE);
	gtk_container_set_border_width(GTK_CONTAINER(dialog), 5);
	GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 15);
	gtk_container_set_border_width(GTK_CONTAINER(vbox), 12);
	gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), vbox);
	GtkWidget *label;
	vector<GtkWidget*> entry;
	entry.resize(unknowns.size(), NULL);
	GtkWidget *ptable = gtk_grid_new();
	gtk_grid_set_column_spacing(GTK_GRID(ptable), 6);
	gtk_grid_set_row_spacing(GTK_GRID(ptable), 6);
	gtk_box_pack_start(GTK_BOX(vbox), ptable, FALSE, TRUE, 0);
	int rows = 0;
	for(size_t i = 0; i < unknowns.size(); i++) {
		rows++;
		label = gtk_label_new(unknowns[i].print().c_str());
		gtk_widget_set_halign(label, GTK_ALIGN_START);
		gtk_grid_attach(GTK_GRID(ptable), label, 0, rows - 1, 1, 1);
		entry[i] = gtk_entry_new();
		gtk_widget_set_hexpand(entry[i], TRUE);
		gtk_grid_attach(GTK_GRID(ptable), entry[i], 1, rows - 1, 1, 1);
	}
	MathStructure msave(*mstruct);
	string result_save = result_text;
	gtk_widget_show_all(dialog);
	bool b_changed = false;
	vector<string> unknown_text;
	unknown_text.resize(unknowns.size());
	while(true) {
		gint response = gtk_dialog_run(GTK_DIALOG(dialog));
		bool b1 = false, b2 = false;
		if(response == GTK_RESPONSE_ACCEPT || response == GTK_RESPONSE_APPLY) {
			string str, result_mod = "";
			do_timeout = false;
			for(size_t i = 0; i < unknowns.size(); i++) {
				str = gtk_entry_get_text(GTK_ENTRY(entry[i]));
				remove_blank_ends(str);
				if(((b1 || !b_changed) && !str.empty()) || (b_changed && unknown_text[i] != str)) {
					if(!result_mod.empty()) {
						result_mod += CALCULATOR->getComma();
						result_mod += " ";
					} else {
						b1 = true;
						mstruct->set(msave);
						for(size_t i2 = 0; i2 < i; i2++) {
							if(!unknown_text[i2].empty()) {
								mstruct->replace(unknowns[i2], CALCULATOR->parse(CALCULATOR->unlocalizeExpression(unknown_text[i2], evalops.parse_options), evalops.parse_options));
								b2 = true;
							}
						}
					}
					result_mod += unknowns[i].print().c_str();
					result_mod += "=";
					if(str.empty()) {
						result_mod += "?";
					} else {
						result_mod += str;
						mstruct->replace(unknowns[i], CALCULATOR->parse(CALCULATOR->unlocalizeExpression(str, evalops.parse_options), evalops.parse_options));
						b2 = true;
					}
					unknown_text[i] = str;
				}
			}
			if(response == GTK_RESPONSE_ACCEPT) {
				gtk_widget_destroy(dialog);
			}
			if(b2) {
				b_changed = true;
				if(response != GTK_RESPONSE_ACCEPT) {
					gtk_window_set_modal(GTK_WINDOW(dialog), FALSE);
					gtk_widget_set_sensitive(GTK_WIDGET(dialog), FALSE);
				}
				executeCommand(COMMAND_TRANSFORM, true, result_mod);
			} else if(b1) {
				b_changed = false;
				printops.allow_factorization = (evalops.structuring == STRUCTURING_FACTORIZE);
				setResult(NULL, true, false, false, result_mod);
			}
			do_timeout = true;
			if(response == GTK_RESPONSE_ACCEPT) {
				break;
			}
			gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
			gtk_widget_set_sensitive(GTK_WIDGET(dialog), TRUE);
		} else {
			if(b_changed && response == GTK_RESPONSE_REJECT) {
				string result_mod = "";
				mstruct->set(msave);
				for(size_t i = 0; i < unknowns.size(); i++) {
					if(!unknown_text[i].empty()) {
						if(!result_mod.empty()) {
							result_mod += CALCULATOR->getComma();
							result_mod += " ";
						}
						result_mod += unknowns[i].print().c_str();
						result_mod += "=";
						result_mod += "?";
					}
				}
				printops.allow_factorization = (evalops.structuring == STRUCTURING_FACTORIZE);
				setResult(NULL, true, false, false, result_mod);
			}
			gtk_widget_destroy(dialog);
			break;
		}
	}
}

#ifdef __cplusplus
}
#endif

