1 /*
2     Qalculate (GTK+ UI)
3 
4     Copyright (C) 2003-2007, 2008, 2016-2021  Hanna Knutsson (hanna.knutsson@protonmail.com)
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 */
11 
12 #ifdef HAVE_CONFIG_H
13 #	include <config.h>
14 #endif
15 
16 #include <gdk/gdkkeysyms.h>
17 #include <gtk/gtk.h>
18 #include <gdk/gdk.h>
19 #include <gdk-pixbuf/gdk-pixbuf.h>
20 #include <glib/gstdio.h>
21 #ifdef USE_WEBKITGTK
22 #	include <webkit2/webkit2.h>
23 #endif
24 #include <sys/stat.h>
25 #include <unistd.h>
26 #include <time.h>
27 #include <limits>
28 #include <fstream>
29 #include <sstream>
30 
31 #include "support.h"
32 #include "callbacks.h"
33 #include "interface.h"
34 #include "main.h"
35 #include <stack>
36 #include <deque>
37 
38 #if HAVE_UNORDERED_MAP
39 #	include <unordered_map>
40 	using std::unordered_map;
41 #elif 	defined(__GNUC__)
42 
43 #	ifndef __has_include
44 #	define __has_include(x) 0
45 #	endif
46 
47 #	if (defined(__clang__) && __has_include(<tr1/unordered_map>)) || (__GNUC__ >= 4 && __GNUC_MINOR__ >= 3)
48 #		include <tr1/unordered_map>
49 		namespace Sgi = std;
50 #		define unordered_map std::tr1::unordered_map
51 #	else
52 #		if __GNUC__ < 3
53 #			include <hash_map.h>
54 			namespace Sgi { using ::hash_map; }; // inherit globals
55 #		else
56 #			include <ext/hash_map>
57 #			if __GNUC__ == 3 && __GNUC_MINOR__ == 0
58 				namespace Sgi = std;		// GCC 3.0
59 #			else
60 				namespace Sgi = ::__gnu_cxx;	// GCC 3.1 and later
61 #			endif
62 #		endif
63 #		define unordered_map Sgi::hash_map
64 #	endif
65 #else      // ...  there are other compilers, right?
66 	namespace Sgi = std;
67 #	define unordered_map Sgi::hash_map
68 #endif
69 
70 using std::string;
71 using std::cout;
72 using std::vector;
73 using std::endl;
74 using std::iterator;
75 using std::list;
76 using std::ifstream;
77 using std::ofstream;
78 using std::deque;
79 using std::stack;
80 
81 extern bool do_timeout, check_expression_position;
82 extern gint expression_position;
83 
84 extern GtkBuilder *main_builder, *argumentrules_builder, *csvimport_builder, *csvexport_builder, *setbase_builder, *datasetedit_builder, *datasets_builder, *decimals_builder;
85 extern GtkBuilder *functionedit_builder, *functions_builder, *matrixedit_builder, *matrix_builder, *namesedit_builder, *nbases_builder, *plot_builder, *precision_builder;
86 extern GtkBuilder *shortcuts_builder, *preferences_builder, *unitedit_builder, *units_builder, *unknownedit_builder, *variableedit_builder, *variables_builder, *buttonsedit_builder;
87 extern GtkBuilder *periodictable_builder, *simplefunctionedit_builder, *percentage_builder, *calendarconversion_builder, *floatingpoint_builder;
88 
89 extern GtkWidget *mainwindow;
90 
91 bool changing_in_nbases_dialog, changing_in_fp_dialog;
92 
93 extern GtkWidget *tabs, *expander_keypad, *expander_history, *expander_stack, *expander_convert;
94 extern GtkEntryCompletion *completion;
95 extern GtkWidget *completion_view, *completion_window, *completion_scrolled;
96 extern GtkListStore *completion_store;
97 extern GtkTreeModel *completion_filter, *completion_sort;
98 
99 extern unordered_map<size_t, GtkWidget*> cal_year, cal_month, cal_day, cal_label;
100 extern GtkWidget *chinese_stem, *chinese_branch;
101 
102 extern GtkCssProvider *expression_provider, *resultview_provider, *statuslabel_l_provider, *statuslabel_r_provider, *keypad_provider, *box_rpnl_provider, *app_provider, *app_provider_theme, *statusframe_provider;
103 
104 extern GtkWidget *expressiontext, *statuslabel_l, *statuslabel_r, *result_bases, *keypad;
105 int two_result_bases_rows = -1;
106 extern GtkTextBuffer *expressionbuffer;
107 extern GtkTextTag *expression_par_tag;
108 extern GtkWidget *f_menu, *v_menu, *u_menu, *u_menu2, *recent_menu;
109 extern KnownVariable *vans[5], *v_memory;
110 MathStructure lastx;
111 extern GtkWidget *tPlotFunctions;
112 extern GtkListStore *tPlotFunctions_store;
113 extern GtkWidget *tFunctionArguments;
114 extern GtkListStore *tFunctionArguments_store;
115 extern GtkWidget *tSubfunctions;
116 extern GtkListStore *tSubfunctions_store;
117 extern GtkWidget *tFunctions, *tFunctionCategories;
118 extern GtkListStore *tFunctions_store;
119 extern GtkTreeModel *tFunctions_store_filter;
120 extern GtkTreeStore *tFunctionCategories_store;
121 extern GtkWidget *tVariables, *tVariableCategories;
122 extern GtkListStore *tVariables_store;
123 extern GtkTreeModel *tVariables_store_filter;
124 extern GtkTreeStore *tVariableCategories_store;
125 extern GtkWidget *tUnits, *tUnitCategories;
126 extern GtkListStore *tUnits_store;
127 extern GtkTreeModel *tUnits_store_filter;
128 extern GtkTreeStore *tUnitCategories_store;
129 extern GtkWidget *tUnitSelectorCategories;
130 extern GtkWidget *tUnitSelector;
131 extern GtkListStore *tUnitSelector_store;
132 extern GtkTreeModel *tUnitSelector_store_filter, *units_convert_filter;
133 extern GtkTreeStore *tUnitSelectorCategories_store;
134 extern GtkWidget *units_convert_view, *units_convert_window, *units_convert_scrolled;
135 extern GtkCellRenderer *units_convert_flag_renderer;
136 extern GtkWidget *tDataObjects, *tDatasets;
137 extern GtkListStore *tDataObjects_store, *tDatasets_store;
138 extern GtkWidget *tDataProperties;
139 extern GtkListStore *tDataProperties_store;
140 extern GtkWidget *tNames;
141 extern GtkListStore *tNames_store;
142 extern GtkWidget *tShortcuts, *tShortcutsType;
143 extern GtkListStore *tShortcuts_store, *tShortcutsType_store;
144 extern GtkWidget *tButtonsEditType, *tButtonsEdit;
145 extern GtkListStore *tButtonsEditType_store, *tButtonsEdit_store;
146 extern GtkAccelGroup *accel_group;
147 extern string selected_function_category;
148 extern MathFunction *selected_function;
149 extern GtkWidget *item_factorize, *item_simplify;
150 DataObject *selected_dataobject = NULL;
151 DataSet *selected_dataset = NULL;
152 DataProperty *selected_dataproperty = NULL;
153 MathFunction *edited_function = NULL;
154 KnownVariable *edited_variable = NULL;
155 UnknownVariable *edited_unknown = NULL;
156 KnownVariable *edited_matrix = NULL;
157 Unit *edited_unit = NULL;
158 DataSet *edited_dataset = NULL;
159 DataProperty *edited_dataproperty = NULL;
160 bool editing_variable = false, editing_unknown = false, editing_matrix = false, editing_unit = false, editing_function = false, editing_dataset = false, editing_dataproperty = false;
161 size_t selected_subfunction;
162 size_t last_subfunction_index;
163 Argument *selected_argument;
164 Argument *edited_argument;
165 extern string selected_variable_category;
166 extern Variable *selected_variable;
167 extern string selected_unit_category;
168 extern string selected_unit_selector_category;
169 extern Unit *selected_unit;
170 extern Unit *selected_to_unit;
171 bool save_mode_on_exit;
172 bool save_defs_on_exit;
173 bool clear_history_on_exit = false;
174 int use_dark_theme = -1;
175 bool use_custom_result_font, use_custom_expression_font, use_custom_status_font, use_custom_keypad_font, use_custom_app_font;
176 bool save_custom_result_font = false, save_custom_expression_font = false, save_custom_status_font = false, save_custom_keypad_font = false, save_custom_app_font = false;
177 string custom_result_font, custom_expression_font, custom_status_font, custom_keypad_font, custom_app_font;
178 int scale_n = 0;
179 bool hyp_is_on, inv_is_on;
180 bool show_keypad, show_history, show_stack, show_convert, continuous_conversion, set_missing_prefixes, persistent_keypad, minimal_mode;
181 bool copy_separator;
182 bool caret_as_xor = false;
183 extern bool load_global_defs, fetch_exchange_rates_at_startup, first_time, showing_first_time_message;
184 extern int allow_multiple_instances;
185 int b_decimal_comma;
186 int auto_update_exchange_rates;
187 bool first_error;
188 bool display_expression_status;
189 bool block_unit_convert, block_unit_selector_convert;
190 extern MathStructure *mstruct, *matrix_mstruct, *parsed_mstruct, *parsed_tostruct, *displayed_mstruct;
191 MathStructure mbak_convert;
192 extern string result_text, parsed_text;
193 string previous_expression;
194 bool result_text_approximate = false;
195 string result_text_long;
196 extern GtkWidget *resultview;
197 extern GtkWidget *historyview;
198 extern GtkWidget *stackview;
199 extern GtkListStore *stackstore, *historystore;
200 extern GtkCellRenderer *register_renderer;
201 extern GtkTreeViewColumn *register_column, *history_column, *history_index_column, *flag_column, *units_flag_column;
202 extern cairo_surface_t *surface_result;
203 gint history_width_e = 0, history_width_a = 0;
204 vector<vector<GtkWidget*> > insert_element_entries;
205 bool b_busy, b_busy_command, b_busy_result, b_busy_expression, b_busy_fetch;
206 cairo_surface_t *tmp_surface;
207 bool expression_has_changed = false, current_object_has_changed = false, expression_has_changed2 = false, expression_has_changed_pos = false;
208 int block_result_update = 0, block_expression_execution = 0, block_display_parse = 0;
209 string parsed_expression;
210 bool parsed_had_errors = false, parsed_had_warnings = false;
211 vector<DataProperty*> tmp_props;
212 vector<DataProperty*> tmp_props_orig;
213 bool keep_unit_selection = false;
214 int visible_keypad = 0, previous_keypad = 0;
215 int programming_inbase = 0, programming_outbase = 0;
216 bool title_modified = false;
217 string current_mode;
218 
219 bool cursor_has_moved = false;
220 
221 string prev_output_base, prev_input_base;
222 
223 string command_convert_units_string;
224 Unit *command_convert_unit;
225 
226 int block_conversion_category_switch = 0;
227 
228 extern GtkWidget *tMatrixEdit, *tMatrix;
229 extern GtkListStore *tMatrixEdit_store, *tMatrix_store;
230 vector<GtkTreeViewColumn*> matrix_edit_columns, matrix_columns;
231 
232 extern GtkAccelGroup *accel_group;
233 
234 extern gint win_height, win_width, win_x, win_y, history_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;
235 bool remember_position = false;
236 
237 gint minimal_width;
238 
239 vector<string> expression_history;
240 int expression_history_index = -1;
241 bool dont_change_index = false;
242 bool result_font_updated = false;
243 bool first_draw_of_result = true;
244 
245 PlotLegendPlacement default_plot_legend_placement = PLOT_LEGEND_TOP_RIGHT;
246 bool default_plot_display_grid = true;
247 bool default_plot_full_border = false;
248 string default_plot_min = "0";
249 string default_plot_max = "10";
250 string default_plot_step = "1";
251 int default_plot_sampling_rate = 100;
252 int default_plot_linewidth = 2;
253 bool default_plot_use_sampling_rate = true;
254 bool default_plot_rows = false;
255 int default_plot_type = 0;
256 PlotStyle default_plot_style = PLOT_STYLE_LINES;
257 PlotSmoothing default_plot_smoothing = PLOT_SMOOTHING_NONE;
258 string default_plot_variable = "x";
259 bool default_plot_color = true;
260 int max_plot_time = 5;
261 
262 bool b_editing_stack = false;
263 
264 string status_error_color, status_warning_color;
265 
266 string nbases_error_color, nbases_warning_color;
267 
268 bool names_edited = false;
269 
270 gint current_object_start = -1, current_object_end = -1;
271 MathFunction *current_function = NULL;
272 size_t current_function_index = 0;
273 bool editing_to_expression = false, editing_to_expression1 = false;
274 bool stop_timeouts = false;
275 
276 PrintOptions printops, parse_printops, displayed_printops;
277 bool displayed_caf = false;
278 EvaluationOptions evalops;
279 
280 bool rpn_mode, rpn_keys;
281 bool adaptive_interval_display;
282 bool use_e_notation;
283 
284 bool tc_set = false;
285 
286 bool use_systray_icon = false, hide_on_startup = false;
287 
288 extern Thread *view_thread, *command_thread;
289 bool exit_in_progress = false, command_aborted = false, display_aborted = false, result_too_long = false;
290 
291 vector<mode_struct> modes;
292 vector<GtkWidget*> mode_items;
293 vector<GtkWidget*> popup_result_mode_items;
294 vector<GtkWidget*> popup_expression_mode_items;
295 GtkMenu *popup_menu_expressiontext;
296 
297 deque<string> inhistory;
298 deque<bool> inhistory_protected;
299 deque<int> inhistory_type;
300 deque<int> inhistory_value;
301 vector<MathStructure*> history_parsed;
302 vector<MathStructure*> history_answer;
303 
304 deque<string> expression_undo_buffer;
305 size_t undo_index = 0;
306 int block_add_to_undo = 0;
307 
308 int current_inhistory_index = -1;
309 int history_index = 0;
310 int initial_inhistory_index = 0;
311 int nr_of_new_expressions = 0;
312 
313 int expression_lines = -1;
314 
315 unordered_map<void*, string> date_map;
316 unordered_map<void*, bool> date_approx_map;
317 unordered_map<void*, string> number_map;
318 unordered_map<void*, string> number_base_map;
319 unordered_map<void*, bool> number_approx_map;
320 unordered_map<void*, string> number_exp_map;
321 unordered_map<void*, bool> number_exp_minus_map;
322 
323 unordered_map<string, GdkPixbuf*> flag_images;
324 
325 extern MathFunction *f_answer;
326 extern MathFunction *f_expression;
327 
328 unordered_map<string, GtkTreeIter> convert_category_map;
329 
330 extern gchar history_error_color[8];
331 extern gchar history_warning_color[8];
332 extern gchar history_parse_color[8];
333 extern gchar history_bookmark_color[8];
334 
335 bool status_error_color_set;
336 bool status_warning_color_set;
337 
338 string old_fromValue, old_toValue;
339 
340 guint completion_timeout_id = 0;
341 int completion_delay = 0;
342 
343 extern QalculateDateTime last_version_check_date;
344 string last_found_version;
345 
346 int completion_min = 1, completion_min2 = 2;
347 bool enable_completion = true, enable_completion2 = true;
348 
349 bool keep_function_dialog_open = false;
350 
351 bool automatic_fraction = false;
352 int default_fraction_fraction = -1;
353 bool scientific_negexp = true;
354 bool scientific_notminuslast = true;
355 bool scientific_noprefix = true;
356 int auto_prefix = 0;
357 
358 bool ignore_locale = false;
359 
360 bool hexadecimal_twos_complement_in = false, twos_complement_in = false;
361 
362 int default_signed = -1;
363 int default_bits = -1;
364 
365 string result_bin, result_oct, result_dec, result_hex;
366 Number max_bases, min_bases;
367 
368 vector<string> history_bookmarks;
369 unordered_map<string, size_t> history_bookmark_titles;
370 
371 bool versatile_exact = false;
372 
373 bool auto_calculate = false;
374 bool result_autocalculated = false;
375 gint autocalc_history_timeout_id = 0;
376 gint autocalc_history_delay = 2000;
377 bool chain_mode = false;
378 
379 bool to_fraction = false;
380 char to_prefix = 0;
381 int to_base = 0;
382 int to_caf = -1;
383 unsigned int to_bits = 0;
384 Number to_nbase;
385 
386 extern bool do_imaginary_j;
387 bool complex_angle_form = false;
388 
389 unordered_map<guint64, keyboard_shortcut> keyboard_shortcuts;
390 vector<custom_button> custom_buttons;
391 
392 bool default_shortcuts;
393 
394 extern bool check_version;
395 
396 guint32 current_shortcut_key = 0;
397 guint32 current_shortcut_modifier = 0;
398 
399 PangoLayout *status_layout = NULL;
400 
401 #define THIN_SPACE " "
402 
403 #define TEXT_TAGS			"<span size=\"xx-large\">"
404 #define TEXT_TAGS_END			"</span>"
405 #define TEXT_TAGS_SMALL			"<span size=\"large\">"
406 #define TEXT_TAGS_SMALL_END		"</span>"
407 #define TEXT_TAGS_XSMALL		"<span size=\"medium\">"
408 #define TEXT_TAGS_XSMALL_END		"</span>"
409 
410 #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\">";}
411 #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\">";}
412 #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\">";}
413 #define TTBP(str)			if(ips.power_depth > 1) {TTB_XSMALL(str);} else if(ips.power_depth > 0) {TTB_SMALL(str);} else {TTB(str);}
414 #define TTBP_SMALL(str)			if(ips.power_depth > 0) {TTB_XSMALL(str);} else {TTB_SMALL(str);}
415 #define TTE(str)			str += "</span>";
416 #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>";}
417 #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>";}
418 #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>";}
419 #define TTP(str, x)			if(ips.power_depth > 1) {TT_XSMALL(str, x);} else if(ips.power_depth > 0) {TT_SMALL(str, x);} else {TT(str, x);}
420 #define TTP_SMALL(str, x)		if(ips.power_depth > 0) {TT_XSMALL(str, x);} else {TT_SMALL(str, x);}
421 
422 #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);}
423 #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);}
424 #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);}
425 #define PANGO_TTP(layout, x)		if(ips.power_depth > 1) {PANGO_TT_XSMALL(layout, x);} else if(ips.power_depth > 0) {PANGO_TT_SMALL(layout, x);} else {PANGO_TT(layout, x);}
426 #define PANGO_TTP_SMALL(layout, x)	if(ips.power_depth > 0) {PANGO_TT_XSMALL(layout, x);} else {PANGO_TT_SMALL(layout, x);}
427 
428 #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);
429 
430 #define HISTORY_IS_MESSAGE(x) (inhistory_type[x] == QALCULATE_HISTORY_MESSAGE || inhistory_type[x] == QALCULATE_HISTORY_ERROR || inhistory_type[x] == QALCULATE_HISTORY_WARNING)
431 #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)
432 #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)
433 #define HISTORY_NOT_MESSAGE(x) (inhistory_type[x] != QALCULATE_HISTORY_MESSAGE && inhistory_type[x] != QALCULATE_HISTORY_ERROR && inhistory_type[x] != QALCULATE_HISTORY_WARNING)
434 #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)
435 #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)
436 #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)) || ((size_t) x < inhistory_type.size() - 2 && HISTORY_IS_MESSAGE(x) && HISTORY_IS_PARSE(x + 1) && HISTORY_IS_EXPRESSION(x + 2) && inhistory[x + 1].empty()))
437 #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)) && ((size_t) x >= inhistory_type.size() - 2 || HISTORY_NOT_MESSAGE(x) || HISTORY_NOT_PARSE(x + 1) || HISTORY_NOT_EXPRESSION(x + 2) || !inhistory[x + 1].empty()))
438 
439 enum {
440 	TITLE_APP,
441 	TITLE_RESULT,
442 	TITLE_APP_RESULT,
443 	TITLE_MODE,
444 	TITLE_APP_MODE
445 };
446 
447 int title_type = TITLE_APP;
448 
string_strdown(const string & str,string & strnew)449 void string_strdown(const string &str, string &strnew) {
450 	char *cstr = utf8_strdown(str.c_str());
451 	if(cstr) {
452 		strnew = cstr;
453 		free(cstr);
454 	} else {
455 		strnew = str;
456 	}
457 }
458 
AnswerFunction()459 AnswerFunction::AnswerFunction() : MathFunction(_("answer"), 1, 1, CALCULATOR->f_warning->category(), _("History Answer Value")) {
460 	if(strcmp(_("answer"), "answer")) addName("answer");
461 	VectorArgument *arg = new VectorArgument(_("History Index(es)"));
462 	arg->addArgument(new IntegerArgument("", ARGUMENT_MIN_MAX_NONZERO, true, true, INTEGER_TYPE_SINT));
463 	setArgumentDefinition(1, arg);
464 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)465 int AnswerFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
466 	if(vargs[0].size() == 0) return 0;
467 	if(vargs[0].size() > 1) mstruct.clearVector();
468 	for(size_t i = 0; i < vargs[0].size(); i++) {
469 		int index = vargs[0][i].number().intValue();
470 		if(index < 0) index = (int) history_answer.size() + 1 + index;
471 		if(index <= 0 || index > (int) history_answer.size() || history_answer[(size_t) index - 1] == NULL) {
472 			CALCULATOR->error(true, _("History index %s does not exist."), vargs[0][i].print().c_str(), NULL);
473 			if(vargs[0].size() == 1) mstruct.setUndefined();
474 			else mstruct.addChild(m_undefined);
475 		} else {
476 			if(vargs[0].size() == 1) mstruct.set(*history_answer[(size_t) index - 1]);
477 			else mstruct.addChild(*history_answer[(size_t) index - 1]);
478 		}
479 	}
480 	return 1;
481 }
ExpressionFunction()482 ExpressionFunction::ExpressionFunction() : MathFunction(_("expression"), 1, 1, CALCULATOR->f_warning->category(), _("History Parsed Expression")) {
483 	if(strcmp(_("expression"), "expression")) addName("expression");
484 	VectorArgument *arg = new VectorArgument(_("History Index(es)"));
485 	arg->addArgument(new IntegerArgument("", ARGUMENT_MIN_MAX_NONZERO, true, true, INTEGER_TYPE_SINT));
486 	setArgumentDefinition(1, arg);
487 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)488 int ExpressionFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
489 	if(vargs[0].size() == 0) return 0;
490 	if(vargs[0].size() > 1) mstruct.clearVector();
491 	for(size_t i = 0; i < vargs[0].size(); i++) {
492 		int index = vargs[0][i].number().intValue();
493 		if(index < 0) index = (int) history_parsed.size() + 1 + index;
494 		if(index <= 0 || index > (int) history_parsed.size() || history_parsed[(size_t) index - 1] == NULL) {
495 			CALCULATOR->error(true, _("History index %s does not exist."), vargs[0][i].print().c_str(), NULL);
496 			if(vargs[0].size() == 1) mstruct.setUndefined();
497 			else mstruct.addChild(m_undefined);
498 		} else {
499 			if(vargs[0].size() == 1) mstruct.set(*history_parsed[(size_t) index - 1]);
500 			else mstruct.addChild(*history_parsed[(size_t) index - 1]);
501 		}
502 	}
503 	return 1;
504 }
SetTitleFunction()505 SetTitleFunction::SetTitleFunction() : MathFunction("settitle", 1, 1, CALCULATOR->f_warning->category(), _("Set Window Title")) {
506 	setArgumentDefinition(1, new TextArgument());
507 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)508 int SetTitleFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
509 	gtk_window_set_title(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), vargs[0].symbol().c_str());
510 	title_modified = true;
511 	return 1;
512 }
513 
514 void executeCommand(int command_type, bool show_result = true, string ceu_str = "", Unit *u = NULL, int run = 1);
515 
has_information_unit_gtk(const MathStructure & m,bool top=true)516 int has_information_unit_gtk(const MathStructure &m, bool top = true) {
517 	if(m.isUnit_exp()) {
518 		if(m.isUnit()) {
519 			if(m.unit()->baseUnit()->referenceName() == "bit") return 1;
520 		} else {
521 			if(m[0].unit()->baseUnit()->referenceName() == "bit") {
522 				if(m[1].isInteger() && m[1].number().isPositive()) return 1;
523 				return 2;
524 			}
525 		}
526 		return 0;
527 	}
528 	for(size_t i = 0; i < m.size(); i++) {
529 		int ret = has_information_unit_gtk(m[i], false);
530 		if(ret > 0) {
531 			if(ret == 1 && top && m.isMultiplication() && m[0].isNumber() && m[0].number().isFraction()) return 2;
532 			return ret;
533 		}
534 	}
535 	return 0;
536 }
537 
print_with_evalops(const Number & nr)538 string print_with_evalops(const Number &nr) {
539 	PrintOptions po;
540 	po.base = evalops.parse_options.base;
541 	po.base_display = BASE_DISPLAY_NONE;
542 	po.twos_complement = evalops.parse_options.twos_complement;
543 	Number nr_base;
544 	if(po.base == BASE_CUSTOM) {
545 		nr_base = CALCULATOR->customOutputBase();
546 		CALCULATOR->setCustomOutputBase(CALCULATOR->customInputBase());
547 	}
548 	if(po.base == BASE_CUSTOM && CALCULATOR->customInputBase().isInteger() && (CALCULATOR->customInputBase() > 1 || CALCULATOR->customInputBase() < -1)) {
549 		nr_base = CALCULATOR->customOutputBase();
550 		CALCULATOR->setCustomOutputBase(CALCULATOR->customInputBase());
551 	} 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)) {
552 		po.base = 10;
553 		string str = "dec(";
554 		str += nr.print(po);
555 		str += ")";
556 		return str;
557 	} else if(po.base == BASE_CUSTOM) {
558 		po.base = 10;
559 	}
560 	string str = nr.print(po);
561 	if(po.base == BASE_CUSTOM) CALCULATOR->setCustomOutputBase(nr_base);
562 	return str;
563 }
564 
565 enum {
566 	COMMAND_FACTORIZE,
567 	COMMAND_EXPAND_PARTIAL_FRACTIONS,
568 	COMMAND_EXPAND,
569 	COMMAND_TRANSFORM,
570 	COMMAND_CONVERT_UNIT,
571 	COMMAND_CONVERT_STRING,
572 	COMMAND_CONVERT_BASE,
573 	COMMAND_CONVERT_OPTIMAL,
574 	COMMAND_CALCULATE,
575 	COMMAND_EVAL
576 };
577 
578 void add_line_breaks(string &str, int expr = false, size_t first_i = 0);
579 
equalsIgnoreCase(const string & str1,const string & str2,size_t i2,size_t i2_end,size_t minlength)580 bool equalsIgnoreCase(const string &str1, const string &str2, size_t i2, size_t i2_end, size_t minlength) {
581 	if(str1.empty() || str2.empty()) return false;
582 	size_t l = 0;
583 	if(i2_end == string::npos) i2_end = str2.length();
584 	for(size_t i1 = 0;; i1++, i2++) {
585 		if(i2 >= i2_end) {
586 			return i1 >= str1.length();
587 		}
588 		if(i1 >= str1.length()) break;
589 		if((str1[i1] < 0 && i1 + 1 < str1.length()) || (str2[i2] < 0 && i2 + 1 < str2.length())) {
590 			size_t iu1 = 1, iu2 = 1;
591 			if(str1[i1] < 0) {
592 				while(iu1 + i1 < str1.length() && str1[i1 + iu1] < 0) {
593 					iu1++;
594 				}
595 			}
596 			if(str2[i2] < 0) {
597 				while(iu2 + i2 < str2.length() && str2[i2 + iu2] < 0) {
598 					iu2++;
599 				}
600 			}
601 			bool isequal = (iu1 == iu2);
602 			if(isequal) {
603 				for(size_t i = 0; i < iu1; i++) {
604 					if(str1[i1 + i] != str2[i2 + i]) {
605 						isequal = false;
606 						break;
607 					}
608 				}
609 			}
610 			if(!isequal) {
611 				char *gstr1 = utf8_strdown(str1.c_str() + (sizeof(char) * i1), iu1);
612 				char *gstr2 = utf8_strdown(str2.c_str() + (sizeof(char) * i2), iu2);
613 				if(!gstr1 || !gstr2) return false;
614 				bool b = strcmp(gstr1, gstr2) == 0;
615 				free(gstr1);
616 				free(gstr2);
617 				if(!b) return false;
618 			}
619 			i1 += iu1 - 1;
620 			i2 += iu2 - 1;
621 		} 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])) {
622 			return false;
623 		}
624 		l++;
625 	}
626 	return l >= minlength;
627 }
628 
title_matches(ExpressionItem * item,const string & str,size_t minlength=0)629 bool title_matches(ExpressionItem *item, const string &str, size_t minlength = 0) {
630 	bool big_A = false;
631 	if(minlength > 1 && str.length() == 1) {
632 		if(str[0] == 'a' || str[0] == 'x' || str[0] == 'y' || str[0] == 'X' || str[0] == 'Y') return false;
633 		big_A = (str[0] == 'A');
634 	}
635 	const string &title = item->title(true);
636 	size_t i = 0;
637 	while(true) {
638 		while(true) {
639 			if(i >= title.length()) return false;
640 			if(title[i] != ' ') break;
641 			i++;
642 		}
643 		size_t i2 = title.find(' ', i);
644 		if(big_A && title[i] == str[0] && ((i2 == string::npos && i == title.length() - 1) || i2 - i == 1)) {
645 			return true;
646 		} else if(!big_A && equalsIgnoreCase(str, title, i, i2, minlength)) {
647 			return true;
648 		}
649 		if(i2 == string::npos) break;
650 		i = i2 + 1;
651 	}
652 	return false;
653 }
name_matches(ExpressionItem * item,const string & str)654 bool name_matches(ExpressionItem *item, const string &str) {
655 	for(size_t i2 = 1; i2 <= item->countNames(); i2++) {
656 		if(item->getName(i2).case_sensitive) {
657 			if(str == item->getName(i2).name.substr(0, str.length())) {
658 				return true;
659 			}
660 		} else {
661 			if(equalsIgnoreCase(str, item->getName(i2).name, 0, str.length(), 0)) {
662 				return true;
663 			}
664 		}
665 	}
666 	return false;
667 }
name_matches2(ExpressionItem * item,const string & str,size_t minlength,size_t * i_match=NULL)668 int name_matches2(ExpressionItem *item, const string &str, size_t minlength, size_t *i_match = NULL) {
669 	if(minlength > 1 && unicode_length(str) == 1) return 0;
670 	bool b_match = false;
671 	for(size_t i2 = 1; i2 <= item->countNames(); i2++) {
672 		if(equalsIgnoreCase(str, item->getName(i2).name, 0, str.length(), 0)) {
673 			if(!item->getName(i2).case_sensitive && item->getName(i2).name.length() == str.length()) {
674 				if(i_match) *i_match = i2;
675 				return 1;
676 			}
677 			if(i_match && *i_match == 0) *i_match = i2;
678 			b_match = true;
679 		}
680 	}
681 	return b_match ? 2 : 0;
682 }
country_matches(Unit * u,const string & str,size_t minlength=0)683 bool country_matches(Unit *u, const string &str, size_t minlength = 0) {
684 	const string &countries = u->countries();
685 	size_t i = 0;
686 	while(true) {
687 		while(true) {
688 			if(i >= countries.length()) return false;
689 			if(countries[i] != ' ') break;
690 			i++;
691 		}
692 		size_t i2 = countries.find(',', i);
693 		if(equalsIgnoreCase(str, countries, i, i2, minlength)) {
694 			return true;
695 		}
696 		if(i2 == string::npos) break;
697 		i = i2 + 1;
698 	}
699 	return false;
700 }
completion_names_match(string name,const string & str,size_t minlength=0,size_t * i_match=NULL)701 int completion_names_match(string name, const string &str, size_t minlength = 0, size_t *i_match = NULL) {
702 	size_t i = 0, n = 0;
703 	bool b_match = false;
704 	while(true) {
705 		size_t i2 = name.find(i == 0 ? " <i>" : "</i>", i);
706 		if(equalsIgnoreCase(str, name, i, i2, minlength)) {
707 			if((i2 == string::npos && name.length() - i == str.length()) || (i2 != string::npos && i2 - i == str.length())) {
708 				if(i_match) *i_match = n;
709 				return 1;
710 			}
711 			if(i_match && *i_match == 0) *i_match = n;
712 			b_match = true;
713 		}
714 		if(i2 == string::npos) break;
715 		if(i == 0) {
716 			i = i2 + 4;
717 		} else {
718 			i = name.find("<i>", i2);
719 			if(i == string::npos) break;
720 			i += 3;
721 		}
722 		n++;
723 	}
724 	return (b_match ? 2 : 0);
725 }
726 
remove_separator(string & copy_text)727 void remove_separator(string &copy_text) {
728 	for(size_t i = ((CALCULATOR->local_digit_group_separator.empty() || CALCULATOR->local_digit_group_separator == " ") ? 1 : 0); i < 3; i++) {
729 		string str_sep;
730 		if(i == 0) str_sep = CALCULATOR->local_digit_group_separator;
731 		else if(i == 1) str_sep = THIN_SPACE;
732 		else str_sep = " ";
733 		size_t index = copy_text.find(str_sep);
734 		while(index != string::npos) {
735 			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') {
736 				copy_text.erase(index, str_sep.length());
737 			} else {
738 				index++;
739 			}
740 			index = copy_text.find(str_sep, index);
741 		}
742 	}
743 }
744 
745 gint help_width = -1, help_height = -1;
746 gdouble help_zoom = -1.0;
747 
get_doc_uri(string file,bool with_proto=true)748 string get_doc_uri(string file, bool with_proto = true) {
749 	string surl;
750 #ifndef LOCAL_HELP
751 	surl = "https://qalculate.github.io/manual/";
752 	surl += file;
753 #else
754 	if(with_proto) surl += "file://";
755 #	ifdef _WIN32
756 	char exepath[MAX_PATH];
757 	GetModuleFileName(NULL, exepath, MAX_PATH);
758 	surl += exepath;
759 	surl.resize(surl.find_last_of('\\'));
760 	if(surl.substr(surl.length() - 4) == "\\bin") {
761 		surl.resize(surl.find_last_of('\\'));
762 		surl += "\\share\\doc\\";
763 		surl += PACKAGE;
764 		surl += "\\html\\";
765 	} else if(surl.substr(surl.length() - 6) == "\\.libs") {
766 		surl.resize(surl.find_last_of('\\'));
767 		surl.resize(surl.find_last_of('\\'));
768 		surl += "\\doc\\html\\";
769 	} else {
770 		surl += "\\doc\\";
771 	}
772 	gsub("\\", "/", surl);
773 	surl += file;
774 #	else
775 	surl += PACKAGE_DOC_DIR "/html/";
776 	surl += file;
777 #	endif
778 #endif
779 	return surl;
780 }
781 
782 #ifdef USE_WEBKITGTK
783 unordered_map<GtkWidget*, GtkWidget*> help_find_entries;
784 bool backwards_search;
on_help_stop_search(GtkSearchEntry * w,gpointer view)785 void on_help_stop_search(GtkSearchEntry *w, gpointer view) {
786 	webkit_find_controller_search_finish(webkit_web_view_get_find_controller(WEBKIT_WEB_VIEW(view)));
787 	gtk_entry_set_text(GTK_ENTRY(w), "");
788 }
on_help_search_found(WebKitFindController *,guint,gpointer)789 void on_help_search_found(WebKitFindController*, guint, gpointer) {
790 	backwards_search = false;
791 }
792 vector<string> help_files;
793 vector<string> help_contents;
on_help_search_failed(WebKitFindController * f,gpointer w)794 void on_help_search_failed(WebKitFindController *f, gpointer w) {
795 	g_signal_handlers_disconnect_matched((gpointer) f, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_help_search_failed, NULL);
796 	string str = gtk_entry_get_text(GTK_ENTRY(help_find_entries[GTK_WIDGET(w)]));
797 	remove_blank_ends(str);
798 	remove_duplicate_blanks(str);
799 	if(str.empty()) return;
800 	string strl;
801 	string_strdown(str, strl);
802 	gsub("&", "&amp;", strl);
803 	gsub(">", "&gt;", strl);
804 	gsub("<", "&lt;", strl);
805 	if(!webkit_web_view_get_uri(WEBKIT_WEB_VIEW(w))) return;
806 	string file = webkit_web_view_get_uri(WEBKIT_WEB_VIEW(w));
807 	size_t i = file.rfind("/");
808 	if(i != string::npos) file = file.substr(i + 1);
809 	i = file.find("#");
810 	if(i != string::npos) file = file.substr(0, i);
811 	size_t help_i = 0;
812 	if(help_files.empty()) {
813 		ifstream ifile(get_doc_uri("index.html", false).c_str());
814 		if(!ifile.is_open()) return;
815 		std::stringstream ssbuffer;
816 		ssbuffer << ifile.rdbuf();
817 		string sbuffer;
818 		string_strdown(ssbuffer.str(), sbuffer);
819 		ifile.close();
820 		help_files.push_back("index.html");
821 		help_contents.push_back(sbuffer);
822 		i = sbuffer.find(".html\"");
823 		while(i != string::npos) {
824 			size_t i2 = sbuffer.rfind("\"", i);
825 			if(i2 != string::npos) {
826 				string sfile = sbuffer.substr(i2 + 1, (i + 5) - (i2 + 1));
827 				if(sfile.find("/") == string::npos) {
828 					for(i2 = 0; i2 < help_files.size(); i2++) {
829 						if(help_files[i2] == sfile) break;
830 					}
831 					if(i2 == help_files.size()) {
832 						help_files.push_back(sfile);
833 						ifstream ifile_i(get_doc_uri(sfile, false).c_str());
834 						string sbuffer_i;
835 						if(ifile_i.is_open()) {
836 							std::stringstream ssbuffer_i;
837 							ssbuffer_i << ifile_i.rdbuf();
838 							string_strdown(ssbuffer_i.str(), sbuffer_i);
839 							ifile_i.close();
840 						}
841 						help_contents.push_back(sbuffer_i);
842 					}
843 				}
844 			}
845 			i = sbuffer.find(".html\"", i + 1);
846 		}
847 	}
848 	for(i = 0; i < help_files.size(); i++) {
849 		if(file == help_files[i]) {
850 			help_i = i;
851 			break;
852 		}
853 	}
854 	size_t help_cur = help_i;
855 	while(true) {
856 		if(backwards_search) {
857 			if(help_i == 0) help_i = help_files.size() - 1;
858 			else help_i--;
859 		} else {
860 			help_i++;
861 			if(help_i == help_files.size()) help_i = 0;
862 		}
863 		if(help_i == help_cur) {
864 			webkit_find_controller_search(f, str.c_str(), backwards_search ? WEBKIT_FIND_OPTIONS_BACKWARDS | WEBKIT_FIND_OPTIONS_CASE_INSENSITIVE : WEBKIT_FIND_OPTIONS_CASE_INSENSITIVE, 10000);
865 			backwards_search = false;
866 			break;
867 		}
868 		string sbuffer = help_contents[help_i];
869 		i = sbuffer.find("<body");
870 		while(i != string::npos) {
871 			i = sbuffer.find(strl, i + 1);
872 			if(i == string::npos) break;
873 			size_t i2 = sbuffer.find_last_of("<>", i);
874 			if(i2 != string::npos && sbuffer[i2] == '>') {
875 				webkit_web_view_load_uri(WEBKIT_WEB_VIEW(w), get_doc_uri(help_files[help_i]).c_str());
876 				break;
877 			}
878 			i = sbuffer.find(">", i);
879 		}
880 		if(i != string::npos) break;
881 	}
882 }
on_help_search_changed(GtkSearchEntry * w,gpointer view)883 void on_help_search_changed(GtkSearchEntry *w, gpointer view) {
884 	string str = gtk_entry_get_text(GTK_ENTRY(w));
885 	remove_blank_ends(str);
886 	remove_duplicate_blanks(str);
887 	if(str.empty()) {
888 		webkit_find_controller_search_finish(webkit_web_view_get_find_controller(WEBKIT_WEB_VIEW(view)));
889 	} else {
890 		g_signal_handlers_disconnect_matched((gpointer) webkit_web_view_get_find_controller(WEBKIT_WEB_VIEW(view)), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_help_search_failed, NULL);
891 		webkit_find_controller_search(webkit_web_view_get_find_controller(WEBKIT_WEB_VIEW(view)), str.c_str(), WEBKIT_FIND_OPTIONS_CASE_INSENSITIVE, 10000);
892 	}
893 }
on_help_next_match(GtkWidget *,gpointer view)894 void on_help_next_match(GtkWidget*, gpointer view) {
895 	backwards_search = false;
896 	g_signal_handlers_disconnect_matched((gpointer) webkit_web_view_get_find_controller(WEBKIT_WEB_VIEW(view)), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_help_search_failed, NULL);
897 	g_signal_connect(webkit_web_view_get_find_controller(WEBKIT_WEB_VIEW(view)), "failed-to-find-text", G_CALLBACK(on_help_search_failed), view);
898 	webkit_find_controller_search_next(webkit_web_view_get_find_controller(WEBKIT_WEB_VIEW(view)));
899 }
on_help_previous_match(GtkWidget *,gpointer view)900 void on_help_previous_match(GtkWidget*, gpointer view) {
901 	backwards_search = true;
902 	g_signal_handlers_disconnect_matched((gpointer) webkit_web_view_get_find_controller(WEBKIT_WEB_VIEW(view)), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_help_search_failed, NULL);
903 	g_signal_connect(webkit_web_view_get_find_controller(WEBKIT_WEB_VIEW(view)), "failed-to-find-text", G_CALLBACK(on_help_search_failed), view);
904 	webkit_find_controller_search_previous(webkit_web_view_get_find_controller(WEBKIT_WEB_VIEW(view)));
905 }
on_help_configure_event(GtkWidget *,GdkEventConfigure * event,gpointer)906 gboolean on_help_configure_event(GtkWidget*, GdkEventConfigure *event, gpointer) {
907 	if(help_width != -1 || event->width != 800 || event->height != 600) {
908 		help_width = event->width;
909 		help_height = event->height;
910 	}
911 	return FALSE;
912 }
on_help_key_press_event(GtkWidget * d,GdkEventKey * event,gpointer w)913 gboolean on_help_key_press_event(GtkWidget *d, GdkEventKey *event, gpointer w) {
914 	GtkWidget *entry_find = help_find_entries[GTK_WIDGET(w)];
915 	switch(event->keyval) {
916 		case GDK_KEY_Escape: {
917 			string str = gtk_entry_get_text(GTK_ENTRY(entry_find));
918 			remove_blank_ends(str);
919 			remove_duplicate_blanks(str);
920 			if(str.empty()) {
921 				gtk_widget_destroy(d);
922 			} else {
923 				on_help_stop_search(GTK_SEARCH_ENTRY(entry_find), w);
924 				return TRUE;
925 			}
926 			return TRUE;
927 		}
928 		case GDK_KEY_BackSpace: {
929 			if(gtk_widget_has_focus(entry_find)) return FALSE;
930 			webkit_web_view_go_back(WEBKIT_WEB_VIEW(w));
931 			return TRUE;
932 		}
933 		case GDK_KEY_Left: {
934 			if(event->state & GDK_CONTROL_MASK || event->state & GDK_MOD1_MASK) {
935 				webkit_web_view_go_back(WEBKIT_WEB_VIEW(w));
936 				return TRUE;
937 			}
938 			break;
939 		}
940 		case GDK_KEY_Right: {
941 			if(event->state & GDK_CONTROL_MASK || event->state & GDK_MOD1_MASK) {
942 				webkit_web_view_go_forward(WEBKIT_WEB_VIEW(w));
943 				return TRUE;
944 			}
945 			break;
946 		}
947 		case GDK_KEY_KP_Add: {}
948 		case GDK_KEY_plus: {
949 			if(event->state & GDK_CONTROL_MASK || event->state & GDK_MOD1_MASK) {
950 				help_zoom = webkit_web_view_get_zoom_level(WEBKIT_WEB_VIEW(w)) + 0.1;
951 				webkit_web_view_set_zoom_level(WEBKIT_WEB_VIEW(w), help_zoom);
952 				return TRUE;
953 			}
954 			break;
955 		}
956 		case GDK_KEY_KP_Subtract: {}
957 		case GDK_KEY_minus: {
958 			if((event->state & GDK_CONTROL_MASK || event->state & GDK_MOD1_MASK) && webkit_web_view_get_zoom_level(WEBKIT_WEB_VIEW(w)) > 0.1) {
959 				help_zoom = webkit_web_view_get_zoom_level(WEBKIT_WEB_VIEW(w)) - 0.1;
960 				webkit_web_view_set_zoom_level(WEBKIT_WEB_VIEW(w), help_zoom);
961 				return TRUE;
962 			}
963 			break;
964 		}
965 		case GDK_KEY_Home: {
966 			if(event->state & GDK_CONTROL_MASK || event->state & GDK_MOD1_MASK) {
967 				webkit_web_view_load_uri(WEBKIT_WEB_VIEW(w), get_doc_uri("index.html").c_str());
968 				return TRUE;
969 			}
970 			break;
971 		}
972 		case GDK_KEY_f: {
973 			if(event->state & GDK_CONTROL_MASK) {
974 				gtk_widget_grab_focus(GTK_WIDGET(entry_find));
975 				return TRUE;
976 			}
977 			break;
978 		}
979 	}
980 	return FALSE;
981 }
on_help_button_home_clicked(GtkButton *,gpointer w)982 void on_help_button_home_clicked(GtkButton*, gpointer w) {
983 	webkit_web_view_load_uri(WEBKIT_WEB_VIEW(w), get_doc_uri("index.html").c_str());
984 }
on_help_button_zoomin_clicked(GtkButton *,gpointer w)985 void on_help_button_zoomin_clicked(GtkButton*, gpointer w) {
986 	help_zoom = webkit_web_view_get_zoom_level(WEBKIT_WEB_VIEW(w)) + 0.1;
987 	webkit_web_view_set_zoom_level(WEBKIT_WEB_VIEW(w), help_zoom);
988 }
on_help_button_zoomout_clicked(GtkButton *,gpointer w)989 void on_help_button_zoomout_clicked(GtkButton*, gpointer w) {
990 	if(webkit_web_view_get_zoom_level(WEBKIT_WEB_VIEW(w)) > 0.1) {
991 		help_zoom = webkit_web_view_get_zoom_level(WEBKIT_WEB_VIEW(w)) - 0.1;
992 		webkit_web_view_set_zoom_level(WEBKIT_WEB_VIEW(w), help_zoom);
993 	}
994 }
on_help_context_menu(WebKitWebView *,WebKitContextMenu *,GdkEvent *,WebKitHitTestResult * hit_test_result,gpointer)995 gboolean on_help_context_menu(WebKitWebView*, WebKitContextMenu*, GdkEvent*, WebKitHitTestResult *hit_test_result, gpointer) {
996 	return webkit_hit_test_result_context_is_image(hit_test_result) || webkit_hit_test_result_context_is_link(hit_test_result) || webkit_hit_test_result_context_is_media(hit_test_result);
997 }
998 
on_help_load_changed_b(WebKitWebView * w,WebKitLoadEvent load_event,gpointer button)999 void on_help_load_changed_b(WebKitWebView *w, WebKitLoadEvent load_event, gpointer button) {
1000 	if(load_event == WEBKIT_LOAD_FINISHED) gtk_widget_set_sensitive(GTK_WIDGET(button), webkit_web_view_can_go_back(w));
1001 }
on_help_load_changed_f(WebKitWebView * w,WebKitLoadEvent load_event,gpointer button)1002 void on_help_load_changed_f(WebKitWebView *w, WebKitLoadEvent load_event, gpointer button) {
1003 	if(load_event == WEBKIT_LOAD_FINISHED) gtk_widget_set_sensitive(GTK_WIDGET(button), webkit_web_view_can_go_forward(w));
1004 }
on_help_load_changed(WebKitWebView * w,WebKitLoadEvent load_event,gpointer)1005 void on_help_load_changed(WebKitWebView *w, WebKitLoadEvent load_event, gpointer) {
1006 	if(load_event == WEBKIT_LOAD_FINISHED) {
1007 		string str = gtk_entry_get_text(GTK_ENTRY(help_find_entries[GTK_WIDGET(w)]));
1008 		remove_blank_ends(str);
1009 		remove_duplicate_blanks(str);
1010 		if(!str.empty()) webkit_find_controller_search(webkit_web_view_get_find_controller(WEBKIT_WEB_VIEW(w)), str.c_str(), backwards_search ? WEBKIT_FIND_OPTIONS_BACKWARDS | WEBKIT_FIND_OPTIONS_CASE_INSENSITIVE : WEBKIT_FIND_OPTIONS_CASE_INSENSITIVE, 10000);
1011 		backwards_search = false;
1012 	}
1013 }
on_help_decide_policy(WebKitWebView * w,WebKitPolicyDecision * d,WebKitPolicyDecisionType t,gpointer window)1014 gboolean on_help_decide_policy(WebKitWebView *w, WebKitPolicyDecision *d, WebKitPolicyDecisionType t, gpointer window) {
1015 	if(t == WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION) {
1016 		const gchar *uri = webkit_uri_request_get_uri(webkit_navigation_action_get_request(webkit_navigation_policy_decision_get_navigation_action (WEBKIT_NAVIGATION_POLICY_DECISION(d))));
1017 		if(uri[0] == 'h' && (uri[4] == ':' || uri[5] == ':')) {
1018 			GError *error = NULL;
1019 #if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 22
1020 			gtk_show_uri_on_window(GTK_WINDOW(window), uri, gtk_get_current_event_time(), &error);
1021 #else
1022 			gtk_show_uri(NULL, uri, gtk_get_current_event_time(), &error);
1023 #endif
1024 			if(error) {
1025 				gchar *error_str = g_locale_to_utf8(error->message, -1, NULL, NULL, NULL);
1026 				GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(window), (GtkDialogFlags) 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("Failed to open %s.\n%s"), uri, error_str);
1027 				gtk_dialog_run(GTK_DIALOG(dialog));
1028 				gtk_widget_destroy(dialog);
1029 				g_free(error_str);
1030 				g_error_free(error);
1031 			}
1032 			webkit_policy_decision_ignore(d);
1033 			return TRUE;
1034 		}
1035 	}
1036 	return FALSE;
1037 }
1038 #endif
1039 
show_help(const char * file,GObject * parent)1040 void show_help(const char *file, GObject *parent) {
1041 #ifdef _WIN32
1042 	if(ShellExecuteA(NULL, "open", get_doc_uri("index.html").c_str(), NULL, NULL, SW_SHOWNORMAL) <= (HINSTANCE) 32) {
1043 		GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(parent), (GtkDialogFlags) 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("Could not display help for Qalculate!."));
1044 		gtk_dialog_run(GTK_DIALOG(dialog));
1045 		gtk_widget_destroy(dialog);
1046 	}
1047 #elif USE_WEBKITGTK
1048 	GtkWidget *dialog = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1049 	gtk_window_set_title(GTK_WINDOW(dialog), "Qalculate! Manual");
1050 	if(parent) {
1051 		gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(parent));
1052 		gtk_window_set_modal(GTK_WINDOW(dialog), gtk_window_get_modal(GTK_WINDOW(parent)));
1053 	}
1054 	gtk_window_set_default_size(GTK_WINDOW(dialog), help_width > 0 ? help_width : 800, help_height > 0 ? help_height : 600);
1055 	GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
1056 	GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
1057 	GtkWidget *hbox_l = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
1058 	GtkWidget *hbox_c = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
1059 	GtkWidget *hbox_r = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
1060 	GtkWidget *button_back = gtk_button_new_from_icon_name("go-previous-symbolic", GTK_ICON_SIZE_BUTTON);
1061 	GtkWidget *button_home = gtk_button_new_from_icon_name("go-home-symbolic", GTK_ICON_SIZE_BUTTON);
1062 	GtkWidget *button_forward = gtk_button_new_from_icon_name("go-next-symbolic", GTK_ICON_SIZE_BUTTON);
1063 	GtkWidget *entry_find = gtk_search_entry_new();
1064 	GtkWidget *button_previous_match = gtk_button_new_from_icon_name("go-up-symbolic", GTK_ICON_SIZE_BUTTON);
1065 	GtkWidget *button_next_match = gtk_button_new_from_icon_name("go-down-symbolic", GTK_ICON_SIZE_BUTTON);
1066 	gtk_entry_set_width_chars(GTK_ENTRY(entry_find), 25);
1067 	GtkWidget *button_zoomin = gtk_button_new_from_icon_name("zoom-in-symbolic", GTK_ICON_SIZE_BUTTON);
1068 	GtkWidget *button_zoomout = gtk_button_new_from_icon_name("zoom-out-symbolic", GTK_ICON_SIZE_BUTTON);
1069 	gtk_widget_set_sensitive(button_back, FALSE);
1070 	gtk_widget_set_sensitive(button_forward, FALSE);
1071 	gtk_container_add(GTK_CONTAINER(hbox_l), button_back);
1072 	gtk_container_add(GTK_CONTAINER(hbox_l), button_home);
1073 	gtk_container_add(GTK_CONTAINER(hbox_l), button_forward);
1074 	gtk_container_add(GTK_CONTAINER(hbox_c), entry_find);
1075 	gtk_container_add(GTK_CONTAINER(hbox_c), button_previous_match);
1076 	gtk_container_add(GTK_CONTAINER(hbox_c), button_next_match);
1077 	gtk_container_add(GTK_CONTAINER(hbox_r), button_zoomout);
1078 	gtk_container_add(GTK_CONTAINER(hbox_r), button_zoomin);
1079 	gtk_box_pack_start(GTK_BOX(hbox), hbox_l, FALSE, FALSE, 0);
1080 	gtk_box_pack_start(GTK_BOX(hbox), hbox_c, TRUE, FALSE, 0);
1081 	gtk_box_pack_end(GTK_BOX(hbox), hbox_r, FALSE, FALSE, 0);
1082 	gtk_style_context_add_class(gtk_widget_get_style_context(hbox_l), "linked");
1083 	gtk_style_context_add_class(gtk_widget_get_style_context(hbox_c), "linked");
1084 	gtk_style_context_add_class(gtk_widget_get_style_context(hbox_r), "linked");
1085 	gtk_container_add(GTK_CONTAINER(vbox), hbox);
1086 	gtk_container_set_border_width(GTK_CONTAINER(hbox), 12);
1087 	gtk_container_add(GTK_CONTAINER(dialog), vbox);
1088 	GtkWidget *scrolledWeb = gtk_scrolled_window_new(NULL, NULL);
1089 	gtk_widget_set_hexpand(scrolledWeb, TRUE);
1090 	gtk_widget_set_vexpand(scrolledWeb, TRUE);
1091 	gtk_container_add(GTK_CONTAINER(vbox), scrolledWeb);
1092 	GtkWidget *webView = webkit_web_view_new();
1093 	help_find_entries[webView] = entry_find;
1094 	WebKitSettings *settings = webkit_web_view_get_settings(WEBKIT_WEB_VIEW(webView));
1095 	webkit_settings_set_enable_plugins(settings, FALSE);
1096 	webkit_settings_set_zoom_text_only(settings, FALSE);
1097 	if(help_zoom > 0.0) webkit_web_view_set_zoom_level(WEBKIT_WEB_VIEW(webView), help_zoom);
1098 	PangoFontDescription *font_desc;
1099 	gtk_style_context_get(gtk_widget_get_style_context(mainwindow), GTK_STATE_FLAG_NORMAL, GTK_STYLE_PROPERTY_FONT, &font_desc, NULL);
1100 	webkit_settings_set_default_font_family(settings, pango_font_description_get_family(font_desc));
1101 	webkit_settings_set_default_font_size(settings, webkit_settings_font_size_to_pixels(pango_font_description_get_size(font_desc) / PANGO_SCALE));
1102 	pango_font_description_free(font_desc);
1103 	g_signal_connect(G_OBJECT(dialog), "key-press-event", G_CALLBACK(on_help_key_press_event), (gpointer) webView);
1104 	g_signal_connect(G_OBJECT(webView), "context-menu", G_CALLBACK(on_help_context_menu), NULL);
1105 	g_signal_connect(G_OBJECT(webView), "load-changed", G_CALLBACK(on_help_load_changed_b), (gpointer) button_back);
1106 	g_signal_connect(G_OBJECT(webView), "load-changed", G_CALLBACK(on_help_load_changed_f), (gpointer) button_forward);
1107 	g_signal_connect(G_OBJECT(webView), "load-changed", G_CALLBACK(on_help_load_changed), NULL);
1108 	g_signal_connect(G_OBJECT(webView), "decide-policy", G_CALLBACK(on_help_decide_policy), dialog);
1109 	g_signal_connect_swapped(G_OBJECT(button_back), "clicked", G_CALLBACK(webkit_web_view_go_back), (gpointer) webView);
1110 	g_signal_connect_swapped(G_OBJECT(button_forward), "clicked", G_CALLBACK(webkit_web_view_go_forward), (gpointer) webView);
1111 	g_signal_connect(G_OBJECT(button_home), "clicked", G_CALLBACK(on_help_button_home_clicked), (gpointer) webView);
1112 	g_signal_connect(G_OBJECT(button_zoomin), "clicked", G_CALLBACK(on_help_button_zoomin_clicked), (gpointer) webView);
1113 	g_signal_connect(G_OBJECT(button_zoomout), "clicked", G_CALLBACK(on_help_button_zoomout_clicked), (gpointer) webView);
1114 	g_signal_connect(G_OBJECT(entry_find), "search-changed", G_CALLBACK(on_help_search_changed), (gpointer) webView);
1115 	g_signal_connect(G_OBJECT(entry_find), "next-match", G_CALLBACK(on_help_next_match), (gpointer) webView);
1116 	g_signal_connect(G_OBJECT(entry_find), "previous-match", G_CALLBACK(on_help_previous_match), (gpointer) webView);
1117 	g_signal_connect(G_OBJECT(button_next_match), "clicked", G_CALLBACK(on_help_next_match), (gpointer) webView);
1118 	g_signal_connect(G_OBJECT(button_previous_match), "clicked", G_CALLBACK(on_help_previous_match), (gpointer) webView);
1119 	g_signal_connect(G_OBJECT(entry_find), "stop-search", G_CALLBACK(on_help_stop_search), (gpointer) webView);
1120 	g_signal_connect(G_OBJECT(entry_find), "activate", G_CALLBACK(on_help_next_match), (gpointer) webView);
1121 	g_signal_connect(webkit_web_view_get_find_controller(WEBKIT_WEB_VIEW(webView)), "found-text", G_CALLBACK(on_help_search_found), NULL);
1122 	gtk_container_add(GTK_CONTAINER(scrolledWeb), GTK_WIDGET(webView));
1123 	webkit_web_view_load_uri(WEBKIT_WEB_VIEW(webView), get_doc_uri(file).c_str());
1124 	g_signal_connect(G_OBJECT(dialog), "configure-event", G_CALLBACK(on_help_configure_event), NULL);
1125 	gtk_widget_grab_focus(GTK_WIDGET(webView));
1126 	gtk_widget_show_all(dialog);
1127 #else
1128 	GError *error = NULL;
1129 #	if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 22
1130 	gtk_show_uri_on_window(GTK_WINDOW(parent), get_doc_uri(file).c_str(), gtk_get_current_event_time(), &error);
1131 #	else
1132 	gtk_show_uri(NULL, get_doc_uri(file).c_str(), gtk_get_current_event_time(), &error);
1133 #	endif
1134 	if(error) {
1135 		gchar *error_str = g_locale_to_utf8(error->message, -1, NULL, NULL, NULL);
1136 		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);
1137 		gtk_dialog_run(GTK_DIALOG(dialog));
1138 		gtk_widget_destroy(dialog);
1139 		g_free(error_str);
1140 		g_error_free(error);
1141 	}
1142 #endif
1143 }
1144 
fix_history_string2(string & str)1145 void fix_history_string2(string &str) {
1146 	gsub("&", "&amp;", str);
1147 	gsub(">", "&gt;", str);
1148 	gsub("<", "&lt;", str);
1149 }
fix_history_string(const string & str2)1150 string fix_history_string(const string &str2) {
1151 	string str = str2;
1152 	gsub("&", "&amp;", str);
1153 	gsub(">", "&gt;", str);
1154 	gsub("<", "&lt;", str);
1155 	return str;
1156 }
unfix_history_string(string & str)1157 void unfix_history_string(string &str) {
1158 	gsub("&amp;", "&", str);
1159 	gsub("&gt;", ">", str);
1160 	gsub("&lt;", "<", str);
1161 }
replace_result_cis_gtk(string & resstr)1162 void replace_result_cis_gtk(string &resstr) {
1163 	if(can_display_unicode_string_function_exact("∠", (void*) historyview)) gsub(" cis ", "∠", resstr);
1164 }
improve_result_text(string & resstr)1165 void improve_result_text(string &resstr) {
1166 	size_t i1 = 0, i2 = 0, i3 = 0, i_prev = 0;
1167 	size_t i_equals = resstr.find(_("approx.")) + strlen(_("approx."));
1168 	while(i_prev + 2 < resstr.length()) {
1169 		i1 = resstr.find_first_of("\"\'", i_prev);
1170 		if(i1 == string::npos) break;
1171 		i2 = resstr.find(resstr[i1], i1 + 1);
1172 		if(i2 == string::npos) break;
1173 		if(i2 - i1 > 2) {
1174 			if(!text_length_is_one(resstr.substr(i1 + 1, i2 - i1 - 1))) {
1175 				i_prev = i2 + 1;
1176 				continue;
1177 			}
1178 		}
1179 
1180 		if(i1 > 1 && resstr[i1 - 1] == ' ' && (i_equals == string::npos || i1 != i_equals + 1) && (is_in(NUMBERS, resstr[i1 - 2]) || i1 == i_prev + 1)) {
1181 			if(resstr[i1 - 2] < 0) {
1182 				i3 = i1 - 2;
1183 				while(i3 > 0 && resstr[i3] < 0 && (unsigned char) resstr[i3] < 0xC0) i3--;
1184 				string str = resstr.substr(i3, i1 - i3 - 1);
1185 				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()) {
1186 					resstr.replace(i1 - 1, 2, "<i>");
1187 					if(i_equals != string::npos && i1 < i_equals) i_equals += 1;
1188 					i2 += 1;
1189 				} else {
1190 					resstr.replace(i1, 1, "<i>");
1191 					if(i_equals != string::npos && i1 < i_equals) i_equals += 2;
1192 					i2 += 2;
1193 				}
1194 			} else {
1195 				resstr.replace(i1 - 1, 2, "<i>");
1196 				if(i_equals != string::npos && i1 < i_equals) i_equals += 1;
1197 				i2 += 1;
1198 			}
1199 		} else {
1200 			resstr.replace(i1, 1, "<i>");
1201 			if(i_equals != string::npos && i1 < i_equals) i_equals += 2;
1202 			i2 += 2;
1203 		}
1204 		resstr.replace(i2, 1, "</i>");
1205 		if(i_equals != string::npos && i1 < i_equals) i_equals += 3;
1206 		i_prev = i2 + 4;
1207 	}
1208 	i1 = 1;
1209 	while(i1 < resstr.length()) {
1210 		i1 = resstr.find('_', i1);
1211 		if(i1 == string::npos || i1 + 1 == resstr.length()) break;
1212 		if(is_not_in(NOT_IN_NAMES, resstr[i1 + 1])) {
1213 			i2 = resstr.find_last_of(NOT_IN_NAMES, i1 - 1);
1214 			i3 = resstr.find_first_of(NOT_IN_NAMES, i1 + 1);
1215 			if(i2 == string::npos) i2 = 0;
1216 			else i2 = i2 + 1;
1217 			if(i3 == string::npos) i3 = resstr.length();
1218 			ExpressionItem *item = CALCULATOR->getActiveExpressionItem(resstr.substr(i2, i3 - i2));
1219 			if(item) {
1220 				i2 = item->hasName(resstr.substr(i2, i3 - i2), true);
1221 				if(i2 > 0 && item->getName(i2).suffix) {
1222 					i1 = resstr.rfind('_', i3 - 1);
1223 					resstr.replace(i1, 1, "<sub>");
1224 					i1 += 4;
1225 					resstr.insert(i3 + 4, "</sub>");
1226 					i1 += 6;
1227 				} else {
1228 					i1 = i3 - 1;
1229 				}
1230 			}
1231 		}
1232 		i1++;
1233 	}
1234 }
1235 
1236 
1237 int completion_blocked = 0;
block_completion()1238 void block_completion() {
1239 	gtk_widget_hide(completion_window);
1240 	completion_blocked++;
1241 }
unblock_completion()1242 void unblock_completion() {
1243 	completion_blocked--;
1244 }
1245 
1246 gboolean do_autocalc_history_timeout(gpointer);
result_text_empty()1247 bool result_text_empty() {
1248 	return result_text.empty() && !autocalc_history_timeout_id;
1249 }
get_result_text()1250 const string &get_result_text() {
1251 	if(autocalc_history_timeout_id) {
1252 		g_source_remove(autocalc_history_timeout_id);
1253 		do_autocalc_history_timeout(NULL);
1254 	}
1255 	return result_text;
1256 }
get_expression_text()1257 string get_expression_text() {
1258 	GtkTextIter istart, iend;
1259 	gtk_text_buffer_get_start_iter(expressionbuffer, &istart);
1260 	gtk_text_buffer_get_end_iter(expressionbuffer, &iend);
1261 	gchar *gtext = gtk_text_buffer_get_text(expressionbuffer, &istart, &iend, FALSE);
1262 	string text = gtext;
1263 	g_free(gtext);
1264 	return text;
1265 }
get_selected_expression_text(bool return_all_if_no_sel=false)1266 string get_selected_expression_text(bool return_all_if_no_sel = false) {
1267 	if(!gtk_text_buffer_get_has_selection(expressionbuffer)) {
1268 		if(return_all_if_no_sel) {
1269 			string str = get_expression_text();
1270 			remove_blank_ends(str);
1271 			return str;
1272 		}
1273 		return "";
1274 	}
1275 	GtkTextIter istart, iend;
1276 	gtk_text_buffer_get_selection_bounds(expressionbuffer, &istart, &iend);
1277 	gchar *gtext = gtk_text_buffer_get_text(expressionbuffer, &istart, &iend, FALSE);
1278 	string text = gtext;
1279 	g_free(gtext);
1280 	return text;
1281 }
add_expression_to_undo()1282 void add_expression_to_undo() {
1283 	if(expression_undo_buffer.size() > 100) expression_undo_buffer.pop_front();
1284 	else undo_index++;
1285 	while(undo_index < expression_undo_buffer.size()) {
1286 		expression_undo_buffer.pop_back();
1287 	}
1288 	expression_undo_buffer.push_back(get_expression_text());
1289 }
1290 
overwrite_expression_selection(const gchar * text)1291 void overwrite_expression_selection(const gchar *text) {
1292 	block_completion();
1293 	block_add_to_undo++;
1294 	gtk_text_buffer_delete_selection(expressionbuffer, FALSE, TRUE);
1295 	block_add_to_undo--;
1296 	if(text) gtk_text_buffer_insert_at_cursor(expressionbuffer, text, -1);
1297 	unblock_completion();
1298 }
set_expression_text(const gchar * text)1299 void set_expression_text(const gchar *text) {
1300 	block_add_to_undo++;
1301 	gtk_text_buffer_set_text(expressionbuffer, text, -1);
1302 	block_add_to_undo--;
1303 	if(!block_add_to_undo) add_expression_to_undo();
1304 }
clear_expression_text()1305 void clear_expression_text() {
1306 	gtk_text_buffer_set_text(expressionbuffer, "", -1);
1307 }
expression_is_empty()1308 bool expression_is_empty() {
1309 	GtkTextIter istart;
1310 	gtk_text_buffer_get_start_iter(expressionbuffer, &istart);
1311 	return gtk_text_iter_is_end(&istart);
1312 }
is_at_beginning_of_expression(bool allow_selection=false)1313 bool is_at_beginning_of_expression(bool allow_selection = false) {
1314 	if(!allow_selection && gtk_text_buffer_get_has_selection(expressionbuffer)) return false;
1315 	GtkTextIter ipos;
1316 	gtk_text_buffer_get_iter_at_mark(expressionbuffer, &ipos, gtk_text_buffer_get_insert(expressionbuffer));
1317 	return gtk_text_iter_is_start(&ipos);
1318 }
1319 
1320 void set_assumptions_items(AssumptionType, AssumptionSign);
1321 void set_mode_items(const PrintOptions&, const EvaluationOptions&, AssumptionType, AssumptionSign, bool, int, bool, bool, bool, int, bool, bool, bool, bool);
1322 
1323 string sdot, saltdot, sdiv, sslash, stimes, sminus;
1324 string sdot_s, saltdot_s, sdiv_s, sslash_s, stimes_s, sminus_s;
1325 string sdot_o, saltdot_o, sdiv_o, sslash_o, stimes_o, sminus_o;
1326 
set_operator_symbols()1327 void set_operator_symbols() {
1328 	if(can_display_unicode_string_function_exact(SIGN_MINUS, (void*) expressiontext)) sminus = SIGN_MINUS;
1329 	else sminus = "-";
1330 	if(can_display_unicode_string_function(SIGN_DIVISION, (void*) expressiontext)) sdiv = SIGN_DIVISION;
1331 	else sdiv = "/";
1332 	sslash = "/";
1333 	if(can_display_unicode_string_function(SIGN_MULTIDOT, (void*) expressiontext)) sdot = SIGN_MULTIDOT;
1334 	else sdot = "*";
1335 	if(can_display_unicode_string_function(SIGN_MIDDLEDOT, (void*) expressiontext)) saltdot = SIGN_MIDDLEDOT;
1336 	else saltdot = "*";
1337 	if(can_display_unicode_string_function(SIGN_MULTIPLICATION, (void*) expressiontext)) stimes = SIGN_MULTIPLICATION;
1338 	else stimes = "*";
1339 
1340 	if(can_display_unicode_string_function_exact(SIGN_MINUS, (void*) statuslabel_l)) sminus_s = SIGN_MINUS;
1341 	else sminus_s = "-";
1342 	if(can_display_unicode_string_function(SIGN_DIVISION, (void*) statuslabel_l)) sdiv_s = SIGN_DIVISION;
1343 	else sdiv_s = "/";
1344 	if(can_display_unicode_string_function_exact(SIGN_DIVISION, (void*) statuslabel_l)) sslash_s = SIGN_DIVISION_SLASH;
1345 	else sslash_s = "/";
1346 	if(can_display_unicode_string_function(SIGN_MULTIDOT, (void*) statuslabel_l)) sdot_s = SIGN_MULTIDOT;
1347 	else sdot_s = "*";
1348 	if(can_display_unicode_string_function(SIGN_MIDDLEDOT, (void*) statuslabel_l)) saltdot_s = SIGN_MIDDLEDOT;
1349 	else saltdot_s = "*";
1350 	if(can_display_unicode_string_function(SIGN_MULTIPLICATION, (void*) statuslabel_l)) stimes_s = SIGN_MULTIPLICATION;
1351 	else stimes_s = "*";
1352 
1353 	if(can_display_unicode_string_function_exact(SIGN_MINUS, (void*) gtk_builder_get_object(main_builder, "convert_entry_unit"))) sminus_o = SIGN_MINUS;
1354 	else sminus_o = "-";
1355 	if(can_display_unicode_string_function(SIGN_DIVISION, (void*) gtk_builder_get_object(main_builder, "convert_entry_unit"))) sdiv_o = SIGN_DIVISION;
1356 	else sdiv_o = "/";
1357 	sslash_o = "/";
1358 	if(can_display_unicode_string_function(SIGN_MULTIDOT, (void*) gtk_builder_get_object(main_builder, "convert_entry_unit"))) sdot_o = SIGN_MULTIDOT;
1359 	else sdot_o = "*";
1360 	if(can_display_unicode_string_function(SIGN_MIDDLEDOT, (void*) gtk_builder_get_object(main_builder, "convert_entry_unit"))) saltdot_o = SIGN_MIDDLEDOT;
1361 	else saltdot_o = "*";
1362 	if(can_display_unicode_string_function(SIGN_MULTIPLICATION, (void*) gtk_builder_get_object(main_builder, "convert_entry_unit"))) stimes_o = SIGN_MULTIPLICATION;
1363 	else stimes_o = "*";
1364 
1365 	if(status_layout) {
1366 		g_object_unref(status_layout);
1367 		status_layout = NULL;
1368 	}
1369 }
1370 
expression_add_sign()1371 const char *expression_add_sign() {
1372 	return "+";
1373 }
expression_sub_sign()1374 const char *expression_sub_sign() {
1375 	if(!printops.use_unicode_signs) return "-";
1376 	return sminus.c_str();
1377 }
expression_times_sign()1378 const char *expression_times_sign() {
1379 	if(printops.use_unicode_signs && printops.multiplication_sign == MULTIPLICATION_SIGN_DOT) return sdot.c_str();
1380 	else if(printops.use_unicode_signs && printops.multiplication_sign == MULTIPLICATION_SIGN_ALTDOT) return saltdot.c_str();
1381 	else if(printops.use_unicode_signs && printops.multiplication_sign == MULTIPLICATION_SIGN_X) return stimes.c_str();
1382 	return "*";
1383 }
expression_divide_sign()1384 const char *expression_divide_sign() {
1385 	if(!printops.use_unicode_signs) return "/";
1386 	if(printops.division_sign == DIVISION_SIGN_DIVISION) return sdiv.c_str();
1387 	return sslash.c_str();
1388 }
1389 
1390 GtkWidget *prev_eb = NULL;
1391 bool prev_ebv = false;
1392 string prev_ebtext;
1393 int block_update_expression_icons = 0;
1394 
showhide_expression_button()1395 void showhide_expression_button() {
1396 	if(block_update_expression_icons) return;
1397 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "expression_button")), !expression_is_empty() || (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_get_visible_child(GTK_STACK(gtk_builder_get_object(main_builder, "expression_button_stack"))) != GTK_WIDGET(gtk_builder_get_object(main_builder, "expression_button_clear"))));
1398 }
hide_expression_spinner()1399 void hide_expression_spinner() {
1400 	if(prev_eb) {
1401 		gtk_stack_set_visible_child(GTK_STACK(gtk_builder_get_object(main_builder, "expression_button_stack")), prev_eb);
1402 		gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "expression_button")), prev_ebv);
1403 		gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(main_builder, "expression_button")), prev_ebtext.c_str());
1404 	}
1405 	gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "expressionspinnerbox")));
1406 	gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "resultspinnerbox")));
1407 }
1408 #define EXPRESSION_STOP 1
1409 #define EXPRESSION_SPINNER 2
1410 #define RESULT_SPINNER 5
1411 #define EXPRESSION_INFO 3
1412 #define EXPRESSION_CLEAR 4
update_expression_icons(int id=0)1413 void update_expression_icons(int id = 0) {
1414 	if(block_update_expression_icons) return;
1415 	if(auto_calculate && id == 0) id = EXPRESSION_CLEAR;
1416 	switch(id) {
1417 		case RESULT_SPINNER: {}
1418 		case EXPRESSION_SPINNER: {
1419 			prev_eb = gtk_stack_get_visible_child(GTK_STACK(gtk_builder_get_object(main_builder, "expression_button_stack")));
1420 			prev_ebv = gtk_widget_is_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "expression_button")));
1421 			gchar *gstr = gtk_widget_get_tooltip_text(GTK_WIDGET(gtk_builder_get_object(main_builder, "expression_button")));
1422 			if(gstr) {
1423 				prev_ebtext = gstr;
1424 				g_free(gstr);
1425 			}
1426 		}
1427 		case EXPRESSION_STOP: {
1428 			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")));
1429 			gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(main_builder, "expression_button")), _("Stop process"));
1430 			break;
1431 		}
1432 		case EXPRESSION_INFO: {
1433 			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")));
1434 			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"))));
1435 			break;
1436 		}
1437 		case EXPRESSION_CLEAR: {
1438 			if(!rpn_mode) {
1439 				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_clear")));
1440 				gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(main_builder, "expression_button")), _("Clear expression"));
1441 				break;
1442 			}
1443 		}
1444 		default: {
1445 			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"))) {
1446 				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")));
1447 				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"));
1448 			}
1449 		}
1450 	}
1451 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "expressionspinnerbox")), id == EXPRESSION_SPINNER);
1452 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "resultspinnerbox")), id == RESULT_SPINNER);
1453 	showhide_expression_button();
1454 }
1455 
result_font_modified()1456 void result_font_modified() {
1457 	while(gtk_events_pending()) gtk_main_iteration();
1458 	set_result_size_request();
1459 	result_font_updated = TRUE;
1460 	set_operator_symbols();
1461 	result_display_updated();
1462 }
expression_font_modified()1463 void expression_font_modified() {
1464 	while(gtk_events_pending()) gtk_main_iteration();
1465 	set_expression_size_request();
1466 	set_operator_symbols();
1467 	PangoLayout *layout_par = gtk_widget_create_pango_layout(expressiontext, "()");
1468 	gint w1 = 0, w2 = 0;
1469 	pango_layout_get_pixel_size(layout_par, &w1, NULL);
1470 	pango_layout_set_markup(layout_par, "<b>()</b>", -1);
1471 	pango_layout_get_pixel_size(layout_par, &w2, NULL);
1472 	if(w1 == w2) g_object_set(expression_par_tag, "weight", PANGO_WEIGHT_BOLD, NULL);
1473 	else g_object_set(expression_par_tag, "weight", PANGO_WEIGHT_NORMAL, NULL);
1474 }
1475 
get_least_coverage(const gchar * gstr,GtkWidget * widget)1476 PangoCoverageLevel get_least_coverage(const gchar *gstr, GtkWidget *widget) {
1477 
1478 	PangoCoverageLevel level = PANGO_COVERAGE_EXACT;
1479 	PangoContext *context = gtk_widget_get_pango_context(widget);
1480 	PangoLanguage *language = pango_context_get_language(context);
1481 	PangoFontDescription *font_desc;
1482 	gtk_style_context_get(gtk_widget_get_style_context(widget), GTK_STATE_FLAG_NORMAL, GTK_STYLE_PROPERTY_FONT, &font_desc, NULL);
1483 	PangoFontset *fontset = pango_context_load_fontset(context, font_desc, language);
1484 	pango_font_description_free(font_desc);
1485 	while(gstr[0] != '\0') {
1486 		if(gstr[0] < 0) {
1487 			gunichar gu = g_utf8_get_char_validated(gstr, -1);
1488 			if(gu != (gunichar) -1 && gu != (gunichar) -2) {
1489 				PangoFont *font = pango_fontset_get_font(fontset, (guint) gu);
1490 				if(font) {
1491 					PangoCoverage *coverage = pango_font_get_coverage(font, language);
1492 					if(pango_coverage_get(coverage, (int) gu) < level) {
1493 						level = pango_coverage_get(coverage, gu);
1494 					}
1495 					g_object_unref(font);
1496 					pango_coverage_unref(coverage);
1497 				} else {
1498 					level = PANGO_COVERAGE_NONE;
1499 				}
1500 			}
1501 		}
1502 		gstr = g_utf8_find_next_char(gstr, NULL);
1503 		if(!gstr) break;
1504 	}
1505 	g_object_unref(fontset);
1506 	return level;
1507 
1508 }
1509 
can_display_unicode_string_function(const char * str,void * w)1510 bool can_display_unicode_string_function(const char *str, void *w) {
1511 	if(!w) w = (void*) historyview;
1512 	return get_least_coverage(str, (GtkWidget*) w) >= PANGO_COVERAGE_APPROXIMATE;
1513 }
can_display_unicode_string_function_exact(const char * str,void * w)1514 bool can_display_unicode_string_function_exact(const char *str, void *w) {
1515 	if(!w) w = (void*) historyview;
1516 	return get_least_coverage(str, (GtkWidget*) w) >= PANGO_COVERAGE_EXACT;
1517 }
1518 
1519 double par_width = 6.0;
1520 
set_result_size_request()1521 void set_result_size_request() {
1522 	MathStructure mtest;
1523 	MathStructure m1("Ü");
1524 	MathStructure mden("y"); mden ^= m1;
1525 	mtest = m1; mtest ^= m1; mtest.transform(STRUCT_DIVISION, mden);
1526 	mtest.transform(CALCULATOR->f_sqrt);
1527 	mtest.transform(CALCULATOR->f_abs);
1528 	PrintOptions po;
1529 	po.can_display_unicode_string_function = &can_display_unicode_string_function;
1530 	po.can_display_unicode_string_arg = (void*) resultview;
1531 	cairo_surface_t *tmp_surface2 = draw_structure(mtest, po, false, top_ips, NULL, 3);
1532 	if(tmp_surface2) {
1533 		cairo_surface_flush(tmp_surface2);
1534 		gint h = cairo_image_surface_get_height(tmp_surface2) / gtk_widget_get_scale_factor(resultview);
1535 		gint sbh = 0;
1536 		gtk_widget_get_preferred_height(gtk_scrolled_window_get_hscrollbar(GTK_SCROLLED_WINDOW(gtk_builder_get_object(main_builder, "scrolled_result"))), NULL, &sbh);
1537 		h += sbh;
1538 		h += 3;
1539 		cairo_surface_destroy(tmp_surface2);
1540 		mtest.set(9);
1541 		mtest.transform(STRUCT_DIVISION, 9);
1542 		tmp_surface2 = draw_structure(mtest, po);
1543 		if(tmp_surface2) {
1544 			cairo_surface_flush(tmp_surface2);
1545 			gint h2 = cairo_image_surface_get_height(tmp_surface2) / gtk_widget_get_scale_factor(resultview) + 3;
1546 			if(h2 > h) h = h2;
1547 			cairo_surface_destroy(tmp_surface2);
1548 		}
1549 		gtk_widget_set_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "scrolled_result")), -1, h);
1550 	}
1551 	PangoLayout *layout_test = gtk_widget_create_pango_layout(resultview, "x");
1552 	gint h;
1553 	pango_layout_get_pixel_size(layout_test, NULL, &h);
1554 	par_width = h / 2.2;
1555 }
1556 
set_expression_size_request()1557 void set_expression_size_request() {
1558 	string test_str = "Äy";
1559 	for(int i = 1; i < (expression_lines < 1 ? 3 : expression_lines); i++) test_str += "\nÄy";
1560 	PangoLayout *layout_test = gtk_widget_create_pango_layout(expressiontext, test_str.c_str());
1561 	gint h;
1562 	pango_layout_get_pixel_size(layout_test, NULL, &h);
1563 	g_object_unref(layout_test);
1564 	h += 12;
1565 	bool show_eb = gtk_widget_is_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "expression_button")));
1566 	gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(main_builder, "expression_button")));
1567 	gint h2 = 0;
1568 	gtk_widget_get_preferred_height(GTK_WIDGET(gtk_builder_get_object(main_builder, "box_expression_buttons")), NULL, &h2);
1569 	if(!show_eb) gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "expression_button")));
1570 	if(h2 <= 0) h2 = minimal_mode ? 58 : 34;
1571 	if(minimal_mode) h2 += 2;
1572 	if(h < h2) h = h2;
1573 	gtk_widget_set_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "expressionscrolled")), -1, h);
1574 	layout_test = gtk_widget_create_pango_layout(expressiontext, "Äy");
1575 	pango_layout_get_pixel_size(layout_test, NULL, &h);
1576 	g_object_unref(layout_test);
1577 	h = h / 2 - 4;
1578 	if(h < 0) h = 0;
1579 	gtk_widget_set_margin_top(GTK_WIDGET(gtk_builder_get_object(main_builder, "expression_button_equals")), h);
1580 	gtk_widget_set_margin_top(GTK_WIDGET(gtk_builder_get_object(main_builder, "expression_button_clear")), h);
1581 	gtk_widget_set_margin_top(GTK_WIDGET(gtk_builder_get_object(main_builder, "expression_button_stop")), h);
1582 	gtk_widget_set_margin_top(GTK_WIDGET(gtk_builder_get_object(main_builder, "message_tooltip_icon")), h);
1583 }
1584 
set_unicode_buttons()1585 void set_unicode_buttons() {
1586 	if(printops.use_unicode_signs) {
1587 		if(custom_buttons[24].text.empty()) {
1588 			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);
1589 			else gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "label_sub")), MINUS);
1590 		}
1591 		if(custom_buttons[22].text.empty()) {
1592 			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);
1593 			else gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "label_times")), MULTIPLICATION);
1594 		}
1595 		if(custom_buttons[21].text.empty()) {
1596 			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);
1597 			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);
1598 			else gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "label_divide")), DIVISION);
1599 		}
1600 
1601 		if(can_display_unicode_string_function("➞", (void*) gtk_builder_get_object(main_builder, "button_fraction"))) gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "label_to")), "x ➞");
1602 		else gtk_label_set_label(GTK_LABEL(gtk_builder_get_object(main_builder, "label_to")), "to");
1603 
1604 		if(can_display_unicode_string_function(SIGN_DIVISION_SLASH, (void*) gtk_builder_get_object(main_builder, "button_fraction"))) gtk_button_set_label(GTK_BUTTON(gtk_builder_get_object(main_builder, "button_fraction")), "a " SIGN_DIVISION_SLASH " b");
1605 		else gtk_button_set_label(GTK_BUTTON(gtk_builder_get_object(main_builder, "button_fraction")), "a " DIVISION " b");
1606 
1607 		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");
1608 		else gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "label_factorize2")), "a" MULTIPLICATION "b");
1609 
1610 		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);
1611 		else gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_history_sub")), MINUS);
1612 		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);
1613 		else gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_history_times")), MULTIPLICATION);
1614 		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);
1615 		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);
1616 		else gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_history_divide")), DIVISION);
1617 
1618 		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);
1619 		else gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_rpn_sub")), MINUS);
1620 		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);
1621 		else gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_rpn_times")), MULTIPLICATION);
1622 		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);
1623 		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);
1624 		else gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_rpn_divide")), DIVISION);
1625 		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");
1626 		else gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_rpn_negate")), MINUS "x");
1627 
1628 		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);
1629 		else gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_sqrt")), "sqrt");
1630 		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);
1631 		else gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_sqrt2")), "sqrt");
1632 		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̄");
1633 		else gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_mean")), "mean");
1634 		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")), "∑");
1635 		else gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_sum")), "sum");
1636 		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")), "π");
1637 		else gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_pi")), "pi");
1638 
1639 	} else {
1640 
1641 		if(custom_buttons[24].text.empty()) gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "label_sub")), MINUS);
1642 		if(custom_buttons[22].text.empty()) gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "label_times")), MULTIPLICATION);
1643 		if(custom_buttons[21].text.empty()) gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "label_divide")), DIVISION);
1644 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_sqrt")), "sqrt");
1645 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_sqrt2")), "sqrt");
1646 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_mean")), "mean");
1647 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_sum")), "sum");
1648 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_pi")), "pi");
1649 		gtk_label_set_label(GTK_LABEL(gtk_builder_get_object(main_builder, "label_factorize2")), "a" MULTIPLICATION "b");
1650 		gtk_label_set_label(GTK_LABEL(gtk_builder_get_object(main_builder, "label_to")), "to");
1651 
1652 		gtk_button_set_label(GTK_BUTTON(gtk_builder_get_object(main_builder, "button_fraction")), "a " DIVISION " b");
1653 
1654 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_history_sub")), MINUS);
1655 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_history_times")), MULTIPLICATION);
1656 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_history_divide")), DIVISION);
1657 
1658 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_rpn_sub")), MINUS);
1659 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_rpn_times")), MULTIPLICATION);
1660 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_rpn_divide")), DIVISION);
1661 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_rpn_negate")), MINUS "x");
1662 	}
1663 
1664 	if(custom_buttons[18].text.empty()) gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "label_dot")), CALCULATOR->getDecimalPoint().c_str());
1665 	if(custom_buttons[4].text.empty()) gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "label_comma")), CALCULATOR->getComma().c_str());
1666 
1667 #define SUP_STRING(X) string("<span size=\"x-small\" rise=\"" + i2s((int) (pango_font_description_get_size(font_desc) / 1.5)) + "\">") + string(X) + "</span>"
1668 #define SUB_STRING(X) string("<span size=\"x-small\" rise=\"" + i2s((int) (-pango_font_description_get_size(font_desc) / 1.5)) + "\">") + string(X) + "</span>"
1669 
1670 	PangoFontDescription *font_desc = NULL;
1671 	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);
1672 	gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "label_history_xy")), (string("x") + SUP_STRING("y")).c_str());
1673 	pango_font_description_free(font_desc);
1674 	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);
1675 	gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "label_rpn_xy")), (string("x") + SUP_STRING("y")).c_str());
1676 	pango_font_description_free(font_desc);
1677 	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);
1678 	if(custom_buttons[20].text.empty()) gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "label_xy")), (string("x") + SUP_STRING("y")).c_str());
1679 	if(evalops.structuring != STRUCTURING_FACTORIZE) {
1680 		gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "label_factorize")), (string("a(x)") + SUP_STRING("b")).c_str());
1681 		gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_factorize")), _("Factorize"));
1682 	} else {
1683 		gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "label_factorize")), (string("x+x") + SUP_STRING("b")).c_str());
1684 		gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_factorize")), _("Expand"));
1685 	}
1686 	pango_font_description_free(font_desc);
1687 	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);
1688 	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());
1689 	else gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "label_reciprocal")), (string("x") + SUP_STRING("-1")).c_str());
1690 	gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "label_log2")), (string("log") + SUB_STRING("2")).c_str());
1691 	pango_font_description_free(font_desc);
1692 
1693 	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);
1694 	else gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_history_sqrt")), "sqrt");
1695 	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);
1696 	else gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_rpn_sqrt")), "sqrt");
1697 	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")), "∑");
1698 	else gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_rpn_sum")), "sum");
1699 
1700 	gtk_widget_set_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_registerup")), -1, -1);
1701 	gtk_widget_set_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_copyregister")), -1, -1);
1702 	gtk_widget_set_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_editregister")), -1, -1);
1703 	gtk_widget_set_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_clearstack")), -1, -1);
1704 	gtk_widget_set_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_add")), -1, -1);
1705 	gtk_widget_set_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_sqrt")), -1, -1);
1706 	gtk_widget_set_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_sum")), -1, -1);
1707 	GtkRequisition a;
1708 	gint w, h;
1709 	gtk_widget_get_preferred_size(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_reciprocal")), &a, NULL);
1710 	w = a.width; h = a.height;
1711 	gtk_widget_get_preferred_size(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_xy")), &a, NULL);
1712 	if(a.width > w) w = a.width;
1713 	if(a.height > h) h = a.height;
1714 	gtk_widget_get_preferred_size(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_sqrt")), &a, NULL);
1715 	if(a.width > w) w = a.width;
1716 	if(a.height > h) h = a.height;
1717 	gtk_widget_get_preferred_size(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_sum")), &a, NULL);
1718 	if(a.width > w) w = a.width;
1719 	if(a.height > h) h = a.height;
1720 	if(gtk_image_get_pixel_size(GTK_IMAGE(gtk_builder_get_object(main_builder, "image_up"))) != -1) gtk_image_set_pixel_size(GTK_IMAGE(gtk_builder_get_object(main_builder, "image_up")), -1);
1721 	gtk_widget_get_preferred_size(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_registerup")), &a, NULL);
1722 	if(a.width > w) w = a.width;
1723 	if(a.height > h) h = a.height;
1724 	if(gtk_image_get_pixel_size(GTK_IMAGE(gtk_builder_get_object(main_builder, "image_swap"))) != -1) gtk_image_set_pixel_size(GTK_IMAGE(gtk_builder_get_object(main_builder, "image_swap")), -1);
1725 	gtk_widget_get_preferred_size(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_registerswap")), &a, NULL);
1726 	gint h_i = -1;
1727 	if(use_custom_keypad_font || use_custom_app_font) {
1728 		h_i = 16 + (h - a.height);
1729 		if(h_i < 20) h_i = -1;
1730 	}
1731 	gtk_image_set_pixel_size(GTK_IMAGE(gtk_builder_get_object(main_builder, "image_up")), h_i);
1732 	gtk_image_set_pixel_size(GTK_IMAGE(gtk_builder_get_object(main_builder, "image_down")), h_i);
1733 	gtk_image_set_pixel_size(GTK_IMAGE(gtk_builder_get_object(main_builder, "image_swap")), h_i);
1734 	gtk_image_set_pixel_size(GTK_IMAGE(gtk_builder_get_object(main_builder, "image_copy")), h_i);
1735 	gtk_image_set_pixel_size(GTK_IMAGE(gtk_builder_get_object(main_builder, "image_lastx")), h_i);
1736 	gtk_image_set_pixel_size(GTK_IMAGE(gtk_builder_get_object(main_builder, "image_delete")), h_i);
1737 	gtk_image_set_pixel_size(GTK_IMAGE(gtk_builder_get_object(main_builder, "image_edit")), h_i);
1738 	gtk_image_set_pixel_size(GTK_IMAGE(gtk_builder_get_object(main_builder, "image_clear")), h_i);
1739 	gtk_widget_set_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_registerup")), w, h);
1740 	gtk_widget_set_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_copyregister")), w, h);
1741 	gtk_widget_set_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_editregister")), w, h);
1742 	gtk_widget_set_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_clearstack")), w, h);
1743 	gtk_widget_set_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_add")), w, h);
1744 	gtk_widget_set_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_sqrt")), w, h);
1745 	gtk_widget_set_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_sum")), w, h);
1746 
1747 	gtk_widget_set_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_history_insert_value")), -1, -1);
1748 	gtk_widget_set_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_history_copy")), -1, -1);
1749 	gtk_widget_set_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_history_add")), -1, -1);
1750 	gtk_widget_get_preferred_size(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_history_xy")), &a, NULL);
1751 	w = a.width; h = a.height;
1752 	gtk_widget_get_preferred_size(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_history_sqrt")), &a, NULL);
1753 	if(a.width > w) w = a.width;
1754 	if(a.height > h) h = a.height;
1755 	if(gtk_image_get_pixel_size(GTK_IMAGE(gtk_builder_get_object(main_builder, "image_history_insert_value"))) != -1) {
1756 		gtk_image_set_pixel_size(GTK_IMAGE(gtk_builder_get_object(main_builder, "image_history_insert_value")), -1);
1757 		gtk_image_set_pixel_size(GTK_IMAGE(gtk_builder_get_object(main_builder, "image_history_insert_text")), -1);
1758 		gtk_image_set_pixel_size(GTK_IMAGE(gtk_builder_get_object(main_builder, "image_history_copy")), -1);
1759 	}
1760 	gtk_widget_get_preferred_size(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_history_insert_value")), &a, NULL);
1761 	if(a.width > w) w = a.width;
1762 	if(a.height > h) h = a.height;
1763 	gtk_widget_get_preferred_size(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_history_copy")), &a, NULL);
1764 	h_i = -1;
1765 	if(use_custom_keypad_font || use_custom_app_font) {
1766 		h_i = 16 + (h - a.height);
1767 		if(h_i < 20) h_i = -1;
1768 	}
1769 	if(h_i != -1) {
1770 		gtk_image_set_pixel_size(GTK_IMAGE(gtk_builder_get_object(main_builder, "image_history_insert_value")), h_i);
1771 		gtk_image_set_pixel_size(GTK_IMAGE(gtk_builder_get_object(main_builder, "image_history_insert_text")), h_i);
1772 		gtk_image_set_pixel_size(GTK_IMAGE(gtk_builder_get_object(main_builder, "image_history_copy")), h_i);
1773 	}
1774 	gtk_widget_set_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_history_insert_value")), w, h);
1775 	gtk_widget_set_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_history_copy")), w, h);
1776 	gtk_widget_set_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_history_add")), w, h);
1777 }
1778 
1779 
string_is_less(string str1,string str2)1780 bool string_is_less(string str1, string str2) {
1781 	size_t i = 0;
1782 	bool b_uni = false;
1783 	while(i < str1.length() && i < str2.length()) {
1784 		if(str1[i] == str2[i]) i++;
1785 		else if(str1[i] < 0 || str2[i] < 0) {b_uni = true; break;}
1786 		else return str1[i] < str2[i];
1787 	}
1788 	if(b_uni) return g_utf8_collate(str1.c_str(), str2.c_str()) < 0;
1789 	return str1 < str2;
1790 }
1791 
1792 struct tree_struct {
1793 	string item;
1794 	list<tree_struct> items;
1795 	list<tree_struct>::iterator it;
1796 	list<tree_struct>::reverse_iterator rit;
1797 	vector<void*> objects;
1798 	tree_struct *parent;
sorttree_struct1799 	void sort() {
1800 		items.sort();
1801 		for(list<tree_struct>::iterator it = items.begin(); it != items.end(); ++it) {
1802 			it->sort();
1803 		}
1804 	}
operator <tree_struct1805 	bool operator < (const tree_struct &s1) const {
1806 		return string_is_less(item, s1.item);
1807 	}
1808 };
1809 
1810 tree_struct function_cats, unit_cats, variable_cats;
1811 vector<void*> ia_units, ia_variables, ia_functions;
1812 vector<string> recent_functions_pre;
1813 vector<string> recent_variables_pre;
1814 vector<string> recent_units_pre;
1815 vector<GtkWidget*> recent_function_items;
1816 vector<GtkWidget*> recent_variable_items;
1817 vector<GtkWidget*> recent_unit_items;
1818 vector<MathFunction*> recent_functions;
1819 vector<Variable*> recent_variables;
1820 vector<Unit*> recent_units;
1821 Unit *latest_button_unit = NULL, *latest_button_currency = NULL;
1822 string latest_button_unit_pre, latest_button_currency_pre;
1823 
is_answer_variable(Variable * v)1824 bool is_answer_variable(Variable *v) {
1825 	return v == vans[0] || v == vans[1] || v == vans[2] || v == vans[3] || v == vans[4];
1826 }
1827 
wrap_expression_selection(const char * insert_before=NULL,bool return_true_if_whole_selected=false)1828 int wrap_expression_selection(const char *insert_before = NULL, bool return_true_if_whole_selected = false) {
1829 	if(!gtk_text_buffer_get_has_selection(expressionbuffer)) return false;
1830 	GtkTextMark *mstart = gtk_text_buffer_get_selection_bound(expressionbuffer);
1831 	if(!mstart) return false;
1832 	GtkTextMark *mend = gtk_text_buffer_get_insert(expressionbuffer);
1833 	if(!mend) return false;
1834 	GtkTextIter istart, iend;
1835 	gtk_text_buffer_get_iter_at_mark(expressionbuffer, &istart, mstart);
1836 	gtk_text_buffer_get_iter_at_mark(expressionbuffer, &iend, mend);
1837 	if(!insert_before && ((gtk_text_iter_is_start(&iend) && gtk_text_iter_is_end(&istart)) || (gtk_text_iter_is_start(&istart) && gtk_text_iter_is_end(&iend)))) {
1838 		string str = get_expression_text();
1839 		if(str.find_first_not_of(NUMBER_ELEMENTS SPACE) == string::npos) {
1840 			if(gtk_text_iter_is_end(&istart)) gtk_text_buffer_place_cursor(expressionbuffer, &istart);
1841 			else gtk_text_buffer_place_cursor(expressionbuffer, &iend);
1842 			return true;
1843 		} else if((str.length() > 1 && str[0] == '/' && str.find_first_not_of(NUMBER_ELEMENTS SPACES, 1) != string::npos) || CALCULATOR->hasToExpression(str, true, evalops) || CALCULATOR->hasWhereExpression(str, evalops)) {
1844 			return -1;
1845 		}
1846 	}
1847 	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)));
1848 	if(gtk_text_iter_compare(&istart, &iend) > 0) {
1849 		block_add_to_undo++;
1850 		if(auto_calculate) block_result_update++;
1851 		if(insert_before) gtk_text_buffer_insert(expressionbuffer, &iend, insert_before, -1);
1852 		gtk_text_buffer_insert(expressionbuffer, &iend, "(", -1);
1853 		if(auto_calculate) block_result_update--;
1854 		gtk_text_buffer_get_iter_at_mark(expressionbuffer, &istart, mstart);
1855 		block_add_to_undo--;
1856 		gtk_text_buffer_insert(expressionbuffer, &istart, ")", -1);
1857 		gtk_text_buffer_place_cursor(expressionbuffer, &istart);
1858 	} else {
1859 		block_add_to_undo++;
1860 		if(auto_calculate) block_result_update++;
1861 		if(insert_before) gtk_text_buffer_insert(expressionbuffer, &istart, insert_before, -1);
1862 		gtk_text_buffer_insert(expressionbuffer, &istart, "(", -1);
1863 		if(auto_calculate) block_result_update--;
1864 		gtk_text_buffer_get_iter_at_mark(expressionbuffer, &iend, mend);
1865 		block_add_to_undo--;
1866 		gtk_text_buffer_insert(expressionbuffer, &iend, ")", -1);
1867 		gtk_text_buffer_place_cursor(expressionbuffer, &iend);
1868 	}
1869 	return b_ret;
1870 }
1871 
show_message(const gchar * text,GtkWidget * win)1872 void show_message(const gchar *text, GtkWidget *win) {
1873 	GtkWidget *edialog = gtk_message_dialog_new(GTK_WINDOW(win), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", text);
1874 	gtk_dialog_run(GTK_DIALOG(edialog));
1875 	gtk_widget_destroy(edialog);
1876 }
ask_question(const gchar * text,GtkWidget * win)1877 bool ask_question(const gchar *text, GtkWidget *win) {
1878 	GtkWidget *edialog = gtk_message_dialog_new(GTK_WINDOW(win), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_YES_NO, "%s", text);
1879 	int question_answer = gtk_dialog_run(GTK_DIALOG(edialog));
1880 	gtk_widget_destroy(edialog);
1881 	return question_answer == GTK_RESPONSE_YES;
1882 }
1883 
do_notification_timeout(gpointer)1884 gboolean do_notification_timeout(gpointer) {
1885 	gtk_revealer_set_reveal_child(GTK_REVEALER(gtk_builder_get_object(main_builder, "overlayrevealer")), FALSE);
1886 	gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "overlayrevealer")));
1887 	return FALSE;
1888 }
show_notification(string text)1889 void show_notification(string text) {
1890 	text.insert(0, "<big>");
1891 	text += "</big>";
1892 	gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "overlaylabel")), text.c_str());
1893 	gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(main_builder, "overlayrevealer")));
1894 	gtk_revealer_set_reveal_child(GTK_REVEALER(gtk_builder_get_object(main_builder, "overlayrevealer")), TRUE);
1895 	g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE, 1000, do_notification_timeout, NULL, NULL);
1896 }
1897 
1898 #define STATUS_SPACE	if(b) str += "  "; else b = true;
1899 
set_status_text(string text,bool break_begin=false,bool had_errors=false,bool had_warnings=false)1900 void set_status_text(string text, bool break_begin = false, bool had_errors = false, bool had_warnings = false) {
1901 
1902 	string str;
1903 	if(had_errors) {
1904 		str = "<span foreground=\"";
1905 		str += status_error_color;
1906 		str += "\">";
1907 	} else if(had_warnings) {
1908 		str = "<span foreground=\"";
1909 		str += status_warning_color;
1910 		str += "\">";
1911 	}
1912 	if(text.empty()) str += " ";
1913 	else str += text;
1914 	if(had_errors || had_warnings) str += "</span>";
1915 
1916 	if(break_begin) gtk_label_set_ellipsize(GTK_LABEL(statuslabel_l), PANGO_ELLIPSIZE_START);
1917 	else gtk_label_set_ellipsize(GTK_LABEL(statuslabel_l), PANGO_ELLIPSIZE_END);
1918 
1919 	gtk_label_set_markup(GTK_LABEL(statuslabel_l), str.c_str());
1920 	gint w = 0;
1921 	if(str.length() > 500) {
1922 		w = -1;
1923 	} else if(str.length() > 20) {
1924 		if(!status_layout) status_layout = gtk_widget_create_pango_layout(statuslabel_l, "");
1925 		pango_layout_set_markup(status_layout, str.c_str(), -1);
1926 		pango_layout_get_pixel_size(status_layout, &w, NULL);
1927 	}
1928 	if(w < 0 || w > gtk_widget_get_allocated_width(statuslabel_l)) gtk_widget_set_tooltip_markup(statuslabel_l, text.c_str());
1929 	else gtk_widget_set_tooltip_text(statuslabel_l, "");
1930 }
1931 
1932 void display_parse_status();
1933 
update_status_text()1934 void update_status_text() {
1935 
1936 	string str = "<span size=\"small\">";
1937 
1938 	bool b = false;
1939 	if(evalops.approximation == APPROXIMATION_EXACT) {
1940 		STATUS_SPACE
1941 		str += _("EXACT");
1942 	} else if(evalops.approximation == APPROXIMATION_APPROXIMATE) {
1943 		STATUS_SPACE
1944 		str += _("APPROX");
1945 	}
1946 	if(evalops.parse_options.parsing_mode == PARSING_MODE_RPN) {
1947 		STATUS_SPACE
1948 		str += _("RPN");
1949 	}
1950 	if(evalops.parse_options.parsing_mode == PARSING_MODE_CHAIN) {
1951 		STATUS_SPACE
1952 		// Chain mode
1953 		str += _("CHN");
1954 	}
1955 	switch(evalops.parse_options.base) {
1956 		case BASE_DECIMAL: {
1957 			break;
1958 		}
1959 		case BASE_BINARY: {
1960 			STATUS_SPACE
1961 			str += _("BIN");
1962 			break;
1963 		}
1964 		case BASE_OCTAL: {
1965 			STATUS_SPACE
1966 			str += _("OCT");
1967 			break;
1968 		}
1969 		case 12: {
1970 			STATUS_SPACE
1971 			str += _("DUO");
1972 			break;
1973 		}
1974 		case BASE_HEXADECIMAL: {
1975 			STATUS_SPACE
1976 			str += _("HEX");
1977 			break;
1978 		}
1979 		case BASE_ROMAN_NUMERALS: {
1980 			STATUS_SPACE
1981 			str += _("ROMAN");
1982 			break;
1983 		}
1984 		case BASE_BIJECTIVE_26: {
1985 			STATUS_SPACE
1986 			str += "B26";
1987 			break;
1988 		}
1989 		case BASE_CUSTOM: {
1990 			STATUS_SPACE
1991 			str += CALCULATOR->customInputBase().print(CALCULATOR->messagePrintOptions());
1992 			break;
1993 		}
1994 		case BASE_GOLDEN_RATIO: {
1995 			STATUS_SPACE
1996 			str += "φ";
1997 			break;
1998 		}
1999 		case BASE_SUPER_GOLDEN_RATIO: {
2000 			STATUS_SPACE
2001 			str += "ψ";
2002 			break;
2003 		}
2004 		case BASE_PI: {
2005 			STATUS_SPACE
2006 			str += "π";
2007 			break;
2008 		}
2009 		case BASE_E: {
2010 			STATUS_SPACE
2011 			str += "e";
2012 			break;
2013 		}
2014 		case BASE_SQRT2: {
2015 			STATUS_SPACE
2016 			str += "√2";
2017 			break;
2018 		}
2019 		case BASE_UNICODE: {
2020 			STATUS_SPACE
2021 			str += "UNICODE";
2022 			break;
2023 		}
2024 		default: {
2025 			STATUS_SPACE
2026 			str += i2s(evalops.parse_options.base);
2027 			break;
2028 		}
2029 	}
2030 	switch (evalops.parse_options.angle_unit) {
2031 		case ANGLE_UNIT_DEGREES: {
2032 			STATUS_SPACE
2033 			str += _("DEG");
2034 			break;
2035 		}
2036 		case ANGLE_UNIT_RADIANS: {
2037 			STATUS_SPACE
2038 			str += _("RAD");
2039 			break;
2040 		}
2041 		case ANGLE_UNIT_GRADIANS: {
2042 			STATUS_SPACE
2043 			str += _("GRA");
2044 			break;
2045 		}
2046 		default: {}
2047 	}
2048 	if(evalops.parse_options.read_precision != DONT_READ_PRECISION) {
2049 		STATUS_SPACE
2050 		str += _("PREC");
2051 	}
2052 	if(!evalops.parse_options.functions_enabled) {
2053 		STATUS_SPACE
2054 		str += "<s>";
2055 		str += _("FUNC");
2056 		str += "</s>";
2057 	}
2058 	if(!evalops.parse_options.units_enabled) {
2059 		STATUS_SPACE
2060 		str += "<s>";
2061 		str += _("UNIT");
2062 		str += "</s>";
2063 	}
2064 	if(!evalops.parse_options.variables_enabled) {
2065 		STATUS_SPACE
2066 		str += "<s>";
2067 		str += _("VAR");
2068 		str += "</s>";
2069 	}
2070 	if(!evalops.allow_infinite) {
2071 		STATUS_SPACE
2072 		str += "<s>";
2073 		str += _("INF");
2074 		str += "</s>";
2075 	}
2076 	if(!evalops.allow_complex) {
2077 		STATUS_SPACE
2078 		str += "<s>";
2079 		str += _("CPLX");
2080 		str += "</s>";
2081 	}
2082 
2083 	remove_blank_ends(str);
2084 	if(!b) str += " ";
2085 
2086 	str += "</span>";
2087 
2088 	if(str != gtk_label_get_label(GTK_LABEL(statuslabel_r))) {
2089 		gtk_label_set_text(GTK_LABEL(statuslabel_l), "");
2090 		gtk_label_set_markup(GTK_LABEL(statuslabel_r), str.c_str());
2091 		display_parse_status();
2092 	}
2093 
2094 }
2095 
check_exchange_rates(GtkWidget * win=NULL,bool set_result=false)2096 bool check_exchange_rates(GtkWidget *win = NULL, bool set_result = false) {
2097 	int i = CALCULATOR->exchangeRatesUsed();
2098 	if(i == 0) return false;
2099 	if(auto_update_exchange_rates == 0 && win != NULL) return false;
2100 	if(CALCULATOR->checkExchangeRatesDate(auto_update_exchange_rates > 0 ? auto_update_exchange_rates : 7, false, auto_update_exchange_rates == 0, i)) return false;
2101 	if(auto_update_exchange_rates == 0) return false;
2102 	bool b = false;
2103 	if(auto_update_exchange_rates < 0) {
2104 		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?"));
2105 		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());
2106 		GtkWidget *w = gtk_check_button_new_with_label(_("Do not ask again"));
2107 		gtk_container_add(GTK_CONTAINER(gtk_message_dialog_get_message_area(GTK_MESSAGE_DIALOG(edialog))), w);
2108 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), FALSE);
2109 		gtk_widget_show(w);
2110 		switch(gtk_dialog_run(GTK_DIALOG(edialog))) {
2111 			case GTK_RESPONSE_YES: {
2112 				b = true;
2113 				if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) {
2114 					auto_update_exchange_rates = 7;
2115 				}
2116 				break;
2117 			}
2118 			case GTK_RESPONSE_NO: {
2119 				if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) {
2120 					auto_update_exchange_rates = 0;
2121 				}
2122 				break;
2123 			}
2124 			default: {}
2125 		}
2126 		gtk_widget_destroy(edialog);
2127 	}
2128 	if(b || auto_update_exchange_rates > 0) {
2129 		if(auto_update_exchange_rates <= 0) i = -1;
2130 		if(!b && set_result) setResult(NULL, false, false, false, "", 0, false);
2131 		fetch_exchange_rates(b ? 15 : 8, i);
2132 		CALCULATOR->loadExchangeRates();
2133 		return true;
2134 	}
2135 	return false;
2136 }
2137 
2138 /*
2139 	display errors generated under calculation
2140 */
display_errors(int * history_index_p=NULL,GtkWidget * win=NULL,int * inhistory_index=NULL,int type=0)2141 bool display_errors(int *history_index_p = NULL, GtkWidget *win = NULL, int *inhistory_index = NULL, int type = 0) {
2142 	if(!CALCULATOR->message()) return false;
2143 	int index = 0;
2144 	MessageType mtype, mtype_highest = MESSAGE_INFORMATION;
2145 	string str = "";
2146 	GtkTreeIter history_iter;
2147 	int inhistory_added = 0;
2148 	while(true) {
2149 		mtype = CALCULATOR->message()->type();
2150 		if(mtype == MESSAGE_INFORMATION && (type == 1 || type == 2) && win && CALCULATOR->message()->message().find("-------------------------------------\n") == 0) {
2151 			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());
2152 			gtk_dialog_run(GTK_DIALOG(edialog));
2153 			gtk_widget_destroy(edialog);
2154 		} else {
2155 			if(index > 0) {
2156 				if(index == 1) str = "• " + str;
2157 				str += "\n• ";
2158 			}
2159 			if(win != NULL && plot_builder && win == GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_dialog")) && CALCULATOR->message()->message() == _("It took too long to generate the plot data.")) str += _("It took too long to generate the plot data. Please decrease the sampling rate or increase the time limit in preferences.");
2160 			else str += CALCULATOR->message()->message();
2161 			if(mtype == MESSAGE_ERROR || (mtype_highest != MESSAGE_ERROR && mtype == MESSAGE_WARNING)) {
2162 				mtype_highest = mtype;
2163 			}
2164 			if(history_index_p && inhistory_index && *inhistory_index >= 0) {
2165 				if(mtype == MESSAGE_ERROR) {
2166 					inhistory.insert(inhistory.begin() + *inhistory_index, CALCULATOR->message()->message());
2167 					inhistory_type.insert(inhistory_type.begin() + *inhistory_index, QALCULATE_HISTORY_ERROR);
2168 					inhistory_protected.insert(inhistory_protected.begin() + *inhistory_index, false);
2169 					inhistory_value.insert(inhistory_value.begin() + *inhistory_index, nr_of_new_expressions);
2170 					string history_message = "- ";
2171 					history_message += CALCULATOR->message()->message();
2172 					add_line_breaks(history_message, false, 2);
2173 					string history_str = "<span foreground=\"";
2174 					history_str += history_error_color;
2175 					history_str += "\">";
2176 					history_str += fix_history_string(history_message);
2177 					history_str += "</span>";
2178 					(*history_index_p)++;
2179 					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);
2180 				} else if(mtype == MESSAGE_WARNING) {
2181 					inhistory.insert(inhistory.begin() + *inhistory_index, CALCULATOR->message()->message());
2182 					inhistory_type.insert(inhistory_type.begin() + *inhistory_index, QALCULATE_HISTORY_WARNING);
2183 					inhistory_protected.insert(inhistory_protected.begin() + *inhistory_index, false);
2184 					inhistory_value.insert(inhistory_value.begin() + *inhistory_index, nr_of_new_expressions);
2185 					string history_message = "- ";
2186 					history_message += CALCULATOR->message()->message();
2187 					add_line_breaks(history_message, false, 2);
2188 					string history_str = "<span foreground=\"";
2189 					history_str += history_warning_color;
2190 					history_str += "\">";
2191 					history_str += fix_history_string(history_message);
2192 					history_str += "</span>";
2193 					(*history_index_p)++;
2194 					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);
2195 				} else {
2196 					inhistory.insert(inhistory.begin() + *inhistory_index, CALCULATOR->message()->message());
2197 					inhistory_type.insert(inhistory_type.begin() + *inhistory_index, QALCULATE_HISTORY_MESSAGE);
2198 					inhistory_protected.insert(inhistory_protected.begin() + *inhistory_index, false);
2199 					inhistory_value.insert(inhistory_value.begin() + *inhistory_index, nr_of_new_expressions);
2200 					string history_message = "- ";
2201 					history_message += CALCULATOR->message()->message();
2202 					add_line_breaks(history_message, false, 2);
2203 					string history_str = "<i>";
2204 					history_str += fix_history_string(history_message);
2205 					history_str += "</i>";
2206 					(*history_index_p)++;
2207 					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);
2208 				}
2209 				inhistory_added++;
2210 			}
2211 		}
2212 		index++;
2213 		if(!CALCULATOR->nextMessage()) break;
2214 	}
2215 	if(inhistory_added > 0) {
2216 		GtkTreeIter index_iter = history_iter;
2217 		gint index_hi = -1;
2218 		gint hi_add = 1;
2219 		while(gtk_tree_model_iter_previous(GTK_TREE_MODEL(historystore), &index_iter)) {
2220 			gtk_tree_model_get(GTK_TREE_MODEL(historystore), &index_iter, 1, &index_hi, -1);
2221 			if(index_hi >= 0) {
2222 				gtk_list_store_set(historystore, &index_iter, 1, index_hi + hi_add, -1);
2223 				if(inhistory_added > 1) {
2224 					inhistory_added--;
2225 					hi_add++;
2226 				}
2227 			}
2228 		}
2229 	}
2230 	if(!str.empty()) {
2231 		if(type == 1 || type == 3) {
2232 			gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(main_builder, "message_tooltip_icon")), str.c_str());
2233 			if(mtype_highest == MESSAGE_ERROR) {
2234 				gtk_image_set_from_icon_name(GTK_IMAGE(gtk_builder_get_object(main_builder, "message_tooltip_icon")), "dialog-error", GTK_ICON_SIZE_BUTTON);
2235 			} else if(mtype_highest == MESSAGE_WARNING) {
2236 				gtk_image_set_from_icon_name(GTK_IMAGE(gtk_builder_get_object(main_builder, "message_tooltip_icon")), "dialog-warning", GTK_ICON_SIZE_BUTTON);
2237 			} else {
2238 				gtk_image_set_from_icon_name(GTK_IMAGE(gtk_builder_get_object(main_builder, "message_tooltip_icon")), "dialog-information", GTK_ICON_SIZE_BUTTON);
2239 			}
2240 			update_expression_icons(EXPRESSION_INFO);
2241 			if(first_error && (auto_calculate || minimal_mode)) first_error = false;
2242 			if(first_error && !minimal_mode) {
2243 				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 icon in the upper right corner of the expression entry changes to reflect this. If you hold the pointer over or click the icon, the message will be shown."));
2244 				gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "message_icon")));
2245 				gtk_info_bar_set_message_type(GTK_INFO_BAR(gtk_builder_get_object(main_builder, "message_bar")), GTK_MESSAGE_INFO);
2246 				gtk_info_bar_set_show_close_button(GTK_INFO_BAR(gtk_builder_get_object(main_builder, "message_bar")), TRUE);
2247 				gtk_revealer_set_reveal_child(GTK_REVEALER(gtk_builder_get_object(main_builder, "message_revealer")), TRUE);
2248 				first_error = false;
2249 			}
2250 			return true;
2251 		} else if(type == 2) {
2252 			gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "message_label")), str.c_str());
2253 			gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(main_builder, "message_icon")));
2254 			if(mtype_highest == MESSAGE_ERROR) {
2255 				gtk_info_bar_set_message_type(GTK_INFO_BAR(gtk_builder_get_object(main_builder, "message_bar")), GTK_MESSAGE_ERROR);
2256 				gtk_image_set_from_icon_name(GTK_IMAGE(gtk_builder_get_object(main_builder, "message_icon")), "dialog-error-symbolic", GTK_ICON_SIZE_BUTTON);
2257 			} else if(mtype_highest == MESSAGE_WARNING) {
2258 				gtk_info_bar_set_message_type(GTK_INFO_BAR(gtk_builder_get_object(main_builder, "message_bar")), GTK_MESSAGE_WARNING);
2259 				gtk_image_set_from_icon_name(GTK_IMAGE(gtk_builder_get_object(main_builder, "message_icon")), "dialog-warning-symbolic", GTK_ICON_SIZE_BUTTON);
2260 			} else {
2261 				gtk_info_bar_set_message_type(GTK_INFO_BAR(gtk_builder_get_object(main_builder, "message_bar")), GTK_MESSAGE_INFO);
2262 				gtk_image_set_from_icon_name(GTK_IMAGE(gtk_builder_get_object(main_builder, "message_icon")), "dialog-information-symbolic", GTK_ICON_SIZE_BUTTON);
2263 			}
2264 			gtk_info_bar_set_show_close_button(GTK_INFO_BAR(gtk_builder_get_object(main_builder, "message_bar")), TRUE);
2265 			gtk_revealer_set_reveal_child(GTK_REVEALER(gtk_builder_get_object(main_builder, "message_revealer")), TRUE);
2266 		} else if(mtype_highest != MESSAGE_INFORMATION) {
2267 			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());
2268 			gtk_dialog_run(GTK_DIALOG(edialog));
2269 			gtk_widget_destroy(edialog);
2270 		}
2271 	}
2272 	return false;
2273 }
2274 
2275 extern GtkCellRenderer *history_renderer;
2276 extern gint history_scroll_width;
2277 
on_history_resize(GtkWidget *,GdkRectangle * alloc,gpointer)2278 void on_history_resize(GtkWidget*, GdkRectangle *alloc, gpointer) {
2279 	gint hsep = 0;
2280 	gtk_widget_style_get(historyview, "horizontal-separator", &hsep, NULL);
2281 	int prev_hw = history_width_a;
2282 	history_width_a = alloc->width - gtk_tree_view_column_get_width(history_index_column) - hsep * 4;
2283 	PangoLayout *layout = gtk_widget_create_pango_layout(historyview, "");
2284 	if(can_display_unicode_string_function_exact("��", historyview)) pango_layout_set_markup(layout, "<span size=\"small\"><sup> ��</sup></span>", -1);
2285 	else pango_layout_set_markup(layout, "<span size=\"x-small\"><sup> P</sup></span>", -1);
2286 	gint w = 0;
2287 	pango_layout_get_pixel_size(layout, &w, NULL);
2288 	g_object_unref(layout);
2289 	history_width_e = history_width_a - 6 - history_scroll_width - w;
2290 	history_width_a -= history_scroll_width * 2;
2291 	if(prev_hw != history_width_a) {
2292 		gtk_tree_view_column_set_max_width(history_column, history_width_a + history_scroll_width * 2);
2293 		reload_history();
2294 	}
2295 }
2296 
on_display_errors_timeout(gpointer)2297 gboolean on_display_errors_timeout(gpointer) {
2298 	if(stop_timeouts) return false;
2299 	if(!do_timeout) return true;
2300 	if(CALCULATOR->checkSaveFunctionCalled()) {
2301 		update_vmenu();
2302 	}
2303 	display_errors();
2304 	return true;
2305 }
2306 
on_activate_link(GtkLabel *,gchar * uri,gpointer)2307 gboolean on_activate_link(GtkLabel*, gchar *uri, gpointer) {
2308 #ifdef _WIN32
2309 	ShellExecuteA(NULL, "open", uri, NULL, NULL, SW_SHOWNORMAL);
2310 	return TRUE;
2311 #else
2312 	return FALSE;
2313 #endif
2314 }
2315 
2316 #ifdef AUTO_UPDATE
auto_update(string new_version)2317 void auto_update(string new_version) {
2318 	char selfpath[1000];
2319 	ssize_t n = readlink("/proc/self/exe", selfpath, 999);
2320 	if(n < 0 || n >= 999) {
2321 		GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(mainwindow), (GtkDialogFlags) 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("Path of executable not found."));
2322 		gtk_dialog_run(GTK_DIALOG(dialog));
2323 		gtk_widget_destroy(dialog);
2324 		return;
2325 	}
2326 	selfpath[n] = '\0';
2327 	gchar *selfdir = g_path_get_dirname(selfpath);
2328 	FILE *pipe = popen("curl --version 1>/dev/null", "w");
2329 	if(!pipe) {
2330 		GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(mainwindow), (GtkDialogFlags) 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("curl not found."));
2331 		gtk_dialog_run(GTK_DIALOG(dialog));
2332 		gtk_widget_destroy(dialog);
2333 		return;
2334 	}
2335 	pclose(pipe);
2336 	string tmpdir = getLocalTmpDir();
2337 	recursiveMakeDir(tmpdir);
2338 	string script = "#!/bin/sh\n\n";
2339 	script += "echo \"Updating Qalculate!...\";\n";
2340 	script += "sleep 1;\n";
2341 	script += "new_version="; script += new_version; script += ";\n";
2342 	script += "if cd \""; script += tmpdir; script += "\"; then\n";
2343 	script += "\tif curl -L -o qalculate-${new_version}-x86_64.tar.xz https://github.com/Qalculate/qalculate-gtk/releases/download/v${new_version}/qalculate-${new_version}-x86_64.tar.xz; then\n";
2344 	script += "\t\techo \"Extracting files...\";\n";
2345 	script += "\t\tif tar -xJf qalculate-${new_version}-x86_64.tar.xz; then\n";
2346 	script += "\t\t\tcd  qalculate-${new_version};\n";
2347 	script += "\t\t\tif cp -f qalculate-gtk \""; script += selfpath; script += "\"; then\n";
2348 	script += "\t\t\t\tcp -f qalc \""; script += selfdir; script += "/\";\n";
2349 	script += "\t\t\t\tcd ..;\n\t\t\trm -r qalculate-${new_version};\n\t\t\trm qalculate-${new_version}-x86_64.tar.xz;\n";
2350 	script += "\t\t\t\texit 0;\n";
2351 	script += "\t\t\tfi\n";
2352 	script += "\t\t\tcd ..;\n\t\trm -r qalculate-${new_version};\n";
2353 	script += "\t\tfi\n";
2354 	script += "\t\trm qalculate-${new_version}-x86_64.tar.xz;\n";
2355 	script += "\tfi\n";
2356 	script += "fi\n";
2357 	script += "echo \"Update failed\";\n";
2358 	script += "echo \"Press Enter to continue\";\n";
2359 	script += "read _;\n";
2360 	script += "exit 1\n";
2361 	g_free(selfdir);
2362 	std::ofstream ofs;
2363 	string scriptpath = tmpdir; scriptpath += "/update.sh";
2364 	ofs.open(scriptpath.c_str(), std::ofstream::out | std::ofstream::trunc);
2365 	ofs << script;
2366 	ofs.close();
2367 	chmod(scriptpath.c_str(), S_IRWXU);
2368 	string termcom = "#!/bin/sh\n\n";
2369 	termcom += "if [ $(command -v gnome-terminal) ]; then\n";
2370 	termcom += "\tif gnome-terminal --wait --version; then\n\t\tdetected_term=\"gnome-terminal --wait -- \";\n";
2371 	termcom += "\telse\n\t\tdetected_term=\"gnome-terminal --disable-factory -- \";\n\tfi\n";
2372 	termcom += "elif [ $(command -v xfce4-terminal) ]; then\n\tdetected_term=\"xfce4-terminal --disable-server -e \";\n";
2373 	termcom += "else\n";
2374 	termcom += "\tfor t in x-terminal-emulator konsole alacritty qterminal xterm urxvt rxvt kitty sakura terminology termite tilix; do\n\t\tif [ $(command -v $t) ]; then\n\t\t\tdetected_term=\"$t -e \";\n\t\t\tbreak\n\t\tfi\n\tdone\nfi\n";
2375 	termcom += "$detected_term "; termcom += scriptpath; termcom += ";\n";
2376 	termcom += "exec "; termcom += selfpath; termcom += "\n";
2377 	std::ofstream ofs2;
2378 	string scriptpath2 = tmpdir; scriptpath2 += "/terminal.sh";
2379 	ofs2.open(scriptpath2.c_str(), std::ofstream::out | std::ofstream::trunc);
2380 	ofs2 << termcom;
2381 	ofs2.close();
2382 	chmod(scriptpath2.c_str(), S_IRWXU);
2383 	GError *error = NULL;
2384 	g_spawn_command_line_async(scriptpath2.c_str(), &error);
2385 	if(error) {
2386 		gchar *error_str = g_locale_to_utf8(error->message, -1, NULL, NULL, NULL);
2387 		GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(mainwindow), (GtkDialogFlags) 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("Failed to run update script.\n%s"), error_str);
2388 		gtk_dialog_run(GTK_DIALOG(dialog));
2389 		gtk_widget_destroy(dialog);
2390 		g_free(error_str);
2391 		g_error_free(error);
2392 		return;
2393 	}
2394 	on_gcalc_exit(NULL, NULL, NULL);
2395 }
2396 #endif
2397 
check_for_new_version(bool do_not_show_again)2398 void check_for_new_version(bool do_not_show_again) {
2399 	string new_version;
2400 #ifdef _WIN32
2401 	int ret = checkAvailableVersion("windows", VERSION, &new_version, do_not_show_again ? 5 : 10);
2402 #else
2403 	int ret = checkAvailableVersion("qalculate-gtk", VERSION, &new_version, do_not_show_again ? 5 : 10);
2404 #endif
2405 	if(!do_not_show_again && ret <= 0) {
2406 		GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(mainwindow), (GtkDialogFlags) 0, ret < 0 ? GTK_MESSAGE_ERROR : GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, ret < 0 ? _("Failed to check for updates.") : _("No updates found."));
2407 		gtk_dialog_run(GTK_DIALOG(dialog));
2408 		gtk_widget_destroy(dialog);
2409 		if(ret < 0) return;
2410 	}
2411 	if(ret > 0 && (!do_not_show_again || new_version != last_found_version)) {
2412 		last_found_version = new_version;
2413 #ifdef AUTO_UPDATE
2414 		GtkWidget *dialog = gtk_dialog_new_with_buttons(NULL, GTK_WINDOW(mainwindow), (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT), _("_OK"), GTK_RESPONSE_ACCEPT, _("_Cancel"), GTK_RESPONSE_REJECT, NULL);
2415 #else
2416 		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);
2417 #endif
2418 		gtk_container_set_border_width(GTK_CONTAINER(dialog), 6);
2419 		GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
2420 		gtk_container_set_border_width(GTK_CONTAINER(hbox), 6);
2421 		gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), hbox);
2422 		GtkWidget *label = gtk_label_new(NULL);
2423 #ifdef AUTO_UPDATE
2424 		gchar *gstr = g_strdup_printf(_("A new version of %s is available at %s.\n\nDo you wish to update to version %s."), "Qalculate!", "<a href=\"http://qalculate.github.io/downloads.html\">qalculate.github.io</a>", new_version.c_str());
2425 #else
2426 		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>");
2427 #endif
2428 		gtk_label_set_markup(GTK_LABEL(label), gstr);
2429 		g_free(gstr);
2430 		gtk_container_add(GTK_CONTAINER(hbox), label);
2431 		g_signal_connect(G_OBJECT(label), "activate-link", G_CALLBACK(on_activate_link), NULL);
2432 		gtk_widget_show_all(dialog);
2433 #ifdef AUTO_UPDATE
2434 		if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
2435 			auto_update(new_version);
2436 		}
2437 #else
2438 		gtk_dialog_run(GTK_DIALOG(dialog));
2439 #endif
2440 		gtk_widget_destroy(dialog);
2441 	}
2442 	last_version_check_date.setToCurrentDate();
2443 }
2444 
on_check_version_idle(gpointer)2445 gboolean on_check_version_idle(gpointer) {
2446 	check_for_new_version(true);
2447 	return FALSE;
2448 }
2449 
display_function_hint(MathFunction * f,int arg_index=1)2450 bool display_function_hint(MathFunction *f, int arg_index = 1) {
2451 	if(!f) return false;
2452 	int iargs = f->maxargs();
2453 	Argument *arg;
2454 	Argument default_arg;
2455 	string str, str2, str3;
2456 	const ExpressionName *ename = &f->preferredName(false, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) statuslabel_l);
2457 	bool last_is_vctr = f->getArgumentDefinition(iargs) && f->getArgumentDefinition(iargs)->type() == ARGUMENT_TYPE_VECTOR;
2458 	if(arg_index > iargs && iargs >= 0 && !last_is_vctr) {
2459 		if(iargs == 1 && f->getArgumentDefinition(1) && f->getArgumentDefinition(1)->handlesVector()) {
2460 			return false;
2461 		}
2462 		gchar *gstr = g_strdup_printf(_("Too many arguments for %s()."), ename->name.c_str());
2463 		set_status_text(gstr, false, false, true);
2464 		g_free(gstr);
2465 		return true;
2466 	}
2467 	str += ename->name;
2468 	if(iargs < 0) {
2469 		iargs = f->minargs() + 1;
2470 		if(arg_index > iargs) arg_index = iargs;
2471 	}
2472 	if(arg_index > iargs && last_is_vctr) arg_index = iargs;
2473 	str += "(";
2474 	int i_reduced = 0;
2475 	if(iargs != 0) {
2476 		for(int i2 = 1; i2 <= iargs; i2++) {
2477 			if(i2 > f->minargs() && arg_index < i2) {
2478 				str += "[";
2479 			}
2480 			if(i2 > 1) {
2481 				str += CALCULATOR->getComma();
2482 				str += " ";
2483 			}
2484 			if(i2 == arg_index) str += "<b>";
2485 			arg = f->getArgumentDefinition(i2);
2486 			if(arg && !arg->name().empty()) {
2487 				str2 = arg->name();
2488 			} else {
2489 				str2 = _("argument");
2490 				str2 += " ";
2491 				str2 += i2s(i2);
2492 			}
2493 			if(i2 == arg_index) {
2494 				if(arg) {
2495 					if(i_reduced == 2) str3 = arg->print();
2496 					else str3 = arg->printlong();
2497 				} else {
2498 					Argument arg_default;
2499 					if(i_reduced == 2) str3 = arg_default.print();
2500 					else str3 = arg_default.printlong();
2501 				}
2502 				if(i_reduced != 2 && printops.use_unicode_signs) {
2503 					gsub(">=", SIGN_GREATER_OR_EQUAL, str3);
2504 					gsub("<=", SIGN_LESS_OR_EQUAL, str3);
2505 					gsub("!=", SIGN_NOT_EQUAL, str3);
2506 				}
2507 				if(!str3.empty()) {
2508 					str2 += ": ";
2509 					str2 += str3;
2510 				}
2511 				gsub("&", "&amp;", str2);
2512 				gsub(">", "&gt;", str2);
2513 				gsub("<", "&lt;", str2);
2514 				str += str2;
2515 				str += "</b>";
2516 				if(i_reduced < 2) {
2517 					PangoLayout *layout_test = gtk_widget_create_pango_layout(statuslabel_l, NULL);
2518 					pango_layout_set_markup(layout_test, str.c_str(), -1);
2519 					gint w, h;
2520 					pango_layout_get_pixel_size(layout_test, &w, &h);
2521 					if(w > gtk_widget_get_allocated_width(statuslabel_l) - 20) {
2522 						str = ename->name;
2523 						str += "(";
2524 						if(i2 != 1) {
2525 							str += "…";
2526 							i_reduced++;
2527 						} else {
2528 							i_reduced = 2;
2529 						}
2530 						i2--;
2531 					}
2532 					g_object_unref(layout_test);
2533 				} else {
2534 					i_reduced = 0;
2535 				}
2536 			} else {
2537 				gsub("&", "&amp;", str2);
2538 				gsub(">", "&gt;", str2);
2539 				gsub("<", "&lt;", str2);
2540 				str += str2;
2541 				if(i2 > f->minargs() && arg_index < i2) {
2542 					str += "]";
2543 				}
2544 			}
2545 		}
2546 		if(f->maxargs() < 0) {
2547 			str += CALCULATOR->getComma();
2548 			str += " …";
2549 		}
2550 	}
2551 	str += ")";
2552 	set_status_text(str);
2553 	return true;
2554 }
2555 
2556 void replace_interval_with_function(MathStructure &m);
2557 void update_result_bases();
2558 void fix_to_struct_gtk(MathStructure &m);
2559 
last_is_operator(string str,bool allow_exp=false)2560 bool last_is_operator(string str, bool allow_exp = false) {
2561 	remove_blank_ends(str);
2562 	if(str.empty()) return false;
2563 	if(str[str.length() - 1] > 0) {
2564 		if(is_in(OPERATORS "\\" LEFT_PARENTHESIS LEFT_VECTOR_WRAP, str[str.length() - 1]) && (str[str.length() - 1] != '!' || str.length() == 1)) return true;
2565 		if(allow_exp && is_in(EXP, str[str.length() - 1])) return true;
2566 		if(str.length() >= 3 && str[str.length() - 1] == 'r' && str[str.length() - 2] == 'o' && str[str.length() - 3] == 'x') return true;
2567 	} else {
2568 		if(str.length() >= 3 && str[str.length() - 2] < 0) {
2569 			str = str.substr(str.length() - 3);
2570 			if(str == "∧" || str == "∨" || str == "⊻" || str == "≤" || str == "≥" || str == "≠" || str == "∠" || str == expression_times_sign() || str == expression_divide_sign() || str == expression_add_sign() || str == expression_sub_sign()) {
2571 				return true;
2572 			}
2573 		}
2574 		if(str.length() >= 2) {
2575 			str = str.substr(str.length() - 2);
2576 			if(str == "¬" || str == expression_times_sign() || str == expression_divide_sign() || str == expression_add_sign() || str == expression_sub_sign()) return true;
2577 		}
2578 	}
2579 	return false;
2580 }
2581 
base_from_string(string str,int & base,Number & nbase,bool input_base=false)2582 void base_from_string(string str, int &base, Number &nbase, bool input_base = false) {
2583 	if(equalsIgnoreCase(str, "golden") || equalsIgnoreCase(str, "golden ratio") || str == "φ") base = BASE_GOLDEN_RATIO;
2584 	else if(equalsIgnoreCase(str, "roman") || equalsIgnoreCase(str, "roman")) base = BASE_ROMAN_NUMERALS;
2585 	else if(!input_base && (equalsIgnoreCase(str, "time") || equalsIgnoreCase(str, "time"))) base = BASE_TIME;
2586 	else if(str == "b26" || str == "B26") base = BASE_BIJECTIVE_26;
2587 	else if(equalsIgnoreCase(str, "unicode")) base = BASE_UNICODE;
2588 	else if(equalsIgnoreCase(str, "supergolden") || equalsIgnoreCase(str, "supergolden ratio") || str == "ψ") base = BASE_SUPER_GOLDEN_RATIO;
2589 	else if(equalsIgnoreCase(str, "pi") || str == "π") base = BASE_PI;
2590 	else if(str == "e") base = BASE_E;
2591 	else if(str == "sqrt(2)" || str == "sqrt 2" || str == "sqrt2" || str == "√2") base = BASE_SQRT2;
2592 	else {
2593 		EvaluationOptions eo = evalops;
2594 		eo.parse_options.base = 10;
2595 		MathStructure m;
2596 		eo.approximation = APPROXIMATION_TRY_EXACT;
2597 		CALCULATOR->beginTemporaryStopMessages();
2598 		CALCULATOR->calculate(&m, CALCULATOR->unlocalizeExpression(str, eo.parse_options), 350, eo);
2599 		if(CALCULATOR->endTemporaryStopMessages()) {
2600 			base = BASE_CUSTOM;
2601 			nbase.clear();
2602 		} else if(m.isInteger() && m.number() >= 2 && m.number() <= 36) {
2603 			base = m.number().intValue();
2604 		} else {
2605 			base = BASE_CUSTOM;
2606 			nbase = m.number();
2607 		}
2608 	}
2609 }
2610 
is_time(const MathStructure & m)2611 bool is_time(const MathStructure &m) {
2612 	bool b = false;
2613 	if(m.isUnit() && m.unit()->baseUnit()->referenceName() == "s") {
2614 		b = true;
2615 	} else if(m.isMultiplication() && m.size() == 2 && m[0].isNumber() && m[1].isUnit() && m[1].unit()->baseUnit()->referenceName() == "s") {
2616 		b = true;
2617 	} else if(m.isAddition() && m.size() > 0) {
2618 		b = true;
2619 		for(size_t i = 0; i < m.size(); i++) {
2620 			if(m[i].isUnit() && m[i].unit()->baseUnit()->referenceName() == "s") {}
2621 			else if(m[i].isMultiplication() && m[i].size() == 2 && m[i][0].isNumber() && m[i][1].isUnit() && m[i][1].unit()->baseUnit()->referenceName() == "s") {}
2622 			else {b = false; break;}
2623 		}
2624 	}
2625 	return b;
2626 }
2627 
2628 void add_to_expression_history(string str);
2629 
contains_temperature_unit_gtk(const MathStructure & m)2630 bool contains_temperature_unit_gtk(const MathStructure &m) {
2631 	if(m.isUnit()) {
2632 		return m.unit() == CALCULATOR->getUnitById(UNIT_ID_CELSIUS) || m.unit() == CALCULATOR->getUnitById(UNIT_ID_FAHRENHEIT);
2633 	}
2634 	if(m.isVariable() && m.variable()->isKnown()) {
2635 		return contains_temperature_unit_gtk(((KnownVariable*) m.variable())->get());
2636 	}
2637 	if(m.isFunction() && m.function()->id() == FUNCTION_ID_STRIP_UNITS) return false;
2638 	for(size_t i = 0; i < m.size(); i++) {
2639 		if(contains_temperature_unit_gtk(m[i])) return true;
2640 	}
2641 	return false;
2642 }
test_ask_tc(MathStructure & m)2643 bool test_ask_tc(MathStructure &m) {
2644 	if(tc_set || !contains_temperature_unit_gtk(m)) return false;
2645 	MathStructure *mp = &m;
2646 	if(m.isMultiplication() && m.size() == 2 && m[0].isMinusOne()) mp = &m[1];
2647 	else if(m.isNegate()) mp = &m[0];
2648 	if(mp->isUnit_exp()) return false;
2649 	if(mp->isMultiplication() && mp->size() > 0 && mp->last().isUnit_exp()) {
2650 		bool b = false;
2651 		for(size_t i = 0; i < mp->size() - 1; i++) {
2652 			if(contains_temperature_unit_gtk((*mp)[i])) {b = true; break;}
2653 		}
2654 		if(!b) return false;
2655 	}
2656 	return true;
2657 }
ask_tc()2658 bool ask_tc() {
2659 	GtkWidget *dialog = gtk_dialog_new_with_buttons(_("Temperature Calculation Mode"), GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT), _("_OK"), GTK_RESPONSE_ACCEPT, NULL);
2660 	gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
2661 	gtk_container_set_border_width(GTK_CONTAINER(dialog), 6);
2662 	GtkWidget *grid = gtk_grid_new();
2663 	gtk_grid_set_row_spacing(GTK_GRID(grid), 12);
2664 	gtk_grid_set_column_spacing(GTK_GRID(grid), 12);
2665 	gtk_container_set_border_width(GTK_CONTAINER(grid), 6);
2666 	gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), grid);
2667 	gtk_widget_show(grid);
2668 	GtkWidget *label = gtk_label_new(_("The expression is ambiguous.\nPlease select temperature calculation mode\n(the mode can later be changed in preferences)."));
2669 	gtk_widget_set_halign(label, GTK_ALIGN_START);
2670 	gtk_grid_attach(GTK_GRID(grid), label, 0, 0, 2, 1);
2671 	GtkWidget *w_abs = gtk_radio_button_new_with_label(NULL, _("Absolute"));
2672 	gtk_widget_set_valign(w_abs, GTK_ALIGN_START);
2673 	gtk_grid_attach(GTK_GRID(grid), w_abs, 0, 1, 1, 1);
2674 	label = gtk_label_new("<i>1 °C + 1 °C ≈ 274 K + 274 K ≈ 548 K\n1 °C + 5 °F ≈ 274 K + 258 K ≈ 532 K\n2 °C − 1 °C = 1 K\n1 °C − 5 °F = 16 K\n1 °C + 1 K = 2 °C</i>");
2675 	gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
2676 	gtk_widget_set_halign(label, GTK_ALIGN_START);
2677 	gtk_grid_attach(GTK_GRID(grid), label, 1, 1, 1, 1);
2678 	GtkWidget *w_rel = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(w_abs), _("Relative"));
2679 	gtk_widget_set_valign(w_rel, GTK_ALIGN_START);
2680 	gtk_grid_attach(GTK_GRID(grid), w_rel, 0, 2, 1, 1);
2681 	label = gtk_label_new("<i>1 °C + 1 °C = 2 °C\n1 °C + 5 °F = 1 °C + 5 °R ≈ 277 K\n2 °C − 1 °C = 1 °C\n1 °C − 5 °F = 1 °C - 5 °R ≈ −2 °C\n1 °C + 1 K = 2 °C</i>");
2682 	gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
2683 	gtk_widget_set_halign(label, GTK_ALIGN_START);
2684 	gtk_grid_attach(GTK_GRID(grid), label, 1, 2, 1, 1);
2685 	GtkWidget *w_hybrid = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(w_abs), _("Hybrid"));
2686 	gtk_widget_set_valign(w_hybrid, GTK_ALIGN_START);
2687 	gtk_grid_attach(GTK_GRID(grid), w_hybrid, 0, 3, 1, 1);
2688 	label = gtk_label_new("<i>1 °C + 1 °C ≈ 2 °C\n1 °C + 5 °F ≈ 274 K + 258 K ≈ 532 K\n2 °C − 1 °C = 1 °C\n1 °C − 5 °F = 16 K\n1 °C + 1 K = 2 °C</i>");
2689 	gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
2690 	gtk_widget_set_halign(label, GTK_ALIGN_START);
2691 	gtk_grid_attach(GTK_GRID(grid), label, 1, 3, 1, 1);
2692 	switch(CALCULATOR->getTemperatureCalculationMode()) {
2693 		case TEMPERATURE_CALCULATION_ABSOLUTE: {gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w_abs), TRUE); break;}
2694 		case TEMPERATURE_CALCULATION_RELATIVE: {gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w_rel), TRUE); break;}
2695 		default: {gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w_hybrid), TRUE); break;}
2696 	}
2697 	gtk_widget_show_all(grid);
2698 	gtk_dialog_run(GTK_DIALOG(dialog));
2699 	TemperatureCalculationMode tc_mode = TEMPERATURE_CALCULATION_HYBRID;
2700 	if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w_abs))) tc_mode = TEMPERATURE_CALCULATION_ABSOLUTE;
2701 	else if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w_rel))) tc_mode = TEMPERATURE_CALCULATION_RELATIVE;
2702 	gtk_widget_destroy(dialog);
2703 	tc_set = true;
2704 	if(tc_mode != CALCULATOR->getTemperatureCalculationMode()) {
2705 		CALCULATOR->setTemperatureCalculationMode(tc_mode);
2706 		return true;
2707 	}
2708 	return false;
2709 }
2710 
2711 vector<CalculatorMessage> autocalc_messages;
do_autocalc_history_timeout(gpointer)2712 gboolean do_autocalc_history_timeout(gpointer) {
2713 	autocalc_history_timeout_id = 0;
2714 	if(!do_timeout || !result_autocalculated || rpn_mode) return FALSE;
2715 	if((test_ask_tc(*parsed_mstruct) && ask_tc()) || check_exchange_rates(NULL, true)) {
2716 		execute_expression(true, false, OPERATION_ADD, NULL, false, 0, "", "", false);
2717 		return FALSE;
2718 	}
2719 	CALCULATOR->addMessages(&autocalc_messages);
2720 	result_text = get_expression_text();
2721 	add_to_expression_history(result_text);
2722 	string to_str = CALCULATOR->parseComments(result_text, evalops.parse_options);
2723 	if(!to_str.empty()) {
2724 		if(result_text.empty()) return FALSE;
2725 		else CALCULATOR->message(MESSAGE_INFORMATION, to_str.c_str(), NULL);
2726 	}
2727 	expression_has_changed = false;
2728 	setResult(NULL, true, true, true, "", 0, false, true);
2729 	if(!block_conversion_category_switch) {
2730 		Unit *u = CALCULATOR->findMatchingUnit(*mstruct);
2731 		if(u && !u->category().empty()) {
2732 			string s_cat = u->category();
2733 			if(s_cat.empty()) s_cat = _("Uncategorized");
2734 			if(s_cat != selected_unit_category) {
2735 				GtkTreeIter iter = convert_category_map[s_cat];
2736 				GtkTreePath *path = gtk_tree_model_get_path(gtk_tree_view_get_model(GTK_TREE_VIEW(tUnitSelectorCategories)), &iter);
2737 				gtk_tree_view_expand_to_path(GTK_TREE_VIEW(tUnitSelectorCategories), path);
2738 				gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(tUnitSelectorCategories), path, NULL, TRUE, 0.5, 0);
2739 				gtk_tree_path_free(path);
2740 				gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitSelectorCategories)), &iter);
2741 			}
2742 		}
2743 		if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "convert_button_continuous_conversion")))) {
2744 			gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitSelector)));
2745 		}
2746 	}
2747 	result_autocalculated = false;
2748 	return FALSE;
2749 }
2750 
2751 bool auto_calc_stopped_at_operator = false;
2752 
set_result_bases(const MathStructure & m)2753 void set_result_bases(const MathStructure &m) {
2754 	result_bin = ""; result_oct = "", result_dec = "", result_hex = "";
2755 	if(max_bases.isZero()) {max_bases = 2; max_bases ^= 64; min_bases = -max_bases;}
2756 	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))) {
2757 		Number nr;
2758 		if(m.isNumber()) {
2759 			nr = m.number();
2760 		} else {
2761 			nr = m[0].number();
2762 			nr.negate();
2763 		}
2764 		nr.round(printops.round_halfway_to_even);
2765 		PrintOptions po = printops;
2766 		po.show_ending_zeroes = false;
2767 		po.base_display = BASE_DISPLAY_NORMAL;
2768 		po.min_exp = 0;
2769 		if(printops.base != 2) {
2770 			po.base = 2;
2771 			result_bin = nr.print(po);
2772 		}
2773 		if(printops.base != 8) {
2774 			po.base = 8;
2775 			result_oct = nr.print(po);
2776 			size_t i = result_oct.find_first_of(NUMBERS);
2777 			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);
2778 		}
2779 		if(printops.base != 10) {
2780 			po.base = 10;
2781 			result_dec = nr.print(po);
2782 		}
2783 		if(printops.base != 16) {
2784 			po.base = 16;
2785 			result_hex = nr.print(po);
2786 			gsub("0x", "", result_hex);
2787 			size_t l = result_hex.length();
2788 			size_t i_after_minus = 0;
2789 			if(nr.isNegative()) {
2790 				if(l > 1 && result_hex[0] == '-') i_after_minus = 1;
2791 				else if(result_hex.find("−") == 0) i_after_minus = strlen("−");
2792 			}
2793 			for(int i = (int) l - 2; i > (int) i_after_minus; i -= 2) {
2794 				result_hex.insert(i, 1, ' ');
2795 			}
2796 			if(result_hex.length() > i_after_minus + 1 && result_hex[i_after_minus + 1] == ' ') result_hex.insert(i_after_minus, 1, '0');
2797 		}
2798 	}
2799 }
2800 
test_parsed_comparison_gtk(const MathStructure & m)2801 bool test_parsed_comparison_gtk(const MathStructure &m) {
2802 	if(m.isComparison()) return true;
2803 	if((m.isLogicalOr() || m.isLogicalAnd()) && m.size() > 0) {
2804 		for(size_t i = 0; i < m.size(); i++) {
2805 			if(!test_parsed_comparison_gtk(m[i])) return false;
2806 		}
2807 		return true;
2808 	}
2809 	return false;
2810 }
2811 
do_auto_calc(bool recalculate=true,string str=string ())2812 void do_auto_calc(bool recalculate = true, string str = string()) {
2813 	if(block_result_update || block_expression_execution) return;
2814 	MathStructure mauto;
2815 	bool do_factors = false, do_pfe = false, do_expand = false;
2816 	bool do_timeout_bak = do_timeout;
2817 
2818 	ComplexNumberForm cnf_bak = evalops.complex_number_form;
2819 	bool caf_bak = complex_angle_form;
2820 	bool b_units_saved = evalops.parse_options.units_enabled;
2821 	AutoPostConversion save_auto_post_conversion = evalops.auto_post_conversion;
2822 	MixedUnitsConversion save_mixed_units_conversion = evalops.mixed_units_conversion;
2823 	Number save_nbase;
2824 	bool custom_base_set = false;
2825 	int save_base = printops.base;
2826 	unsigned int save_bits = printops.binary_bits;
2827 	bool save_pre = printops.use_unit_prefixes;
2828 	bool save_cur = printops.use_prefixes_for_currencies;
2829 	bool save_allu = printops.use_prefixes_for_all_units;
2830 	bool save_all = printops.use_all_prefixes;
2831 	bool save_den = printops.use_denominator_prefix;
2832 	int save_bin = CALCULATOR->usesBinaryPrefixes();
2833 	NumberFractionFormat save_format = printops.number_fraction_format;
2834 	bool save_restrict_fraction_length = printops.restrict_fraction_length;
2835 	bool do_to = false;
2836 
2837 	if(recalculate) {
2838 		if(!mbak_convert.isUndefined()) mbak_convert.setUndefined();
2839 		auto_calc_stopped_at_operator = false;
2840 		if(autocalc_history_timeout_id != 0) {
2841 			g_source_remove(autocalc_history_timeout_id);
2842 			autocalc_history_timeout_id = 0;
2843 		}
2844 		bool origstr = str.empty();
2845 		if(origstr) str = get_expression_text();
2846 		if(origstr) CALCULATOR->parseComments(str, evalops.parse_options);
2847 		if(str.empty() || (origstr && (str == "MC" || str == "MS" || str == "M+" || str == "M-" || str == "M−"))) {clearresult(); return;}
2848 		if(origstr && str.length() > 1 && str[0] == '/') {
2849 			size_t i = str.find_first_not_of(SPACES, 1);
2850 			if(i != string::npos && str[i] > 0 && is_not_in(NUMBER_ELEMENTS OPERATORS, str[i])) {
2851 				clearresult(); return;
2852 			}
2853 		}
2854 		if(auto_calculate && evalops.parse_options.base != BASE_UNICODE && (evalops.parse_options.base != BASE_CUSTOM || (CALCULATOR->customInputBase() <= 62 && CALCULATOR->customInputBase() >= -62))) {
2855 			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;
2856 			GtkTextMark *mark = gtk_text_buffer_get_insert(expressionbuffer);
2857 			if(mark) {
2858 				GtkTextIter ipos;
2859 				gtk_text_buffer_get_iter_at_mark(expressionbuffer, &ipos, mark);
2860 				if(!gtk_text_iter_is_end(&ipos)) {
2861 					GtkTextIter iter = ipos;
2862 					gtk_text_iter_forward_char(&iter);
2863 					gchar *gstr = gtk_text_buffer_get_text(expressionbuffer, &ipos, &iter, FALSE);
2864 					string c2 = gstr;
2865 					g_free(gstr);
2866 					string c1;
2867 					if(!gtk_text_iter_is_start(&ipos)) {
2868 						iter = ipos;
2869 						gtk_text_iter_backward_char(&iter);
2870 						gstr = gtk_text_buffer_get_text(expressionbuffer, &iter, &ipos, FALSE);
2871 						c1 = gstr;
2872 						g_free(gstr);
2873 					}
2874 					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))) {
2875 						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()))) {
2876 							auto_calc_stopped_at_operator = true;
2877 							return;
2878 						}
2879 					}
2880 				}
2881 			}
2882 		}
2883 		if(origstr) {
2884 			to_caf = -1; to_fraction = false; to_prefix = 0; to_base = 0; to_bits = 0; to_nbase.clear();
2885 		}
2886 		string from_str = str, to_str, str_conv;
2887 		bool had_to_expression = false;
2888 		bool last_is_space = !from_str.empty() && is_in(SPACES, from_str[from_str.length() - 1]);
2889 		if(origstr && CALCULATOR->separateToExpression(from_str, to_str, evalops, true, false)) {
2890 			had_to_expression = true;
2891 			if(from_str.empty()) {
2892 				clearresult();
2893 				evalops.complex_number_form = cnf_bak;
2894 				evalops.auto_post_conversion = save_auto_post_conversion;
2895 				evalops.parse_options.units_enabled = b_units_saved;
2896 				evalops.mixed_units_conversion = save_mixed_units_conversion;
2897 				printops.custom_time_zone = 0;
2898 				printops.time_zone = TIME_ZONE_LOCAL;
2899 				return;
2900 			}
2901 			remove_duplicate_blanks(to_str);
2902 			string str_left;
2903 			string to_str1, to_str2;
2904 			while(true) {
2905 				if(last_is_space) to_str += " ";
2906 				CALCULATOR->separateToExpression(to_str, str_left, evalops, true, false);
2907 				remove_blank_ends(to_str);
2908 				size_t ispace = to_str.find_first_of(SPACES);
2909 				if(ispace != string::npos) {
2910 					to_str1 = to_str.substr(0, ispace);
2911 					remove_blank_ends(to_str1);
2912 					to_str2 = to_str.substr(ispace + 1);
2913 					remove_blank_ends(to_str2);
2914 				}
2915 				if(equalsIgnoreCase(to_str, "hex") || equalsIgnoreCase(to_str, "hexadecimal") || equalsIgnoreCase(to_str, _("hexadecimal"))) {
2916 					to_base = BASE_HEXADECIMAL;
2917 					do_to = true;
2918 				} else if(equalsIgnoreCase(to_str, "oct") || equalsIgnoreCase(to_str, "octal") || equalsIgnoreCase(to_str, _("octal"))) {
2919 					to_base = BASE_OCTAL;
2920 					do_to = true;
2921 				} else if(equalsIgnoreCase(to_str, "dec") || equalsIgnoreCase(to_str, "decimal") || equalsIgnoreCase(to_str, _("decimal"))) {
2922 					to_base = BASE_DECIMAL;
2923 					do_to = true;
2924 				} else if(equalsIgnoreCase(to_str, "duo") || equalsIgnoreCase(to_str, "duodecimal") || equalsIgnoreCase(to_str, _("duodecimal"))) {
2925 					to_base = BASE_DUODECIMAL;
2926 					do_to = true;
2927 				} else if(equalsIgnoreCase(to_str, "bin") || equalsIgnoreCase(to_str, "binary") || equalsIgnoreCase(to_str, _("binary"))) {
2928 					to_base = BASE_BINARY;
2929 					do_to = true;
2930 				} else if(equalsIgnoreCase(to_str, "roman") || equalsIgnoreCase(to_str, _("roman"))) {
2931 					to_base = BASE_ROMAN_NUMERALS;
2932 					do_to = true;
2933 				} else if(equalsIgnoreCase(to_str, "bijective") || equalsIgnoreCase(to_str, _("bijective"))) {
2934 					to_base = BASE_BIJECTIVE_26;
2935 					do_to = true;
2936 				} else if(equalsIgnoreCase(to_str, "sexa") || equalsIgnoreCase(to_str, "sexagesimal") || equalsIgnoreCase(to_str, _("sexagesimal"))) {
2937 					to_base = BASE_SEXAGESIMAL;
2938 					do_to = true;
2939 				} else if(equalsIgnoreCase(to_str, "fp32") || equalsIgnoreCase(to_str, "binary32") || equalsIgnoreCase(to_str, "float")) {
2940 					to_base = BASE_FP32;
2941 					do_to = true;
2942 				} else if(equalsIgnoreCase(to_str, "fp64") || equalsIgnoreCase(to_str, "binary64") || equalsIgnoreCase(to_str, "double")) {
2943 					to_base = BASE_FP64;
2944 					do_to = true;
2945 				} else if(equalsIgnoreCase(to_str, "fp16") || equalsIgnoreCase(to_str, "binary16")) {
2946 					to_base = BASE_FP16;
2947 					do_to = true;
2948 				} else if(equalsIgnoreCase(to_str, "fp80")) {
2949 					to_base = BASE_FP80;
2950 					do_to = true;
2951 				} else if(equalsIgnoreCase(to_str, "fp128") || equalsIgnoreCase(to_str, "binary128")) {
2952 					to_base = BASE_FP128;
2953 					do_to = true;
2954 				} else if(equalsIgnoreCase(to_str, "time") || equalsIgnoreCase(to_str, _("time"))) {
2955 					to_base = BASE_TIME;
2956 					do_to = true;
2957 				} else if(equalsIgnoreCase(to_str, "Unicode")) {
2958 					to_base = BASE_UNICODE;
2959 					do_to = true;
2960 				} else if(equalsIgnoreCase(to_str, "utc") || equalsIgnoreCase(to_str, "gmt")) {
2961 					printops.time_zone = TIME_ZONE_UTC;
2962 					do_to = true;
2963 				} else if(to_str.length() > 3 && equalsIgnoreCase(to_str.substr(0, 3), "bin") && is_in(NUMBERS, to_str[3])) {
2964 					to_base = BASE_BINARY;
2965 					int bits = s2i(to_str.substr(3));
2966 					if(bits >= 0) {
2967 						if(bits > 4096) to_bits = 4096;
2968 						else to_bits = bits;
2969 					}
2970 					do_to = true;
2971 				} else if(to_str.length() > 3 && equalsIgnoreCase(to_str.substr(0, 3), "hex") && is_in(NUMBERS, to_str[3])) {
2972 					to_base = BASE_HEXADECIMAL;
2973 					int bits = s2i(to_str.substr(3));
2974 					if(bits >= 0) {
2975 						if(bits > 4096) to_bits = 4096;
2976 						else to_bits = bits;
2977 					}
2978 					do_to = true;
2979 				} else if(to_str.length() > 3 && (equalsIgnoreCase(to_str.substr(0, 3), "utc") || equalsIgnoreCase(to_str.substr(0, 3), "gmt"))) {
2980 					to_str = to_str.substr(3);
2981 					remove_blanks(to_str);
2982 					bool b_minus = false;
2983 					if(to_str[0] == '+') {
2984 						to_str.erase(0, 1);
2985 					} else if(to_str[0] == '-') {
2986 						b_minus = true;
2987 						to_str.erase(0, 1);
2988 					} else if(to_str.find(SIGN_MINUS) == 0) {
2989 						b_minus = true;
2990 						to_str.erase(0, strlen(SIGN_MINUS));
2991 					}
2992 					unsigned int tzh = 0, tzm = 0;
2993 					int itz = 0;
2994 					if(!to_str.empty() && sscanf(to_str.c_str(), "%2u:%2u", &tzh, &tzm) > 0) {
2995 						itz = tzh * 60 + tzm;
2996 						if(b_minus) itz = -itz;
2997 					}
2998 					printops.time_zone = TIME_ZONE_CUSTOM;
2999 					printops.custom_time_zone = itz;
3000 					do_to = true;
3001 				} else if(to_str == "CET") {
3002 					printops.time_zone = TIME_ZONE_CUSTOM;
3003 					printops.custom_time_zone = 60;
3004 					do_to = true;
3005 				} else if(equalsIgnoreCase(to_str, "bases") || equalsIgnoreCase(to_str, _("bases"))) {
3006 					str = from_str;
3007 				} else if(equalsIgnoreCase(to_str, "calendars") || equalsIgnoreCase(to_str, _("calendars"))) {
3008 					str = from_str;
3009 				} else if(equalsIgnoreCase(to_str, "rectangular") || equalsIgnoreCase(to_str, "cartesian") || equalsIgnoreCase(to_str, _("rectangular")) || equalsIgnoreCase(to_str, _("cartesian"))) {
3010 					to_caf = 0;
3011 					evalops.complex_number_form = COMPLEX_NUMBER_FORM_RECTANGULAR;
3012 					do_to = true;
3013 				} else if(equalsIgnoreCase(to_str, "exponential") || equalsIgnoreCase(to_str, _("exponential"))) {
3014 					to_caf = 0;
3015 					evalops.complex_number_form = COMPLEX_NUMBER_FORM_EXPONENTIAL;
3016 					do_to = true;
3017 				} else if(equalsIgnoreCase(to_str, "polar") || equalsIgnoreCase(to_str, _("polar"))) {
3018 					to_caf = 0;
3019 					evalops.complex_number_form = COMPLEX_NUMBER_FORM_POLAR;
3020 					do_to = true;
3021 				} else if(to_str == "cis") {
3022 					to_caf = 0;
3023 					evalops.complex_number_form = COMPLEX_NUMBER_FORM_CIS;
3024 					do_to = true;
3025 				} else if(equalsIgnoreCase(to_str, "angle") || equalsIgnoreCase(to_str, _("angle")) || equalsIgnoreCase(to_str, "phasor") || equalsIgnoreCase(to_str, _("phasor"))) {
3026 					to_caf = 1;
3027 					evalops.complex_number_form = COMPLEX_NUMBER_FORM_CIS;
3028 					do_to = true;
3029 				} else if(equalsIgnoreCase(to_str, "optimal") || equalsIgnoreCase(to_str, _("optimal"))) {
3030 					evalops.parse_options.units_enabled = true;
3031 					evalops.auto_post_conversion = POST_CONVERSION_OPTIMAL_SI;
3032 					str_conv = "";
3033 					do_to = true;
3034 				} else if(equalsIgnoreCase(to_str, "base") || equalsIgnoreCase(to_str, _("base"))) {
3035 					evalops.parse_options.units_enabled = true;
3036 					evalops.auto_post_conversion = POST_CONVERSION_BASE;
3037 					str_conv = "";
3038 					do_to = true;
3039 				} else if(equalsIgnoreCase(to_str, "mixed") || equalsIgnoreCase(to_str, _("mixed"))) {
3040 					evalops.parse_options.units_enabled = true;
3041 					evalops.auto_post_conversion = POST_CONVERSION_NONE;
3042 					evalops.mixed_units_conversion = MIXED_UNITS_CONVERSION_FORCE_INTEGER;
3043 					do_to = true;
3044 				} else if(equalsIgnoreCase(to_str, "fraction") || equalsIgnoreCase(to_str, _("fraction"))) {
3045 					do_to = true;
3046 					to_fraction = true;
3047 				} else if(equalsIgnoreCase(to_str, "factors") || equalsIgnoreCase(to_str, _("factors")) || equalsIgnoreCase(to_str, "factor")) {
3048 					do_factors = true;
3049 					str = from_str;
3050 				} else if(equalsIgnoreCase(to_str, "partial fraction") || equalsIgnoreCase(to_str, _("partial fraction"))) {
3051 					do_pfe = true;
3052 					str = from_str;
3053 				} else if(equalsIgnoreCase(to_str1, "base") || equalsIgnoreCase(to_str1, _("base"))) {
3054 					base_from_string(to_str2, to_base, to_nbase);
3055 					do_to = true;
3056 				} else {
3057 					if(to_str[0] == '?') {
3058 						to_prefix = 1;
3059 					} else if(to_str.length() > 1 && to_str[1] == '?' && (to_str[0] == 'b' || to_str[0] == 'a' || to_str[0] == 'd')) {
3060 						to_prefix = to_str[0];
3061 					}
3062 					do_to = true;
3063 					if(!str_conv.empty()) str_conv += " to ";
3064 					str_conv += to_str;
3065 				}
3066 				if(str_left.empty()) break;
3067 				to_str = str_left;
3068 			}
3069 			if(do_to) {
3070 				str = from_str;
3071 				if(!str_conv.empty()) {
3072 					str += " to ";
3073 					str += str_conv;
3074 				}
3075 			}
3076 		}
3077 		if(origstr) {
3078 			size_t i = str.find_first_of(SPACES LEFT_PARENTHESIS);
3079 			if(i != string::npos) {
3080 				to_str = str.substr(0, i);
3081 				if(to_str == "factor" || equalsIgnoreCase(to_str, "factorize") || equalsIgnoreCase(to_str, _("factorize"))) {
3082 					str = str.substr(i + 1);
3083 					do_factors = true;
3084 				} else if(equalsIgnoreCase(to_str, "expand") || equalsIgnoreCase(to_str, _("expand"))) {
3085 					str = str.substr(i + 1);
3086 					do_expand = true;
3087 				}
3088 			}
3089 		}
3090 		if(origstr && str_conv.empty() && gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "convert_button_continuous_conversion"))) && gtk_expander_get_expanded(GTK_EXPANDER(expander_convert)) && !minimal_mode) {
3091 			ParseOptions pa = evalops.parse_options; pa.base = 10;
3092 			string ceu_str = CALCULATOR->unlocalizeExpression(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(main_builder, "convert_entry_unit"))), pa);
3093 			remove_blank_ends(ceu_str);
3094 			if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "convert_button_set_missing_prefixes"))) && !ceu_str.empty()) {
3095 				if(!ceu_str.empty() && ceu_str[0] != '0' && ceu_str[0] != '?' && ceu_str[0] != '+' && ceu_str[0] != '-' && (ceu_str.length() == 1 || ceu_str[1] != '?')) {
3096 					ceu_str = "?" + ceu_str;
3097 				}
3098 			}
3099 			if(ceu_str.empty()) {
3100 				parsed_tostruct->setUndefined();
3101 			} else {
3102 				if(ceu_str[0] == '?') {
3103 					to_prefix = 1;
3104 				} else if(ceu_str.length() > 1 && ceu_str[1] == '?' && (ceu_str[0] == 'b' || ceu_str[0] == 'a' || ceu_str[0] == 'd')) {
3105 					to_prefix = ceu_str[0];
3106 				}
3107 				parsed_tostruct->set(ceu_str);
3108 			}
3109 		} else {
3110 			parsed_tostruct->setUndefined();
3111 		}
3112 
3113 		do_timeout_bak = do_timeout;
3114 		do_timeout = false;
3115 
3116 		CALCULATOR->resetExchangeRatesUsed();
3117 
3118 		CALCULATOR->beginTemporaryStopMessages();
3119 		if(!CALCULATOR->calculate(&mauto, CALCULATOR->unlocalizeExpression(str, evalops.parse_options), 100, evalops, parsed_mstruct, parsed_tostruct)) {
3120 			mauto.setAborted();
3121 		} else if(do_factors || do_pfe || do_expand) {
3122 			CALCULATOR->startControl(100);
3123 			if(do_factors) {
3124 				if(!mauto.integerFactorize()) {
3125 					mauto.structure(STRUCTURING_FACTORIZE, evalops, true);
3126 				}
3127 			} else if(do_pfe) {
3128 				mauto.expandPartialFractions(evalops);
3129 			} else if(do_expand) {
3130 				mauto.expand(evalops);
3131 			}
3132 			if(CALCULATOR->aborted()) mauto.setAborted();
3133 			CALCULATOR->stopControl();
3134 		} else if(!str_conv.empty() && parsed_tostruct->containsType(STRUCT_UNIT, true) && !mauto.containsType(STRUCT_UNIT, false, true, true) && !parsed_mstruct->containsType(STRUCT_UNIT, false, true, true) && !CALCULATOR->hasToExpression(str_conv, false, evalops)) {
3135 			MathStructure to_struct(*parsed_tostruct);
3136 			to_struct.unformat();
3137 			to_struct = CALCULATOR->convertToOptimalUnit(to_struct, evalops, true);
3138 			fix_to_struct_gtk(to_struct);
3139 			if(!to_struct.isZero()) {
3140 				mauto.multiply(to_struct);
3141 				PrintOptions po = printops;
3142 				po.negative_exponents = false;
3143 				to_struct.format(po);
3144 				if(to_struct.isMultiplication() && to_struct.size() >= 2) {
3145 					if(to_struct[0].isOne()) to_struct.delChild(1, true);
3146 					else if(to_struct[1].isOne()) to_struct.delChild(2, true);
3147 				}
3148 				parsed_mstruct->multiply(to_struct);
3149 				CALCULATOR->calculate(&mauto, 100, evalops, CALCULATOR->unlocalizeExpression(str_conv, evalops.parse_options));
3150 			}
3151 		// Always perform conversion to optimal (SI) unit when the expression is a number multiplied by a unit and input equals output
3152 		} else if((!parsed_tostruct || parsed_tostruct->isUndefined()) && origstr && !had_to_expression && (evalops.approximation == APPROXIMATION_EXACT || evalops.auto_post_conversion == POST_CONVERSION_OPTIMAL || evalops.auto_post_conversion == POST_CONVERSION_NONE) && parsed_mstruct && ((parsed_mstruct->isMultiplication() && parsed_mstruct->size() == 2 && (*parsed_mstruct)[0].isNumber() && (*parsed_mstruct)[1].isUnit_exp() && parsed_mstruct->equals(mauto)) || (parsed_mstruct->isNegate() && (*parsed_mstruct)[0].isMultiplication() && (*parsed_mstruct)[0].size() == 2 && (*parsed_mstruct)[0][0].isNumber() && (*parsed_mstruct)[0][1].isUnit_exp() && mauto.isMultiplication() && mauto.size() == 2 && mauto[1] == (*parsed_mstruct)[0][1] && mauto[0].isNumber() && (*parsed_mstruct)[0][0].number() == -mauto[0].number()) || (parsed_mstruct->isUnit_exp() && parsed_mstruct->equals(mauto)))) {
3153 			Unit *u = NULL;
3154 			MathStructure *munit = NULL;
3155 			if(mauto.isMultiplication()) munit = &mauto[1];
3156 			else munit = &mauto;
3157 			if(munit->isUnit()) u = munit->unit();
3158 			else u = (*munit)[0].unit();
3159 			if(u && u->isCurrency()) {
3160 				if(evalops.local_currency_conversion && CALCULATOR->getLocalCurrency() && u != CALCULATOR->getLocalCurrency()) {
3161 					ApproximationMode abak = evalops.approximation;
3162 					if(evalops.approximation == APPROXIMATION_EXACT) evalops.approximation = APPROXIMATION_TRY_EXACT;
3163 					mauto.set(CALCULATOR->convertToOptimalUnit(mauto, evalops, true));
3164 					evalops.approximation = abak;
3165 				}
3166 			} else if(u && u->subtype() != SUBTYPE_BASE_UNIT && !u->isSIUnit()) {
3167 				MathStructure mbak(mauto);
3168 				if(evalops.auto_post_conversion == POST_CONVERSION_OPTIMAL || evalops.auto_post_conversion == POST_CONVERSION_NONE) {
3169 					if(munit->isUnit() && u->referenceName() == "oF") {
3170 						u = CALCULATOR->getActiveUnit("oC");
3171 						if(u) mauto.set(CALCULATOR->convert(mauto, u, evalops, true, false));
3172 					} else {
3173 						mauto.set(CALCULATOR->convertToOptimalUnit(mauto, evalops, true));
3174 					}
3175 				}
3176 				if(evalops.approximation == APPROXIMATION_EXACT && ((evalops.auto_post_conversion != POST_CONVERSION_OPTIMAL && evalops.auto_post_conversion != POST_CONVERSION_NONE) || mauto.equals(mbak))) {
3177 					evalops.approximation = APPROXIMATION_TRY_EXACT;
3178 					if(evalops.auto_post_conversion == POST_CONVERSION_BASE) mauto.set(CALCULATOR->convertToBaseUnits(mauto, evalops));
3179 					else mauto.set(CALCULATOR->convertToOptimalUnit(mauto, evalops, true));
3180 					evalops.approximation = APPROXIMATION_EXACT;
3181 				}
3182 			}
3183 		}
3184 		CALCULATOR->endTemporaryStopMessages(!mauto.isAborted(), &autocalc_messages);
3185 		if(!mauto.isAborted()) {
3186 			mstruct->set(mauto);
3187 			if(autocalc_history_delay >= 0 && auto_calculate) {
3188 				autocalc_history_timeout_id = g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE, autocalc_history_delay, do_autocalc_history_timeout, NULL, NULL);
3189 			}
3190 		}
3191 	} else {
3192 		do_timeout_bak = do_timeout;
3193 		do_timeout = false;
3194 	}
3195 	if(!recalculate || !mauto.isAborted()) {
3196 
3197 		CALCULATOR->beginTemporaryStopMessages();
3198 
3199 		CALCULATOR->startControl(100);
3200 
3201 		if(to_base != 0 || to_fraction || to_prefix != 0 || (to_caf >= 0 && to_caf != complex_angle_form)) {
3202 			if(to_base != 0 && (to_base != printops.base || to_bits != printops.binary_bits || (to_base == BASE_CUSTOM && to_nbase != CALCULATOR->customOutputBase()))) {
3203 				printops.base = to_base;
3204 				printops.binary_bits = to_bits;
3205 				if(to_base == BASE_CUSTOM) {
3206 					custom_base_set = true;
3207 					save_nbase = CALCULATOR->customOutputBase();
3208 					CALCULATOR->setCustomOutputBase(to_nbase);
3209 				}
3210 				do_to = true;
3211 			}
3212 			if(to_fraction && (printops.restrict_fraction_length || printops.number_fraction_format != FRACTION_COMBINED)) {
3213 				printops.restrict_fraction_length = false;
3214 				printops.number_fraction_format = FRACTION_COMBINED;
3215 				do_to = true;
3216 			}
3217 			if(to_caf >= 0 && to_caf != complex_angle_form) {
3218 				complex_angle_form = to_caf;
3219 				do_to = true;
3220 			}
3221 			if(to_prefix != 0) {
3222 				bool new_pre = printops.use_unit_prefixes;
3223 				bool new_cur = printops.use_prefixes_for_currencies;
3224 				bool new_allu = printops.use_prefixes_for_all_units;
3225 				bool new_all = printops.use_all_prefixes;
3226 				bool new_den = printops.use_denominator_prefix;
3227 				int new_bin = CALCULATOR->usesBinaryPrefixes();
3228 				new_pre = true;
3229 				if(to_prefix == 'b') {
3230 					int i = has_information_unit_gtk(*mstruct);
3231 					new_bin = (i > 0 ? 1 : 2);
3232 					if(i == 1) {
3233 						new_den = false;
3234 					} else if(i > 1) {
3235 						new_den = true;
3236 					} else {
3237 						new_cur = true;
3238 						new_allu = true;
3239 					}
3240 				} else {
3241 					new_cur = true;
3242 					new_allu = true;
3243 					if(to_prefix == 'a') new_all = true;
3244 					else if(to_prefix == 'd') new_bin = 0;
3245 				}
3246 				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) {
3247 					printops.use_unit_prefixes = new_pre;
3248 					printops.use_all_prefixes = new_all;
3249 					printops.use_prefixes_for_currencies = new_cur;
3250 					printops.use_prefixes_for_all_units = new_allu;
3251 					printops.use_denominator_prefix = new_den;
3252 					CALCULATOR->useBinaryPrefixes(new_bin);
3253 					do_to = true;
3254 				}
3255 			}
3256 		}
3257 
3258 		MathStructure *displayed_mstruct_pre = new MathStructure();
3259 		displayed_mstruct_pre->set(*mstruct);
3260 		if(printops.interval_display == INTERVAL_DISPLAY_INTERVAL) replace_interval_with_function(*displayed_mstruct_pre);
3261 
3262 		printops.allow_non_usable = true;
3263 		printops.can_display_unicode_string_arg = (void*) resultview;
3264 
3265 		date_map.clear();
3266 		date_approx_map.clear();
3267 		number_map.clear();
3268 		number_base_map.clear();
3269 		number_exp_map.clear();
3270 		number_exp_minus_map.clear();
3271 		number_approx_map.clear();
3272 
3273 		// convert time units to hours when using time format
3274 		if(printops.base == BASE_TIME && is_time(*displayed_mstruct_pre)) {
3275 			Unit *u = CALCULATOR->getActiveUnit("h");
3276 			if(u) {
3277 				displayed_mstruct_pre->divide(u);
3278 				displayed_mstruct_pre->eval(evalops);
3279 			}
3280 		}
3281 
3282 		if(printops.spell_out_logical_operators && parsed_mstruct && test_parsed_comparison_gtk(*parsed_mstruct)) {
3283 			if(displayed_mstruct_pre->isZero()) {
3284 				Variable *v = CALCULATOR->getActiveVariable("false");
3285 				if(v) displayed_mstruct_pre->set(v);
3286 			} else if(displayed_mstruct_pre->isOne()) {
3287 				Variable *v = CALCULATOR->getActiveVariable("true");
3288 				if(v) displayed_mstruct_pre->set(v);
3289 			}
3290 		}
3291 
3292 		displayed_mstruct_pre->removeDefaultAngleUnit(evalops);
3293 		displayed_mstruct_pre->format(printops);
3294 		displayed_mstruct_pre->removeDefaultAngleUnit(evalops);
3295 		tmp_surface = draw_structure(*displayed_mstruct_pre, printops, complex_angle_form, top_ips, NULL, 0);
3296 		if(tmp_surface && CALCULATOR->aborted()) {
3297 			CALCULATOR->endTemporaryStopMessages();
3298 			cairo_surface_destroy(tmp_surface);
3299 			tmp_surface = NULL;
3300 			clearresult();
3301 			displayed_mstruct_pre->unref();
3302 		} else if(tmp_surface) {
3303 			CALCULATOR->endTemporaryStopMessages(true);
3304 			scale_n = 0;
3305 			showing_first_time_message = FALSE;
3306 			if(surface_result) cairo_surface_destroy(surface_result);
3307 			if(displayed_mstruct) displayed_mstruct->unref();
3308 			displayed_mstruct = displayed_mstruct_pre;
3309 			displayed_printops = printops;
3310 			displayed_printops.allow_non_usable = true;
3311 			displayed_caf = complex_angle_form;
3312 			result_autocalculated = true;
3313 			display_aborted = false;
3314 			surface_result = tmp_surface;
3315 			first_draw_of_result = TRUE;
3316 			if(minimal_mode && !gtk_widget_is_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "resultoverlay")))) {
3317 				gint h = -1;
3318 				gtk_widget_get_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "expressionscrolled")), NULL, &h);
3319 				gtk_widget_set_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "expressionscrolled")), -1, gtk_widget_get_allocated_height(GTK_WIDGET(gtk_builder_get_object(main_builder, "expressionscrolled"))));
3320 				gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(main_builder, "statusseparator1")));
3321 				gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(main_builder, "resultoverlay")));
3322 				while(gtk_events_pending()) gtk_main_iteration();
3323 				gtk_widget_set_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "expressionscrolled")), -1, h);
3324 			}
3325 			gtk_widget_queue_draw(resultview);
3326 			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "menu_item_save_image")), true);
3327 			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_save_image")), true);
3328 			result_text = "";
3329 			result_text_long = "";
3330 			gtk_widget_set_tooltip_text(resultview, "");
3331 			if(!display_errors(NULL, NULL, NULL, 1)) update_expression_icons(EXPRESSION_CLEAR);
3332 			if(visible_keypad & PROGRAMMING_KEYPAD) {
3333 				set_result_bases(*displayed_mstruct);
3334 				update_result_bases();
3335 			}
3336 		} else {
3337 			displayed_mstruct_pre->unref();
3338 			CALCULATOR->endTemporaryStopMessages();
3339 			clearresult();
3340 		}
3341 
3342 		printops.can_display_unicode_string_arg = NULL;
3343 		printops.allow_non_usable = false;
3344 
3345 		CALCULATOR->stopControl();
3346 	} else {
3347 		auto_calculate = false;
3348 		clearresult();
3349 		auto_calculate = true;
3350 	}
3351 
3352 	if(do_to) {
3353 		printops.base = save_base;
3354 		printops.binary_bits = save_bits;
3355 		if(custom_base_set) CALCULATOR->setCustomOutputBase(save_nbase);
3356 		printops.use_unit_prefixes = save_pre;
3357 		printops.use_all_prefixes = save_all;
3358 		printops.use_prefixes_for_currencies = save_cur;
3359 		printops.use_prefixes_for_all_units = save_allu;
3360 		printops.use_denominator_prefix = save_den;
3361 		CALCULATOR->useBinaryPrefixes(save_bin);
3362 		printops.number_fraction_format = save_format;
3363 		printops.restrict_fraction_length = save_restrict_fraction_length;
3364 		complex_angle_form = caf_bak;
3365 		evalops.complex_number_form = cnf_bak;
3366 		evalops.auto_post_conversion = save_auto_post_conversion;
3367 		evalops.parse_options.units_enabled = b_units_saved;
3368 		evalops.mixed_units_conversion = save_mixed_units_conversion;
3369 		printops.custom_time_zone = 0;
3370 		printops.time_zone = TIME_ZONE_LOCAL;
3371 	}
3372 
3373 	do_timeout = do_timeout_bak;
3374 }
print_auto_calc()3375 void print_auto_calc() {
3376 	do_auto_calc(false);
3377 }
3378 
do_chain_mode(const gchar * op)3379 bool do_chain_mode(const gchar *op) {
3380 	if(!rpn_mode && chain_mode && !current_function && evalops.parse_options.base != BASE_UNICODE && (evalops.parse_options.base != BASE_CUSTOM || (CALCULATOR->customInputBase() <= 62 && CALCULATOR->customInputBase() >= -62))) {
3381 		GtkTextIter iend, istart;
3382 		gtk_text_buffer_get_iter_at_mark(expressionbuffer, &iend, gtk_text_buffer_get_insert(expressionbuffer));
3383 		if(gtk_text_buffer_get_has_selection(expressionbuffer)) {
3384 			GtkTextMark *mstart = gtk_text_buffer_get_selection_bound(expressionbuffer);
3385 			if(mstart) {
3386 				gtk_text_buffer_get_iter_at_mark(expressionbuffer, &istart, mstart);
3387 				if((!gtk_text_iter_is_start(&istart) || !gtk_text_iter_is_end(&iend)) && (!gtk_text_iter_is_end(&istart) || !gtk_text_iter_is_start(&iend))) return false;
3388 			}
3389 		} else {
3390 			if(!gtk_text_iter_is_end(&iend)) return false;
3391 		}
3392 		string str = get_expression_text();
3393 		remove_blanks(str);
3394 		if(str.empty() || str[0] == '/' || CALCULATOR->hasToExpression(str, true, evalops) || CALCULATOR->hasWhereExpression(str, evalops) || last_is_operator(str)) return false;
3395 		size_t par_n = 0, vec_n = 0;
3396 		for(size_t i = 0; i < str.length(); i++) {
3397 			if(str[i] == LEFT_PARENTHESIS_CH) par_n++;
3398 			else if(par_n > 0 && str[i] == RIGHT_PARENTHESIS_CH) par_n--;
3399 			else if(str[i] == LEFT_VECTOR_WRAP_CH) vec_n++;
3400 			else if(vec_n > 0 && str[i] == RIGHT_VECTOR_WRAP_CH) vec_n--;
3401 		}
3402 		if(par_n > 0 || vec_n > 0) return false;
3403 		if(!auto_calculate) do_auto_calc(true);
3404 		rpn_mode = true;
3405 		if(get_expression_text().find_first_not_of(NUMBER_ELEMENTS SPACE) != string::npos && (!parsed_mstruct || ((!parsed_mstruct->isMultiplication() || op != expression_times_sign()) && (!parsed_mstruct->isAddition() || (op != expression_add_sign() && op != expression_sub_sign())) && (!parsed_mstruct->isBitwiseOr() || strcmp(op, BITWISE_OR) != 0) && (!parsed_mstruct->isBitwiseAnd() || strcmp(op, BITWISE_AND) != 0)))) {
3406 			block_add_to_undo++;
3407 			gtk_text_buffer_get_start_iter(expressionbuffer, &istart);
3408 			gtk_text_buffer_insert(expressionbuffer, &istart, "(", -1);
3409 			gtk_text_buffer_get_end_iter(expressionbuffer, &iend);
3410 			gtk_text_buffer_insert(expressionbuffer, &iend, ")", -1);
3411 			gtk_text_buffer_place_cursor(expressionbuffer, &iend);
3412 			block_add_to_undo--;
3413 		} else if(gtk_text_buffer_get_has_selection(expressionbuffer)) {
3414 			gtk_text_buffer_get_end_iter(expressionbuffer, &iend);
3415 			gtk_text_buffer_place_cursor(expressionbuffer, &iend);
3416 		}
3417 		insert_text(op);
3418 		rpn_mode = false;
3419 		return true;
3420 	}
3421 	return false;
3422 }
3423 
3424 MathStructure *current_from_struct = NULL;
3425 Unit *current_from_unit = NULL;
3426 
display_parse_status()3427 void display_parse_status() {
3428 	current_function = NULL;
3429 	if(!display_expression_status) return;
3430 	if(block_display_parse) return;
3431 	GtkTextIter istart, iend, ipos;
3432 	gtk_text_buffer_get_start_iter(expressionbuffer, &istart);
3433 	gtk_text_buffer_get_end_iter(expressionbuffer, &iend);
3434 	gchar *gtext = gtk_text_buffer_get_text(expressionbuffer, &istart, &iend, FALSE);
3435 	string text = gtext, str_f;
3436 	g_free(gtext);
3437 	if(text.empty()) {
3438 		set_status_text("", true, false, false);
3439 		parsed_expression = "";
3440 		expression_has_changed2 = false;
3441 		return;
3442 	}
3443 	string to_str = CALCULATOR->parseComments(text, evalops.parse_options);
3444 	if(!to_str.empty() && text.empty()) {
3445 		text = CALCULATOR->f_message->referenceName();
3446 		text += "(";
3447 		text += to_str;
3448 		text += ")";
3449 	}
3450 	if(text[0] == '/' && text.length() > 1) {
3451 		size_t i = text.find_first_not_of(SPACES, 1);
3452 		if(i != string::npos && text[i] > 0 && is_not_in(NUMBER_ELEMENTS OPERATORS, text[i])) {
3453 			set_status_text("qalc command", true, false, false);
3454 			return;
3455 		}
3456 	} else if(text == "MC") {
3457 		set_status_text(_("MC (memory clear)"), true, false, false);
3458 		return;
3459 	} else if(text == "MS") {
3460 		set_status_text(_("MS (memory store)"), true, false, false);
3461 		return;
3462 	} else if(text == "M+") {
3463 		set_status_text(_("M+ (memory plus)"), true, false, false);
3464 		return;
3465 	} else if(text == "M-" || text == "M−") {
3466 		set_status_text(_("M− (memory minus)"), true, false, false);
3467 		return;
3468 	}
3469 	remove_duplicate_blanks(text);
3470 	size_t i = text.find_first_of(SPACES LEFT_PARENTHESIS);
3471 	if(i != string::npos) {
3472 		str_f = text.substr(0, i);
3473 		if(str_f == "factor" || equalsIgnoreCase(str_f, "factorize") || equalsIgnoreCase(str_f, _("factorize"))) {
3474 			text = text.substr(i + 1);
3475 			str_f = _("factorize");
3476 		} else if(equalsIgnoreCase(str_f, "expand") || equalsIgnoreCase(str_f, _("expand"))) {
3477 			text = text.substr(i + 1);
3478 			str_f = _("expand");
3479 		} else {
3480 			str_f = "";
3481 		}
3482 	}
3483 	GtkTextMark *mark = gtk_text_buffer_get_insert(expressionbuffer);
3484 	if(mark) gtk_text_buffer_get_iter_at_mark(expressionbuffer, &ipos, mark);
3485 	else ipos = iend;
3486 	MathStructure mparse, mfunc;
3487 	bool full_parsed = false;
3488 	string str_e, str_u, str_w;
3489 	bool had_errors = false, had_warnings = false;
3490 	evalops.parse_options.preserve_format = true;
3491 	if(!gtk_text_iter_is_start(&ipos)) {
3492 		evalops.parse_options.unended_function = &mfunc;
3493 		CALCULATOR->beginTemporaryStopMessages();
3494 		if(current_from_struct) {current_from_struct->unref(); current_from_struct = NULL; current_from_unit = NULL;}
3495 		if(!gtk_text_iter_is_end(&ipos)) {
3496 			gtext = gtk_text_buffer_get_text(expressionbuffer, &istart, &ipos, FALSE);
3497 			str_e = CALCULATOR->unlocalizeExpression(gtext, evalops.parse_options);
3498 			bool b = CALCULATOR->separateToExpression(str_e, str_u, evalops, false, !auto_calculate);
3499 			b = CALCULATOR->separateWhereExpression(str_e, str_w, evalops) || b;
3500 			if(!b) {
3501 				CALCULATOR->parse(&mparse, str_e, evalops.parse_options);
3502 			}
3503 			g_free(gtext);
3504 		} else {
3505 			str_e = CALCULATOR->unlocalizeExpression(text, evalops.parse_options);
3506 			bool b = CALCULATOR->separateToExpression(str_e, str_u, evalops, false, !auto_calculate);
3507 			b = CALCULATOR->separateWhereExpression(str_e, str_w, evalops) || b;
3508 			if(!b) {
3509 				CALCULATOR->parse(&mparse, str_e, evalops.parse_options);
3510 				full_parsed = true;
3511 			}
3512 		}
3513 		int warnings_count;
3514 		had_errors = CALCULATOR->endTemporaryStopMessages(NULL, &warnings_count) > 0;
3515 		had_warnings = warnings_count > 0;
3516 		evalops.parse_options.unended_function = NULL;
3517 	}
3518 	bool b_func = false;
3519 	if(mfunc.isFunction()) {
3520 		current_function = mfunc.function();
3521 		if(mfunc.countChildren() == 0) {
3522 			current_function_index = 1;
3523 			b_func = display_function_hint(mfunc.function(), 1);
3524 		} else {
3525 			current_function_index = mfunc.countChildren();
3526 			b_func = display_function_hint(mfunc.function(), mfunc.countChildren());
3527 		}
3528 	}
3529 	if(expression_has_changed2) {
3530 		bool last_is_space = false;
3531 		if(!full_parsed) {
3532 			CALCULATOR->beginTemporaryStopMessages();
3533 			str_e = CALCULATOR->unlocalizeExpression(text, evalops.parse_options);
3534 			last_is_space = is_in(SPACES, str_e[str_e.length() - 1]);
3535 			if(CALCULATOR->separateToExpression(str_e, str_u, evalops, false, !auto_calculate) && !str_e.empty()) {
3536 				if(!current_from_struct) {
3537 					current_from_struct = new MathStructure;
3538 					EvaluationOptions eo = evalops;
3539 					eo.structuring = STRUCTURING_NONE;
3540 					eo.mixed_units_conversion = MIXED_UNITS_CONVERSION_NONE;
3541 					eo.auto_post_conversion = POST_CONVERSION_NONE;
3542 					eo.complex_number_form = COMPLEX_NUMBER_FORM_RECTANGULAR;
3543 					eo.expand = -2;
3544 					if(!CALCULATOR->calculate(current_from_struct, str_e, 20, eo)) current_from_struct->setAborted();
3545 					current_from_unit = CALCULATOR->findMatchingUnit(*current_from_struct);
3546 				}
3547 			} else if(current_from_struct) {
3548 				current_from_struct->unref();
3549 				current_from_struct = NULL;
3550 				current_from_unit = NULL;
3551 			}
3552 			CALCULATOR->separateWhereExpression(str_e, str_w, evalops);
3553 			if(!str_e.empty()) CALCULATOR->parse(&mparse, str_e, evalops.parse_options);
3554 			int warnings_count;
3555 			had_errors = CALCULATOR->endTemporaryStopMessages(NULL, &warnings_count) > 0;
3556 			had_warnings = warnings_count > 0;
3557 		}
3558 		PrintOptions po;
3559 		po.preserve_format = true;
3560 		po.show_ending_zeroes = evalops.parse_options.read_precision != DONT_READ_PRECISION && !CALCULATOR->usesIntervalArithmetic() && evalops.parse_options.base > BASE_CUSTOM;
3561 		po.lower_case_e = printops.lower_case_e;
3562 		po.lower_case_numbers = printops.lower_case_numbers;
3563 		po.base_display = printops.base_display;
3564 		po.twos_complement = printops.twos_complement;
3565 		po.hexadecimal_twos_complement = printops.hexadecimal_twos_complement;
3566 		po.base = evalops.parse_options.base;
3567 		Number nr_base;
3568 		if(po.base == BASE_CUSTOM && (CALCULATOR->usesIntervalArithmetic() || CALCULATOR->customInputBase().isRational()) && (CALCULATOR->customInputBase().isInteger() || !CALCULATOR->customInputBase().isNegative()) && (CALCULATOR->customInputBase() > 1 || CALCULATOR->customInputBase() < -1)) {
3569 			nr_base = CALCULATOR->customOutputBase();
3570 			CALCULATOR->setCustomOutputBase(CALCULATOR->customInputBase());
3571 		} else if(po.base == BASE_CUSTOM || (po.base < BASE_CUSTOM && !CALCULATOR->usesIntervalArithmetic() && po.base != BASE_UNICODE && po.base != BASE_BIJECTIVE_26)) {
3572 			po.base = 10;
3573 			po.min_exp = 6;
3574 			po.use_max_decimals = true;
3575 			po.max_decimals = 5;
3576 			po.preserve_format = false;
3577 		}
3578 		po.abbreviate_names = false;
3579 		po.hide_underscore_spaces = true;
3580 		po.use_unicode_signs = printops.use_unicode_signs;
3581 		po.digit_grouping = printops.digit_grouping;
3582 		po.multiplication_sign = printops.multiplication_sign;
3583 		po.division_sign = printops.division_sign;
3584 		po.short_multiplication = false;
3585 		po.excessive_parenthesis = true;
3586 		po.improve_division_multipliers = false;
3587 		po.can_display_unicode_string_function = &can_display_unicode_string_function;
3588 		po.can_display_unicode_string_arg = (void*) statuslabel_l;
3589 		po.spell_out_logical_operators = printops.spell_out_logical_operators;
3590 		po.restrict_to_parent_precision = false;
3591 		po.interval_display = INTERVAL_DISPLAY_PLUSMINUS;
3592 		if(str_e.empty()) {
3593 			parsed_expression = "";
3594 		} else {
3595 			CALCULATOR->beginTemporaryStopMessages();
3596 			mparse.format(po);
3597 			parsed_expression = mparse.print(po);
3598 			CALCULATOR->endTemporaryStopMessages();
3599 		}
3600 		if(!str_w.empty()) {
3601 			CALCULATOR->beginTemporaryStopMessages();
3602 			CALCULATOR->parse(&mparse, str_w, evalops.parse_options);
3603 			int warnings_count;
3604 			had_errors = CALCULATOR->endTemporaryStopMessages(NULL, &warnings_count) > 0 || had_errors;
3605 			had_warnings = warnings_count > 0 || had_warnings || (!mparse.isLogicalAnd() && !mparse.isComparison());
3606 			parsed_expression += CALCULATOR->localWhereString();
3607 			CALCULATOR->beginTemporaryStopMessages();
3608 			mparse.format(po);
3609 			parsed_expression += mparse.print(po);
3610 			CALCULATOR->endTemporaryStopMessages();
3611 		}
3612 		if(!str_u.empty()) {
3613 			string str_u2;
3614 			size_t parse_l = parsed_expression.length();
3615 			bool had_to_conv = false;
3616 			MathStructure *mparse2 = NULL;
3617 			while(true) {
3618 				if(last_is_space) str_u += " ";
3619 				CALCULATOR->separateToExpression(str_u, str_u2, evalops, false, false);
3620 				remove_blank_ends(str_u);
3621 				if(parsed_expression.empty()) {
3622 					parsed_expression += CALCULATOR->localToString(false);
3623 					parsed_expression += " ";
3624 				} else {
3625 					parsed_expression += CALCULATOR->localToString();
3626 				}
3627 				remove_duplicate_blanks(str_u);
3628 				string to_str1, to_str2;
3629 				size_t ispace = str_u.find_first_of(SPACES);
3630 				if(ispace != string::npos) {
3631 					to_str1 = str_u.substr(0, ispace);
3632 					remove_blank_ends(to_str1);
3633 					to_str2 = str_u.substr(ispace + 1);
3634 					remove_blank_ends(to_str2);
3635 				}
3636 				if(equalsIgnoreCase(str_u, "hex") || equalsIgnoreCase(str_u, "hexadecimal") || equalsIgnoreCase(str_u, _("hexadecimal"))) {
3637 					parsed_expression += _("hexadecimal number");
3638 				} else if(equalsIgnoreCase(str_u, "oct") || equalsIgnoreCase(str_u, "octal") || equalsIgnoreCase(str_u, _("octal"))) {
3639 					parsed_expression += _("octal number");
3640 				} else if(equalsIgnoreCase(str_u, "dec") || equalsIgnoreCase(str_u, "decimal") || equalsIgnoreCase(str_u, _("decimal"))) {
3641 					parsed_expression += _("decimal number");
3642 				} else if(equalsIgnoreCase(str_u, "duo") || equalsIgnoreCase(str_u, "duodecimal") || equalsIgnoreCase(str_u, _("duodecimal"))) {
3643 					parsed_expression += _("duodecimal number");
3644 				} else if(equalsIgnoreCase(str_u, "bin") || equalsIgnoreCase(str_u, "binary") || equalsIgnoreCase(str_u, _("binary"))) {
3645 					parsed_expression += _("binary number");
3646 				} else if(equalsIgnoreCase(str_u, "roman") || equalsIgnoreCase(str_u, _("roman"))) {
3647 					parsed_expression += _("roman numerals");
3648 				} else if(equalsIgnoreCase(str_u, "bijective") || equalsIgnoreCase(str_u, _("bijective"))) {
3649 					parsed_expression += _("bijective base-26");
3650 				} else if(equalsIgnoreCase(str_u, "sexa") || equalsIgnoreCase(str_u, "sexagesimal") || equalsIgnoreCase(str_u, _("sexagesimal"))) {
3651 					parsed_expression += _("sexagesimal number");
3652 				} else if(equalsIgnoreCase(str_u, "fp32") || equalsIgnoreCase(str_u, "binary32") || equalsIgnoreCase(str_u, "float")) {
3653 					parsed_expression += _("32-bit floating point");
3654 				} else if(equalsIgnoreCase(str_u, "fp64") || equalsIgnoreCase(str_u, "binary64") || equalsIgnoreCase(str_u, "double")) {
3655 					parsed_expression += _("64-bit floating point");
3656 				} else if(equalsIgnoreCase(str_u, "fp16") || equalsIgnoreCase(str_u, "binary16")) {
3657 					parsed_expression += _("16-bit floating point");
3658 				} else if(equalsIgnoreCase(str_u, "fp80")) {
3659 					parsed_expression += _("80-bit (x86) floating point");
3660 				} else if(equalsIgnoreCase(str_u, "fp128") || equalsIgnoreCase(str_u, "binary128")) {
3661 					parsed_expression += _("128-bit floating point");
3662 				} else if(equalsIgnoreCase(str_u, "time") || equalsIgnoreCase(str_u, _("time"))) {
3663 					parsed_expression += _("time format");
3664 				} else if(equalsIgnoreCase(str_u, "unicode")) {
3665 					parsed_expression += _("Unicode");
3666 				} else if(equalsIgnoreCase(str_u, "bases") || equalsIgnoreCase(str_u, _("bases"))) {
3667 					parsed_expression += _("number bases");
3668 				} else if(equalsIgnoreCase(str_u, "calendars") || equalsIgnoreCase(str_u, _("calendars"))) {
3669 					parsed_expression += _("calendars");
3670 				} else if(equalsIgnoreCase(str_u, "optimal") || equalsIgnoreCase(str_u, _("optimal"))) {
3671 					parsed_expression += _("optimal unit");
3672 				} else if(equalsIgnoreCase(str_u, "base") || equalsIgnoreCase(str_u, _("base"))) {
3673 					parsed_expression += _("base units");
3674 				} else if(equalsIgnoreCase(str_u, "mixed") || equalsIgnoreCase(str_u, _("mixed"))) {
3675 					parsed_expression += _("mixed units");
3676 				} else if(equalsIgnoreCase(str_u, "fraction") || equalsIgnoreCase(str_u, _("fraction"))) {
3677 					parsed_expression += _("fraction");
3678 				} else if(equalsIgnoreCase(str_u, "factors") || equalsIgnoreCase(str_u, _("factors")) || equalsIgnoreCase(str_u, "factor")) {
3679 					parsed_expression += _("factors");
3680 				} else if(equalsIgnoreCase(str_u, "partial fraction") || equalsIgnoreCase(str_u, _("partial fraction"))) {
3681 					parsed_expression += _("expanded partial fractions");
3682 				} else if(equalsIgnoreCase(str_u, "rectangular") || equalsIgnoreCase(str_u, "cartesian") || equalsIgnoreCase(str_u, _("rectangular")) || equalsIgnoreCase(str_u, _("cartesian"))) {
3683 					parsed_expression += _("complex rectangular form");
3684 				} else if(equalsIgnoreCase(str_u, "exponential") || equalsIgnoreCase(str_u, _("exponential"))) {
3685 					parsed_expression += _("complex exponential form");
3686 				} else if(equalsIgnoreCase(str_u, "polar") || equalsIgnoreCase(str_u, _("polar"))) {
3687 					parsed_expression += _("complex polar form");
3688 				} else if(str_u == "cis") {
3689 					parsed_expression += _("complex cis form");
3690 				} else if(equalsIgnoreCase(str_u, "angle") || equalsIgnoreCase(str_u, _("angle"))) {
3691 					parsed_expression += _("complex angle notation");
3692 				} else if(equalsIgnoreCase(str_u, "phasor") || equalsIgnoreCase(str_u, _("phasor"))) {
3693 					parsed_expression += _("complex phasor notation");
3694 				} else if(equalsIgnoreCase(str_u, "utc") || equalsIgnoreCase(str_u, "gmt")) {
3695 					parsed_expression += _("UTC time zone");
3696 				} else if(str_u.length() > 3 && (equalsIgnoreCase(str_u.substr(0, 3), "utc") || equalsIgnoreCase(str_u.substr(0, 3), "gmt"))) {
3697 					str_u = str_u.substr(3);
3698 					parsed_expression += "UTC";
3699 					remove_blanks(str_u);
3700 					bool b_minus = false;
3701 					if(str_u[0] == '+') {
3702 						str_u.erase(0, 1);
3703 					} else if(str_u[0] == '-') {
3704 						b_minus = true;
3705 						str_u.erase(0, 1);
3706 					} else if(str_u.find(SIGN_MINUS) == 0) {
3707 						b_minus = true;
3708 						str_u.erase(0, strlen(SIGN_MINUS));
3709 					}
3710 					unsigned int tzh = 0, tzm = 0;
3711 					int itz = 0;
3712 					if(!str_u.empty() && sscanf(str_u.c_str(), "%2u:%2u", &tzh, &tzm) > 0) {
3713 						itz = tzh * 60 + tzm;
3714 					} else {
3715 						had_errors = true;
3716 					}
3717 					if(itz > 0) {
3718 						if(b_minus) parsed_expression += '-';
3719 						else parsed_expression += '+';
3720 						if(itz < 60) {
3721 							parsed_expression += "00";
3722 						} else {
3723 							if(itz < 60 * 10) parsed_expression += '0';
3724 							parsed_expression += i2s(itz / 60);
3725 						}
3726 						if(itz % 60 > 0) {
3727 							parsed_expression += ":";
3728 							if(itz % 60 < 10) parsed_expression += '0';
3729 							parsed_expression += i2s(itz % 60);
3730 						}
3731 					}
3732 				} else if(str_u.length() > 3 && equalsIgnoreCase(str_u.substr(0, 3), "bin") && is_in(NUMBERS, str_u[3])) {
3733 					unsigned int bits = s2i(str_u.substr(3));
3734 					if(bits > 4096) bits = 4096;
3735 					parsed_expression += i2s(bits);
3736 					parsed_expression += "-bit ";
3737 					parsed_expression += _("binary number");
3738 				} else if(str_u.length() > 3 && equalsIgnoreCase(str_u.substr(0, 3), "hex") && is_in(NUMBERS, str_u[3])) {
3739 					unsigned int bits = s2i(str_u.substr(3));
3740 					if(bits > 4096) bits = 4096;
3741 					parsed_expression += i2s(bits);
3742 					parsed_expression += "-bit ";
3743 					parsed_expression += _("hexadecimal number");
3744 				} else if(str_u == "CET") {
3745 					parsed_expression += "UTC";
3746 					parsed_expression += "+01";
3747 				} else if(equalsIgnoreCase(to_str1, "base") || equalsIgnoreCase(to_str1, _("base"))) {
3748 					gchar *gstr = g_strdup_printf(_("number base %s"), to_str2.c_str());
3749 					parsed_expression += gstr;
3750 					g_free(gstr);
3751 				} else {
3752 					Variable *v = CALCULATOR->getVariable(str_u);
3753 					if(v && !v->isKnown()) v = NULL;
3754 					if(v && CALCULATOR->getUnit(str_u)) v = NULL;
3755 					if(v) {
3756 						mparse = v;
3757 					} else {
3758 						CALCULATOR->beginTemporaryStopMessages();
3759 						CompositeUnit cu("", "temporary_composite_parse", "", str_u);
3760 						int warnings_count;
3761 						had_errors = CALCULATOR->endTemporaryStopMessages(NULL, &warnings_count) > 0 || had_errors;
3762 						had_warnings = had_warnings || warnings_count > 0;
3763 						bool b_unit = mparse.containsType(STRUCT_UNIT, false, true, true);
3764 						mparse = cu.generateMathStructure(true);
3765 						mparse.format(po);
3766 						if(!had_to_conv && !mparse.isZero() && !b_unit && !str_e.empty() && str_w.empty()) {
3767 							CALCULATOR->beginTemporaryStopMessages();
3768 							MathStructure to_struct(mparse);
3769 							to_struct.unformat();
3770 							to_struct = CALCULATOR->convertToOptimalUnit(to_struct, evalops, true);
3771 							fix_to_struct_gtk(to_struct);
3772 							if(!to_struct.isZero()) {
3773 								mparse2 = new MathStructure();
3774 								CALCULATOR->parse(mparse2, str_e, evalops.parse_options);
3775 								po.preserve_format = false;
3776 								to_struct.format(po);
3777 								po.preserve_format = true;
3778 								if(to_struct.isMultiplication() && to_struct.size() >= 2) {
3779 									if(to_struct[0].isOne()) to_struct.delChild(1, true);
3780 									else if(to_struct[1].isOne()) to_struct.delChild(2, true);
3781 								}
3782 								mparse2->multiply(to_struct);
3783 							}
3784 							CALCULATOR->endTemporaryStopMessages();
3785 						}
3786 					}
3787 					CALCULATOR->beginTemporaryStopMessages();
3788 					parsed_expression += mparse.print(po);
3789 					CALCULATOR->endTemporaryStopMessages();
3790 					if(had_to_conv && mparse2) {
3791 						mparse2->unref();
3792 						mparse2 = NULL;
3793 					}
3794 					had_to_conv = true;
3795 				}
3796 				if(str_u2.empty()) break;
3797 				str_u = str_u2;
3798 			}
3799 			if(mparse2) {
3800 				mparse2->format(po);
3801 				parsed_expression.replace(0, parse_l, mparse2->print(po));
3802 				mparse2->unref();
3803 			}
3804 		}
3805 		if(po.base == BASE_CUSTOM) CALCULATOR->setCustomOutputBase(nr_base);
3806 		parsed_had_errors = had_errors; parsed_had_warnings = had_warnings;
3807 		if(!str_f.empty()) {str_f += " "; parsed_expression.insert(0, str_f);}
3808 		gsub("&", "&amp;", parsed_expression);
3809 		gsub(">", "&gt;", parsed_expression);
3810 		gsub("<", "&lt;", parsed_expression);
3811 		if(!b_func) set_status_text(parsed_expression.c_str(), true, had_errors, had_warnings);
3812 		expression_has_changed2 = false;
3813 	} else if(!b_func) {
3814 		set_status_text(parsed_expression.c_str(), true, parsed_had_errors, parsed_had_warnings);
3815 	}
3816 	evalops.parse_options.preserve_format = false;
3817 }
3818 
3819 
highlight_parentheses()3820 void highlight_parentheses() {
3821 	GtkTextMark *mcur = gtk_text_buffer_get_insert(expressionbuffer);
3822 	if(!mcur) return;
3823 	GtkTextIter icur, istart, iend;
3824 	gtk_text_buffer_get_iter_at_mark(expressionbuffer, &icur, mcur);
3825 	gtk_text_buffer_get_start_iter(expressionbuffer, &istart);
3826 	gtk_text_buffer_get_end_iter(expressionbuffer, &iend);
3827 	gtk_text_buffer_remove_tag(expressionbuffer, expression_par_tag, &istart, &iend);
3828 	bool b = false;
3829 	b = (gtk_text_iter_get_char(&icur) == ')');
3830 	if(!b && gtk_text_iter_backward_char(&icur)) {
3831 		b = (gtk_text_iter_get_char(&icur) == ')');
3832 		if(!b) gtk_text_iter_forward_char(&icur);
3833 	}
3834 	if(b) {
3835 		GtkTextIter ipar2 = icur;
3836 		int pars = 1;
3837 		while(gtk_text_iter_backward_char(&ipar2)) {
3838 			if(gtk_text_iter_get_char(&ipar2) == ')') {
3839 				pars++;
3840 			} else if(gtk_text_iter_get_char(&ipar2) == '(') {
3841 				pars--;
3842 				if(pars == 0) break;
3843 			}
3844 		}
3845 		if(pars == 0) {
3846 			GtkTextIter inext = icur;
3847 			gtk_text_iter_forward_char(&inext);
3848 			gtk_text_buffer_apply_tag(expressionbuffer, expression_par_tag, &icur, &inext);
3849 			inext = ipar2;
3850 			gtk_text_iter_forward_char(&inext);
3851 			gtk_text_buffer_apply_tag(expressionbuffer, expression_par_tag, &ipar2, &inext);
3852 		}
3853 	} else {
3854 		b = (gtk_text_iter_get_char(&icur) == '(');
3855 		if(!b && gtk_text_iter_backward_char(&icur)) {
3856 			b = (gtk_text_iter_get_char(&icur) == '(');
3857 			if(!b) gtk_text_iter_forward_char(&icur);
3858 		}
3859 		if(b) {
3860 			GtkTextIter ipar2 = icur;
3861 			int pars = 1;
3862 			while(gtk_text_iter_forward_char(&ipar2)) {
3863 				if(gtk_text_iter_get_char(&ipar2) == '(') {
3864 					pars++;
3865 				} else if(gtk_text_iter_get_char(&ipar2) == ')') {
3866 					pars--;
3867 					if(pars == 0) break;
3868 				}
3869 			}
3870 			if(pars == 0) {
3871 				GtkTextIter inext = icur;
3872 				gtk_text_iter_forward_char(&inext);
3873 				gtk_text_buffer_apply_tag(expressionbuffer, expression_par_tag, &icur, &inext);
3874 				inext = ipar2;
3875 				gtk_text_iter_forward_char(&inext);
3876 				gtk_text_buffer_apply_tag(expressionbuffer, expression_par_tag, &ipar2, &inext);
3877 			}
3878 		}
3879 	}
3880 }
3881 
on_expressionbuffer_cursor_position_notify()3882 void on_expressionbuffer_cursor_position_notify() {
3883 	cursor_has_moved = true;
3884 	if(expression_has_changed_pos) {
3885 		expression_has_changed_pos = false;
3886 		return;
3887 	}
3888 	gtk_widget_hide(completion_window);
3889 	if(!check_expression_position) return;
3890 	highlight_parentheses();
3891 	display_parse_status();
3892 	if(autocalc_history_timeout_id) {
3893 		g_source_remove(autocalc_history_timeout_id);
3894 		autocalc_history_timeout_id = 0;
3895 		if(autocalc_history_delay >= 0) autocalc_history_timeout_id = g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE, autocalc_history_delay, do_autocalc_history_timeout, NULL, NULL);
3896 	}
3897 	if(auto_calc_stopped_at_operator) do_auto_calc();
3898 }
3899 
3900 /*
3901 	set focus on expression entry without losing selection
3902 */
focus_keeping_selection()3903 void focus_keeping_selection() {
3904 	if(gtk_widget_is_focus(expressiontext)) return;
3905 	gtk_widget_grab_focus(expressiontext);
3906 }
3907 
get_selected_function()3908 MathFunction *get_selected_function() {
3909 	return selected_function;
3910 }
3911 
get_edited_function()3912 MathFunction *get_edited_function() {
3913 	return edited_function;
3914 }
get_edited_unit()3915 Unit *get_edited_unit() {
3916 	return edited_unit;
3917 }
get_edited_dataset()3918 DataSet *get_edited_dataset() {
3919 	return edited_dataset;
3920 }
get_edited_dataproperty()3921 DataProperty *get_edited_dataproperty() {
3922 	return edited_dataproperty;
3923 }
get_edited_variable()3924 KnownVariable *get_edited_variable() {
3925 	return edited_variable;
3926 }
get_edited_unknown()3927 UnknownVariable *get_edited_unknown() {
3928 	return edited_unknown;
3929 }
get_edited_matrix()3930 KnownVariable *get_edited_matrix() {
3931 	return edited_matrix;
3932 }
3933 
get_edited_argument()3934 Argument *get_edited_argument() {
3935 	return edited_argument;
3936 }
get_selected_argument()3937 Argument *get_selected_argument() {
3938 	return selected_argument;
3939 }
get_selected_subfunction()3940 size_t get_selected_subfunction() {
3941 	return selected_subfunction;
3942 }
3943 
get_selected_variable()3944 Variable *get_selected_variable() {
3945 	return selected_variable;
3946 }
3947 
get_selected_unit()3948 Unit *get_selected_unit() {
3949 	return selected_unit;
3950 }
3951 
get_selected_to_unit()3952 Unit *get_selected_to_unit() {
3953 	return selected_to_unit;
3954 }
3955 
generate_units_tree_struct()3956 void generate_units_tree_struct() {
3957 	size_t cat_i, cat_i_prev;
3958 	bool b;
3959 	string str, cat, cat_sub;
3960 	Unit *u = NULL;
3961 	unit_cats.items.clear();
3962 	unit_cats.objects.clear();
3963 	unit_cats.parent = NULL;
3964 	ia_units.clear();
3965 	list<tree_struct>::iterator it;
3966 	for(size_t i = 0; i < CALCULATOR->units.size(); i++) {
3967 		if(!CALCULATOR->units[i]->isActive()) {
3968 			b = false;
3969 			for(size_t i3 = 0; i3 < ia_units.size(); i3++) {
3970 				u = (Unit*) ia_units[i3];
3971 				if(string_is_less(CALCULATOR->units[i]->title(true, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) expressiontext), u->title(true, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) expressiontext))) {
3972 					b = true;
3973 					ia_units.insert(ia_units.begin() + i3, (void*) CALCULATOR->units[i]);
3974 					break;
3975 				}
3976 			}
3977 			if(!b) ia_units.push_back((void*) CALCULATOR->units[i]);
3978 		} else {
3979 			tree_struct *item = &unit_cats;
3980 			if(!CALCULATOR->units[i]->category().empty()) {
3981 				cat = CALCULATOR->units[i]->category();
3982 				cat_i = cat.find("/"); cat_i_prev = 0;
3983 				b = false;
3984 				while(true) {
3985 					if(cat_i == string::npos) {
3986 						cat_sub = cat.substr(cat_i_prev, cat.length() - cat_i_prev);
3987 					} else {
3988 						cat_sub = cat.substr(cat_i_prev, cat_i - cat_i_prev);
3989 					}
3990 					b = false;
3991 					for(it = item->items.begin(); it != item->items.end(); ++it) {
3992 						if(cat_sub == it->item) {
3993 							item = &*it;
3994 							b = true;
3995 							break;
3996 						}
3997 					}
3998 					if(!b) {
3999 						tree_struct cat;
4000 						item->items.push_back(cat);
4001 						it = item->items.end();
4002 						--it;
4003 						it->parent = item;
4004 						item = &*it;
4005 						item->item = cat_sub;
4006 					}
4007 					if(cat_i == string::npos) {
4008 						break;
4009 					}
4010 					cat_i_prev = cat_i + 1;
4011 					cat_i = cat.find("/", cat_i_prev);
4012 				}
4013 			}
4014 			b = false;
4015 			for(size_t i3 = 0; i3 < item->objects.size(); i3++) {
4016 				u = (Unit*) item->objects[i3];
4017 				if(string_is_less(CALCULATOR->units[i]->title(true, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) expressiontext), u->title(true, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) expressiontext))) {
4018 					b = true;
4019 					item->objects.insert(item->objects.begin() + i3, (void*) CALCULATOR->units[i]);
4020 					break;
4021 				}
4022 			}
4023 			if(!b) item->objects.push_back((void*) CALCULATOR->units[i]);
4024 		}
4025 	}
4026 
4027 	unit_cats.sort();
4028 
4029 }
generate_variables_tree_struct()4030 void generate_variables_tree_struct() {
4031 
4032 	size_t cat_i, cat_i_prev;
4033 	bool b;
4034 	string str, cat, cat_sub;
4035 	Variable *v = NULL;
4036 	variable_cats.items.clear();
4037 	variable_cats.objects.clear();
4038 	variable_cats.parent = NULL;
4039 	ia_variables.clear();
4040 	list<tree_struct>::iterator it;
4041 	for(size_t i = 0; i < CALCULATOR->variables.size(); i++) {
4042 		if(!CALCULATOR->variables[i]->isActive()) {
4043 			//deactivated variable
4044 			b = false;
4045 			for(size_t i3 = 0; i3 < ia_variables.size(); i3++) {
4046 				v = (Variable*) ia_variables[i3];
4047 				if(string_is_less(CALCULATOR->variables[i]->title(true, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) expressiontext), v->title(true, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) expressiontext))) {
4048 					b = true;
4049 					ia_variables.insert(ia_variables.begin() + i3, (void*) CALCULATOR->variables[i]);
4050 					break;
4051 				}
4052 			}
4053 			if(!b) ia_variables.push_back((void*) CALCULATOR->variables[i]);
4054 		} else {
4055 			tree_struct *item = &variable_cats;
4056 			if(!CALCULATOR->variables[i]->category().empty()) {
4057 				cat = CALCULATOR->variables[i]->category();
4058 				cat_i = cat.find("/"); cat_i_prev = 0;
4059 				b = false;
4060 				while(true) {
4061 					if(cat_i == string::npos) {
4062 						cat_sub = cat.substr(cat_i_prev, cat.length() - cat_i_prev);
4063 					} else {
4064 						cat_sub = cat.substr(cat_i_prev, cat_i - cat_i_prev);
4065 					}
4066 					b = false;
4067 					for(it = item->items.begin(); it != item->items.end(); ++it) {
4068 						if(cat_sub == it->item) {
4069 							item = &*it;
4070 							b = true;
4071 							break;
4072 						}
4073 					}
4074 					if(!b) {
4075 						tree_struct cat;
4076 						item->items.push_back(cat);
4077 						it = item->items.end();
4078 						--it;
4079 						it->parent = item;
4080 						item = &*it;
4081 						item->item = cat_sub;
4082 					}
4083 					if(cat_i == string::npos) {
4084 						break;
4085 					}
4086 					cat_i_prev = cat_i + 1;
4087 					cat_i = cat.find("/", cat_i_prev);
4088 				}
4089 			}
4090 			b = false;
4091 			for(size_t i3 = 0; i3 < item->objects.size(); i3++) {
4092 				v = (Variable*) item->objects[i3];
4093 				if(string_is_less(CALCULATOR->variables[i]->title(true, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) expressiontext), v->title(true, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) expressiontext))) {
4094 					b = true;
4095 					item->objects.insert(item->objects.begin() + i3, (void*) CALCULATOR->variables[i]);
4096 					break;
4097 				}
4098 			}
4099 			if(!b) item->objects.push_back((void*) CALCULATOR->variables[i]);
4100 		}
4101 	}
4102 
4103 	variable_cats.sort();
4104 
4105 }
generate_functions_tree_struct()4106 void generate_functions_tree_struct() {
4107 
4108 	size_t cat_i, cat_i_prev;
4109 	bool b;
4110 	string str, cat, cat_sub;
4111 	MathFunction *f = NULL;
4112 	function_cats.items.clear();
4113 	function_cats.objects.clear();
4114 	function_cats.parent = NULL;
4115 	ia_functions.clear();
4116 	list<tree_struct>::iterator it;
4117 
4118 	for(size_t i = 0; i < CALCULATOR->functions.size(); i++) {
4119 		if(!CALCULATOR->functions[i]->isActive()) {
4120 			//deactivated function
4121 			b = false;
4122 			for(size_t i3 = 0; i3 < ia_functions.size(); i3++) {
4123 				f = (MathFunction*) ia_functions[i3];
4124 				if(string_is_less(CALCULATOR->functions[i]->title(true, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) expressiontext), f->title(true, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) expressiontext))) {
4125 					b = true;
4126 					ia_functions.insert(ia_functions.begin() + i3, (void*) CALCULATOR->functions[i]);
4127 					break;
4128 				}
4129 			}
4130 			if(!b) ia_functions.push_back((void*) CALCULATOR->functions[i]);
4131 		} else {
4132 			tree_struct *item = &function_cats;
4133 			if(!CALCULATOR->functions[i]->category().empty()) {
4134 				cat = CALCULATOR->functions[i]->category();
4135 				cat_i = cat.find("/"); cat_i_prev = 0;
4136 				b = false;
4137 				while(true) {
4138 					if(cat_i == string::npos) {
4139 						cat_sub = cat.substr(cat_i_prev, cat.length() - cat_i_prev);
4140 					} else {
4141 						cat_sub = cat.substr(cat_i_prev, cat_i - cat_i_prev);
4142 					}
4143 					b = false;
4144 					for(it = item->items.begin(); it != item->items.end(); ++it) {
4145 						if(cat_sub == it->item) {
4146 							item = &*it;
4147 							b = true;
4148 							break;
4149 						}
4150 					}
4151 					if(!b) {
4152 						tree_struct cat;
4153 						item->items.push_back(cat);
4154 						it = item->items.end();
4155 						--it;
4156 						it->parent = item;
4157 						item = &*it;
4158 						item->item = cat_sub;
4159 					}
4160 					if(cat_i == string::npos) {
4161 						break;
4162 					}
4163 					cat_i_prev = cat_i + 1;
4164 					cat_i = cat.find("/", cat_i_prev);
4165 				}
4166 			}
4167 			b = false;
4168 			for(size_t i3 = 0; i3 < item->objects.size(); i3++) {
4169 				f = (MathFunction*) item->objects[i3];
4170 				if(string_is_less(CALCULATOR->functions[i]->title(true, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) expressiontext), f->title(true, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) expressiontext))) {
4171 					b = true;
4172 					item->objects.insert(item->objects.begin() + i3, (void*) CALCULATOR->functions[i]);
4173 					break;
4174 				}
4175 			}
4176 			if(!b) item->objects.push_back((void*) CALCULATOR->functions[i]);
4177 		}
4178 	}
4179 
4180 	function_cats.sort();
4181 
4182 }
4183 
4184 /*
4185 	generate the function categories tree in manage functions dialog
4186 */
update_functions_tree()4187 void update_functions_tree() {
4188 	if(!functions_builder) return;
4189 	GtkTreeIter iter, iter2, iter3;
4190 	GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(tFunctionCategories));
4191 	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tFunctionCategories));
4192 	g_signal_handlers_block_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tFunctionCategories_selection_changed, NULL);
4193 	gtk_tree_store_clear(tFunctionCategories_store);
4194 	g_signal_handlers_unblock_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tFunctionCategories_selection_changed, NULL);
4195 	gtk_tree_store_append(tFunctionCategories_store, &iter3, NULL);
4196 	gtk_tree_store_set(tFunctionCategories_store, &iter3, 0, _("All"), 1, _("All"), -1);
4197 	string str;
4198 	tree_struct *item, *item2;
4199 	function_cats.it = function_cats.items.begin();
4200 	if(function_cats.it != function_cats.items.end()) {
4201 		item = &*function_cats.it;
4202 		++function_cats.it;
4203 		item->it = item->items.begin();
4204 	} else {
4205 		item = NULL;
4206 	}
4207 	str = "";
4208 	iter2 = iter3;
4209 	while(item) {
4210 		gtk_tree_store_append(tFunctionCategories_store, &iter, &iter2);
4211 		str += "/";
4212 		str += item->item;
4213 		gtk_tree_store_set(tFunctionCategories_store, &iter, 0, item->item.c_str(), 1, str.c_str(), -1);
4214 		if(str == selected_function_category) {
4215 			EXPAND_TO_ITER(model, tFunctionCategories, iter)
4216 			gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tFunctionCategories)), &iter);
4217 		}
4218 		while(item && item->it == item->items.end()) {
4219 			size_t str_i = str.rfind("/");
4220 			if(str_i == string::npos) {
4221 				str = "";
4222 			} else {
4223 				str = str.substr(0, str_i);
4224 			}
4225 			item = item->parent;
4226 			gtk_tree_model_iter_parent(model, &iter2, &iter);
4227 			iter = iter2;
4228 		}
4229 		if(item) {
4230 			item2 = &*item->it;
4231 			if(item->it == item->items.begin()) iter2 = iter;
4232 			++item->it;
4233 			item = item2;
4234 			item->it = item->items.begin();
4235 		}
4236 	}
4237 	if(!function_cats.objects.empty()) {
4238 		//add "Uncategorized" category if there are functions without category
4239 		gtk_tree_store_append(tFunctionCategories_store, &iter, &iter3);
4240 		EXPAND_TO_ITER(model, tFunctionCategories, iter)
4241 		gtk_tree_store_set(tFunctionCategories_store, &iter, 0, _("Uncategorized"), 1, _("Uncategorized"), -1);
4242 		if(selected_function_category == _("Uncategorized")) {
4243 			gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tFunctionCategories)), &iter);
4244 		}
4245 	}
4246 	if(!ia_functions.empty()) {
4247 		//add "Inactive" category if there are inactive functions
4248 		gtk_tree_store_append(tFunctionCategories_store, &iter, NULL);
4249 		EXPAND_TO_ITER(model, tFunctionCategories, iter)
4250 		gtk_tree_store_set(tFunctionCategories_store, &iter, 0, _("Inactive"), 1, _("Inactive"), -1);
4251 		if(selected_function_category == _("Inactive")) {
4252 			gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tFunctionCategories)), &iter);
4253 		}
4254 	}
4255 	if(!gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(tFunctionCategories)), &model, &iter)) {
4256 		//if no category has been selected (previously selected has been renamed/deleted), select "All"
4257 		selected_function_category = _("All");
4258 		gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tFunctionCategories_store), &iter);
4259 		EXPAND_ITER(model, tFunctionCategories, iter)
4260 		gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tFunctionCategories)), &iter);
4261 	}
4262 }
4263 
setFunctionTreeItem(GtkTreeIter & iter2,MathFunction * f)4264 void setFunctionTreeItem(GtkTreeIter &iter2, MathFunction *f) {
4265 	gtk_list_store_append(tFunctions_store, &iter2);
4266 	gtk_list_store_set(tFunctions_store, &iter2, 0, f->title(true).c_str(), 1, (gpointer) f, 2, TRUE, -1);
4267 	GtkTreeIter iter;
4268 	if(f == selected_function && gtk_tree_model_filter_convert_child_iter_to_iter(GTK_TREE_MODEL_FILTER(tFunctions_store_filter), &iter, &iter2)) {
4269 		gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tFunctions)), &iter);
4270 	}
4271 }
4272 
4273 /*
4274 	generate the function tree in manage functions dialog when category selection has changed
4275 */
on_tFunctionCategories_selection_changed(GtkTreeSelection * treeselection,gpointer)4276 void on_tFunctionCategories_selection_changed(GtkTreeSelection *treeselection, gpointer) {
4277 	GtkTreeModel *model, *model2;
4278 	GtkTreeIter iter, iter2;
4279 	bool no_cat = false, b_all = false, b_inactive = false;
4280 	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tFunctions));
4281 	g_signal_handlers_block_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_functions_entry_search_changed, NULL);
4282 	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(functions_builder, "functions_entry_search")), "");
4283 	g_signal_handlers_unblock_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_functions_entry_search_changed, NULL);
4284 	g_signal_handlers_block_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tFunctions_selection_changed, NULL);
4285 	gtk_list_store_clear(tFunctions_store);
4286 	g_signal_handlers_unblock_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tFunctions_selection_changed, NULL);
4287 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functions_builder, "functions_button_edit")), FALSE);
4288 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functions_builder, "functions_button_insert")), FALSE);
4289 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functions_builder, "functions_button_delete")), FALSE);
4290 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functions_builder, "functions_button_deactivate")), FALSE);
4291 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functions_builder, "functions_button_apply")), FALSE);
4292 	if(gtk_tree_selection_get_selected(treeselection, &model, &iter)) {
4293 		gchar *gstr;
4294 		gtk_tree_model_get(model, &iter, 1, &gstr, -1);
4295 		selected_function_category = gstr;
4296 		if(selected_function_category == _("All")) {
4297 			b_all = true;
4298 		} else if(selected_function_category == _("Uncategorized")) {
4299 			no_cat = true;
4300 		} else if(selected_function_category == _("Inactive")) {
4301 			b_inactive = true;
4302 		}
4303 		if(!b_all && !no_cat && !b_inactive && selected_function_category[0] == '/') {
4304 			string str = selected_function_category.substr(1, selected_function_category.length() - 1);
4305 			ExpressionItem *o;
4306 			size_t l1 = str.length(), l2;
4307 			for(size_t i = 0; i < CALCULATOR->functions.size(); i++) {
4308 				o = CALCULATOR->functions[i];
4309 				l2 = o->category().length();
4310 				if(o->isActive() && (l2 == l1 || (l2 > l1 && o->category()[l1] == '/')) && o->category().substr(0, l1) == str) {
4311 					setFunctionTreeItem(iter2, CALCULATOR->functions[i]);
4312 				}
4313 			}
4314 		} else {
4315 			for(size_t i = 0; i < CALCULATOR->functions.size(); i++) {
4316 				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)))) {
4317 					setFunctionTreeItem(iter2, CALCULATOR->functions[i]);
4318 				}
4319 			}
4320 		}
4321 		if(!selected_function || !gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(tFunctions)), &model2, &iter2)) {
4322 			if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tFunctions_store_filter), &iter2)) {
4323 				gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tFunctions)), &iter2);
4324 			}
4325 		}
4326 		g_free(gstr);
4327 	} else {
4328 		selected_function_category = "";
4329 	}
4330 }
4331 
4332 /*
4333 	function selection has changed
4334 */
on_tFunctions_selection_changed(GtkTreeSelection * treeselection,gpointer)4335 void on_tFunctions_selection_changed(GtkTreeSelection *treeselection, gpointer) {
4336 	GtkTreeModel *model;
4337 	GtkTreeIter iter;
4338 	if(gtk_tree_selection_get_selected(treeselection, &model, &iter)) {
4339 		MathFunction *f;
4340 		gtk_tree_model_get(model, &iter, 1, &f, -1);
4341 		//remember the new selection
4342 		selected_function = f;
4343 		for(size_t i = 0; i < CALCULATOR->functions.size(); i++) {
4344 			if(CALCULATOR->functions[i] == selected_function) {
4345 				GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtk_builder_get_object(functions_builder, "functions_textview_description")));
4346 				gtk_text_buffer_set_text(buffer, "", -1);
4347 				GtkTextIter iter;
4348 				f = CALCULATOR->functions[i];
4349 				Argument *arg;
4350 				Argument default_arg;
4351 				string str, str2;
4352 				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"));
4353 				str += ename->name;
4354 				gtk_text_buffer_get_end_iter(buffer, &iter);
4355 				gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, str.c_str(), -1, "bold", "italic", NULL);
4356 				str = "";
4357 				int iargs = f->maxargs();
4358 				if(iargs < 0) {
4359 					iargs = f->minargs() + 1;
4360 				}
4361 				str += "(";
4362 				if(iargs != 0) {
4363 					for(int i2 = 1; i2 <= iargs; i2++) {
4364 						if(i2 > f->minargs()) {
4365 							str += "[";
4366 						}
4367 						if(i2 > 1) {
4368 							str += CALCULATOR->getComma();
4369 							str += " ";
4370 						}
4371 						arg = f->getArgumentDefinition(i2);
4372 						if(arg && !arg->name().empty()) {
4373 							str2 = arg->name();
4374 						} else {
4375 							str2 = _("argument");
4376 							str2 += " ";
4377 							str2 += i2s(i2);
4378 						}
4379 						str += str2;
4380 						if(i2 > f->minargs()) {
4381 							str += "]";
4382 						}
4383 					}
4384 					if(f->maxargs() < 0) {
4385 						str += CALCULATOR->getComma();
4386 						str += " …";
4387 					}
4388 				}
4389 				str += ")";
4390 				for(size_t i2 = 1; i2 <= f->countNames(); i2++) {
4391 					if(&f->getName(i2) != ename) {
4392 						str += "\n";
4393 						str += f->getName(i2).name;
4394 					}
4395 				}
4396 				gtk_text_buffer_get_end_iter(buffer, &iter);
4397 				gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, str.c_str(), -1, "italic", NULL);
4398 				str = "";
4399 				str += "\n";
4400 				if(f->subtype() == SUBTYPE_DATA_SET) {
4401 					str += "\n";
4402 					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(true, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) expressiontext).c_str());
4403 					str += gstr;
4404 					g_free(gstr);
4405 					str += "\n";
4406 				}
4407 				if(!f->description().empty()) {
4408 					str += "\n";
4409 					str += f->description();
4410 					str += "\n";
4411 				}
4412 				if(!f->example(true).empty()) {
4413 					str += "\n";
4414 					str += _("Example:");
4415 					str += " ";
4416 					str += f->example(false, ename->name);
4417 					str += "\n";
4418 				}
4419 				if(f->subtype() == SUBTYPE_DATA_SET && !((DataSet*) f)->copyright().empty()) {
4420 					str += "\n";
4421 					str += ((DataSet*) f)->copyright();
4422 					str += "\n";
4423 				}
4424 				gtk_text_buffer_get_end_iter(buffer, &iter);
4425 				gtk_text_buffer_insert(buffer, &iter, str.c_str(), -1);
4426 				if(iargs) {
4427 					str = "\n";
4428 					str += _("Arguments");
4429 					str += "\n";
4430 					gtk_text_buffer_get_end_iter(buffer, &iter);
4431 					gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, str.c_str(), -1, "bold", NULL);
4432 					for(int i2 = 1; i2 <= iargs; i2++) {
4433 						arg = f->getArgumentDefinition(i2);
4434 						if(arg && !arg->name().empty()) {
4435 							str = arg->name();
4436 						} else {
4437 							str = i2s(i2);
4438 						}
4439 						str += ": ";
4440 						if(arg) {
4441 							str2 = arg->printlong();
4442 						} else {
4443 							str2 = default_arg.printlong();
4444 						}
4445 						if(printops.use_unicode_signs) {
4446 							gsub(">=", SIGN_GREATER_OR_EQUAL, str2);
4447 							gsub("<=", SIGN_LESS_OR_EQUAL, str2);
4448 							gsub("!=", SIGN_NOT_EQUAL, str2);
4449 						}
4450 						if(i2 > f->minargs()) {
4451 							str2 += " (";
4452 							//optional argument
4453 							str2 += _("optional");
4454 							if(!f->getDefaultValue(i2).empty() && f->getDefaultValue(i2) != "\"\"") {
4455 								str2 += ", ";
4456 								//argument default, in description
4457 								str2 += _("default: ");
4458 								ParseOptions pa = evalops.parse_options; pa.base = 10;
4459 								str2 += CALCULATOR->localizeExpression(f->getDefaultValue(i2), pa);
4460 							}
4461 							str2 += ")";
4462 						}
4463 						str2 += "\n";
4464 						gtk_text_buffer_get_end_iter(buffer, &iter);
4465 						gtk_text_buffer_insert(buffer, &iter, str.c_str(), -1);
4466 						gtk_text_buffer_get_end_iter(buffer, &iter);
4467 						gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, str2.c_str(), -1, "italic", NULL);
4468 					}
4469 				}
4470 				if(!f->condition().empty()) {
4471 					str = "\n";
4472 					str += _("Requirement");
4473 					str += ": ";
4474 					str += f->printCondition();
4475 					if(printops.use_unicode_signs) {
4476 						gsub(">=", SIGN_GREATER_OR_EQUAL, str);
4477 						gsub("<=", SIGN_LESS_OR_EQUAL, str);
4478 						gsub("!=", SIGN_NOT_EQUAL, str);
4479 					}
4480 					str += "\n";
4481 					gtk_text_buffer_get_end_iter(buffer, &iter);
4482 					gtk_text_buffer_insert(buffer, &iter, str.c_str(), -1);
4483 				}
4484 				if(f->subtype() == SUBTYPE_DATA_SET) {
4485 					DataSet *ds = (DataSet*) f;
4486 					str = "\n";
4487 					str += _("Properties");
4488 					str += "\n";
4489 					gtk_text_buffer_get_end_iter(buffer, &iter);
4490 					gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, str.c_str(), -1, "bold", NULL);
4491 					DataPropertyIter it;
4492 					DataProperty *dp = ds->getFirstProperty(&it);
4493 					while(dp) {
4494 						if(!dp->isHidden()) {
4495 							if(!dp->title(false).empty()) {
4496 								str = dp->title();
4497 								str += ": ";
4498 							}
4499 							for(size_t i = 1; i <= dp->countNames(); i++) {
4500 								if(i > 1) str += ", ";
4501 								str += dp->getName(i);
4502 							}
4503 							if(dp->isKey()) {
4504 								str += " (";
4505 								//indicating that the property is a data set key
4506 								str += _("key");
4507 								str += ")";
4508 							}
4509 							str += "\n";
4510 							gtk_text_buffer_get_end_iter(buffer, &iter);
4511 							gtk_text_buffer_insert(buffer, &iter, str.c_str(), -1);
4512 							if(!dp->description().empty()) {
4513 								str = dp->description();
4514 								str += "\n";
4515 								gtk_text_buffer_get_end_iter(buffer, &iter);
4516 								gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, str.c_str(), -1, "italic", NULL);
4517 							}
4518 						}
4519 						dp = ds->getNextProperty(&it);
4520 					}
4521 				}
4522 				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functions_builder, "functions_button_edit")), !CALCULATOR->functions[i]->isBuiltin());
4523 				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functions_builder, "functions_button_deactivate")), TRUE);
4524 				if(CALCULATOR->functions[i]->isActive()) {
4525 					gtk_label_set_text_with_mnemonic(GTK_LABEL(gtk_builder_get_object(functions_builder, "functions_buttonlabel_deactivate")), _("Deacti_vate"));
4526 				} else {
4527 					gtk_label_set_text_with_mnemonic(GTK_LABEL(gtk_builder_get_object(functions_builder, "functions_buttonlabel_deactivate")), _("Acti_vate"));
4528 				}
4529 				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functions_builder, "functions_button_insert")), CALCULATOR->functions[i]->isActive());
4530 				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));
4531 				//user cannot delete global definitions
4532 				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functions_builder, "functions_button_delete")), CALCULATOR->functions[i]->isLocal());
4533 			}
4534 		}
4535 	} else {
4536 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functions_builder, "functions_button_edit")), FALSE);
4537 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functions_builder, "functions_button_insert")), FALSE);
4538 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functions_builder, "functions_button_delete")), FALSE);
4539 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functions_builder, "functions_button_deactivate")), FALSE);
4540 		gtk_text_buffer_set_text(gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtk_builder_get_object(functions_builder, "functions_textview_description"))), "", -1);
4541 		selected_function = NULL;
4542 	}
4543 }
4544 
4545 /*
4546 	generate the variable categories tree in manage variables dialog
4547 */
update_variables_tree()4548 void update_variables_tree() {
4549 	if(!variables_builder) return;
4550 	GtkTreeIter iter, iter2, iter3;
4551 	GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(tVariableCategories));
4552 	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tVariableCategories));
4553 	g_signal_handlers_block_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tVariableCategories_selection_changed, NULL);
4554 	gtk_tree_store_clear(tVariableCategories_store);
4555 	g_signal_handlers_unblock_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tVariableCategories_selection_changed, NULL);
4556 	gtk_tree_store_append(tVariableCategories_store, &iter3, NULL);
4557 	gtk_tree_store_set(tVariableCategories_store, &iter3, 0, _("All"), 1, _("All"), -1);
4558 	string str;
4559 	tree_struct *item, *item2;
4560 	variable_cats.it = variable_cats.items.begin();
4561 	if(variable_cats.it != variable_cats.items.end()) {
4562 		item = &*variable_cats.it;
4563 		++variable_cats.it;
4564 		item->it = item->items.begin();
4565 	} else {
4566 		item = NULL;
4567 	}
4568 	str = "";
4569 	iter2 = iter3;
4570 	while(item) {
4571 		gtk_tree_store_append(tVariableCategories_store, &iter, &iter2);
4572 		str += "/";
4573 		str += item->item;
4574 		gtk_tree_store_set(tVariableCategories_store, &iter, 0, item->item.c_str(), 1, str.c_str(), -1);
4575 		if(str == selected_variable_category) {
4576 			EXPAND_TO_ITER(model, tVariableCategories, iter)
4577 			gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tVariableCategories)), &iter);
4578 		}
4579 
4580 		while(item && item->it == item->items.end()) {
4581 			size_t str_i = str.rfind("/");
4582 			if(str_i == string::npos) {
4583 				str = "";
4584 			} else {
4585 				str = str.substr(0, str_i);
4586 			}
4587 			item = item->parent;
4588 			gtk_tree_model_iter_parent(model, &iter2, &iter);
4589 			iter = iter2;
4590 		}
4591 		if(item) {
4592 			item2 = &*item->it;
4593 			if(item->it == item->items.begin()) iter2 = iter;
4594 			++item->it;
4595 			item = item2;
4596 			item->it = item->items.begin();
4597 		}
4598 	}
4599 
4600 	if(!variable_cats.objects.empty()) {
4601 		//add "Uncategorized" category if there are variables without category
4602 		gtk_tree_store_append(tVariableCategories_store, &iter, &iter3);
4603 		EXPAND_TO_ITER(model, tVariableCategories, iter)
4604 		gtk_tree_store_set(tVariableCategories_store, &iter, 0, _("Uncategorized"), 1, _("Uncategorized"), -1);
4605 		if(selected_variable_category == _("Uncategorized")) {
4606 			gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tVariableCategories)), &iter);
4607 		}
4608 	}
4609 	if(!ia_variables.empty()) {
4610 		//add "Inactive" category if there are inactive variables
4611 		gtk_tree_store_append(tVariableCategories_store, &iter, NULL);
4612 		EXPAND_TO_ITER(model, tVariableCategories, iter)
4613 		gtk_tree_store_set(tVariableCategories_store, &iter, 0, _("Inactive"), 1, _("Inactive"), -1);
4614 		if(selected_variable_category == _("Inactive")) {
4615 			gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tVariableCategories)), &iter);
4616 		}
4617 	}
4618 	if(!gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(tVariableCategories)), &model, &iter)) {
4619 		//if no category has been selected (previously selected has been renamed/deleted), select "All"
4620 		selected_variable_category = _("All");
4621 		gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tVariableCategories_store), &iter);
4622 		EXPAND_ITER(model, tVariableCategories, iter)
4623 		gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tVariableCategories)), &iter);
4624 	}
4625 }
4626 
setVariableTreeItem(GtkTreeIter & iter2,Variable * v)4627 void setVariableTreeItem(GtkTreeIter &iter2, Variable *v) {
4628 	gtk_list_store_append(tVariables_store, &iter2);
4629 	string value = "";
4630 	if(is_answer_variable(v)) {
4631 		value = _("a previous result");
4632 	} else if(v->isKnown()) {
4633 		if(((KnownVariable*) v)->isExpression()) {
4634 			ParseOptions pa = evalops.parse_options; pa.base = 10;
4635 			value = CALCULATOR->localizeExpression(((KnownVariable*) v)->expression(), pa);
4636 			bool is_relative = false;
4637 			if(!((KnownVariable*) v)->uncertainty(&is_relative).empty()) {
4638 				if(is_relative) {
4639 					value.insert(0, "(");
4640 					value.insert(0, CALCULATOR->f_uncertainty->referenceName());
4641 					value += CALCULATOR->getComma();
4642 					value += " ";
4643 					value += CALCULATOR->localizeExpression(((KnownVariable*) v)->uncertainty(), pa);
4644 					value += CALCULATOR->getComma();
4645 					value += " 1)";
4646 				} else {
4647 					value += SIGN_PLUSMINUS;
4648 					value += CALCULATOR->localizeExpression(((KnownVariable*) v)->uncertainty(), pa);
4649 				}
4650 			}
4651 			if(!((KnownVariable*) v)->unit().empty()) {value += " "; value += ((KnownVariable*) v)->unit();}
4652 		} else {
4653 			if(((KnownVariable*) v)->get().isMatrix()) {
4654 				value = _("matrix");
4655 			} else if(((KnownVariable*) v)->get().isVector()) {
4656 				value = _("vector");
4657 			} else {
4658 				PrintOptions po;
4659 				po.interval_display = INTERVAL_DISPLAY_PLUSMINUS;
4660 				value = CALCULATOR->print(((KnownVariable*) v)->get(), 30, po);
4661 			}
4662 		}
4663 	} else {
4664 		if(((UnknownVariable*) v)->assumptions()) {
4665 			switch(((UnknownVariable*) v)->assumptions()->sign()) {
4666 				case ASSUMPTION_SIGN_POSITIVE: {value = _("positive"); break;}
4667 				case ASSUMPTION_SIGN_NONPOSITIVE: {value = _("non-positive"); break;}
4668 				case ASSUMPTION_SIGN_NEGATIVE: {value = _("negative"); break;}
4669 				case ASSUMPTION_SIGN_NONNEGATIVE: {value = _("non-negative"); break;}
4670 				case ASSUMPTION_SIGN_NONZERO: {value = _("non-zero"); break;}
4671 				default: {}
4672 			}
4673 			if(!value.empty() && ((UnknownVariable*) v)->assumptions()->type() != ASSUMPTION_TYPE_NONE) value += " ";
4674 			switch(((UnknownVariable*) v)->assumptions()->type()) {
4675 				case ASSUMPTION_TYPE_INTEGER: {value += _("integer"); break;}
4676 				case ASSUMPTION_TYPE_RATIONAL: {value += _("rational"); break;}
4677 				case ASSUMPTION_TYPE_REAL: {value += _("real"); break;}
4678 				case ASSUMPTION_TYPE_COMPLEX: {value += _("complex"); break;}
4679 				case ASSUMPTION_TYPE_NUMBER: {value += _("number"); break;}
4680 				case ASSUMPTION_TYPE_NONMATRIX: {value += _("(not matrix)"); break;}
4681 				default: {}
4682 			}
4683 			if(value.empty()) value = _("unknown");
4684 		} else {
4685 			value = _("default assumptions");
4686 		}
4687 	}
4688 	gtk_list_store_set(tVariables_store, &iter2, 0, v->title(true).c_str(), 1, value.c_str(), 2, (gpointer) v, 3, TRUE, -1);
4689 	GtkTreeIter iter;
4690 	if(v == selected_variable && gtk_tree_model_filter_convert_child_iter_to_iter(GTK_TREE_MODEL_FILTER(tVariables_store_filter), &iter, &iter2)) {
4691 		gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tVariables)), &iter);
4692 	}
4693 }
4694 
4695 /*
4696 	generate the variable tree in manage variables dialog when category selection has changed
4697 */
on_tVariableCategories_selection_changed(GtkTreeSelection * treeselection,gpointer)4698 void on_tVariableCategories_selection_changed(GtkTreeSelection *treeselection, gpointer) {
4699 	GtkTreeModel *model, *model2;
4700 	GtkTreeIter iter, iter2;
4701 	bool no_cat = false, b_all = false, b_inactive = false;
4702 	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tVariables));
4703 	g_signal_handlers_block_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_variables_entry_search_changed, NULL);
4704 	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(variables_builder, "variables_entry_search")), "");
4705 	g_signal_handlers_unblock_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_variables_entry_search_changed, NULL);
4706 	g_signal_handlers_block_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tVariables_selection_changed, NULL);
4707 	gtk_list_store_clear(tVariables_store);
4708 	g_signal_handlers_unblock_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tVariables_selection_changed, NULL);
4709 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_button_edit")), FALSE);
4710 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_button_insert")), FALSE);
4711 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_button_delete")), FALSE);
4712 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_button_deactivate")), FALSE);
4713 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_button_export")), FALSE);
4714 
4715 	if(gtk_tree_selection_get_selected(treeselection, &model, &iter)) {
4716 		gchar *gstr;
4717 		gtk_tree_model_get(model, &iter, 1, &gstr, -1);
4718 		selected_variable_category = gstr;
4719 		if(selected_variable_category == _("All")) {
4720 			b_all = true;
4721 		} else if(selected_variable_category == _("Uncategorized")) {
4722 			no_cat = true;
4723 		} else if(selected_variable_category == _("Inactive")) {
4724 			b_inactive = true;
4725 		}
4726 
4727 		if(!b_all && !no_cat && !b_inactive && selected_variable_category[0] == '/') {
4728 			string str = selected_variable_category.substr(1, selected_variable_category.length() - 1);
4729 			ExpressionItem *o;
4730 			size_t l1 = str.length(), l2;
4731 			for(size_t i = 0; i < CALCULATOR->variables.size(); i++) {
4732 				o = CALCULATOR->variables[i];
4733 				l2 = o->category().length();
4734 				if(o->isActive() && (l2 == l1 || (l2 > l1 && o->category()[l1] == '/')) && o->category().substr(0, l1) == str) {
4735 					setVariableTreeItem(iter2, CALCULATOR->variables[i]);
4736 				}
4737 			}
4738 		} else {
4739 			for(size_t i = 0; i < CALCULATOR->variables.size(); i++) {
4740 				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)))) {
4741 					setVariableTreeItem(iter2, CALCULATOR->variables[i]);
4742 				}
4743 			}
4744 		}
4745 
4746 		if(!selected_variable || !gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(tVariables)), &model2, &iter2)) {
4747 			if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tVariables_store_filter), &iter2)) {
4748 				gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tVariables)), &iter2);
4749 			}
4750 		}
4751 		g_free(gstr);
4752 
4753 	} else {
4754 		selected_variable_category = "";
4755 	}
4756 
4757 }
4758 
4759 /*
4760 	variable selection has changed
4761 */
on_tVariables_selection_changed(GtkTreeSelection * treeselection,gpointer)4762 void on_tVariables_selection_changed(GtkTreeSelection *treeselection, gpointer) {
4763 	GtkTreeModel *model;
4764 	GtkTreeIter iter;
4765 	if(gtk_tree_selection_get_selected(treeselection, &model, &iter)) {
4766 		Variable *v;
4767 		gtk_tree_model_get(model, &iter, 2, &v, -1);
4768 		if(!CALCULATOR->stillHasVariable(v)) {
4769 			show_message(_("Variable does not exist anymore."), GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_dialog")));
4770 			selected_variable = NULL;
4771 			update_vmenu();
4772 			return;
4773 		}
4774 		//remember selection
4775 		selected_variable = v;
4776 		for(size_t i = 0; i < CALCULATOR->variables.size(); i++) {
4777 			if(CALCULATOR->variables[i] == selected_variable) {
4778 				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]) && CALCULATOR->variables[i] != v_memory);
4779 				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_button_insert")), CALCULATOR->variables[i]->isActive());
4780 				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_button_deactivate")), !is_answer_variable(CALCULATOR->variables[i]) && CALCULATOR->variables[i] != v_memory);
4781 				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_button_export")), CALCULATOR->variables[i]->isKnown());
4782 				if(CALCULATOR->variables[i]->isActive()) {
4783 					gtk_label_set_text_with_mnemonic(GTK_LABEL(gtk_builder_get_object(variables_builder, "variables_buttonlabel_deactivate")), _("Deacti_vate"));
4784 				} else {
4785 					gtk_label_set_text_with_mnemonic(GTK_LABEL(gtk_builder_get_object(variables_builder, "variables_buttonlabel_deactivate")), _("Acti_vate"));
4786 				}
4787 				//user cannot delete global definitions
4788 				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] != v_memory && CALCULATOR->variables[i] != CALCULATOR->v_x && CALCULATOR->variables[i] != CALCULATOR->v_y && CALCULATOR->variables[i] != CALCULATOR->v_z);
4789 			}
4790 		}
4791 	} else {
4792 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_button_edit")), FALSE);
4793 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_button_insert")), FALSE);
4794 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_button_delete")), FALSE);
4795 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_button_deactivate")), FALSE);
4796 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_button_export")), FALSE);
4797 		selected_variable = NULL;
4798 	}
4799 }
4800 
4801 
4802 /*
4803 	generate the unit categories tree in manage units dialog
4804 */
update_units_tree()4805 void update_units_tree() {
4806 	if(!units_builder) return;
4807 	GtkTreeIter iter, iter2, iter3;
4808 	GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(tUnitCategories));
4809 	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitCategories));
4810 	g_signal_handlers_block_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tUnitCategories_selection_changed, NULL);
4811 	gtk_tree_store_clear(tUnitCategories_store);
4812 	g_signal_handlers_unblock_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tUnitCategories_selection_changed, NULL);
4813 	gtk_tree_store_append(tUnitCategories_store, &iter3, NULL);
4814 	gtk_tree_store_set(tUnitCategories_store, &iter3, 0, _("All"), 1, _("All"), -1);
4815 	string str;
4816 	tree_struct *item, *item2;
4817 	unit_cats.it = unit_cats.items.begin();
4818 	if(unit_cats.it != unit_cats.items.end()) {
4819 		item = &*unit_cats.it;
4820 		++unit_cats.it;
4821 		item->it = item->items.begin();
4822 	} else {
4823 		item = NULL;
4824 	}
4825 	str = "";
4826 	iter2 = iter3;
4827 	while(item) {
4828 		gtk_tree_store_append(tUnitCategories_store, &iter, &iter2);
4829 		str += "/";
4830 		str += item->item;
4831 		gtk_tree_store_set(tUnitCategories_store, &iter, 0, item->item.c_str(), 1, str.c_str(), -1);
4832 		if(str == selected_unit_category) {
4833 			EXPAND_TO_ITER(model, tUnitCategories, iter)
4834 			gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitCategories)), &iter);
4835 		}
4836 		while(item && item->it == item->items.end()) {
4837 			size_t str_i = str.rfind("/");
4838 			if(str_i == string::npos) {
4839 				str = "";
4840 			} else {
4841 				str = str.substr(0, str_i);
4842 			}
4843 			item = item->parent;
4844 			gtk_tree_model_iter_parent(model, &iter2, &iter);
4845 			iter = iter2;
4846 		}
4847 		if(item) {
4848 			item2 = &*item->it;
4849 			if(item->it == item->items.begin()) iter2 = iter;
4850 			++item->it;
4851 			item = item2;
4852 			item->it = item->items.begin();
4853 		}
4854 	}
4855 	if(!unit_cats.objects.empty()) {
4856 		//add "Uncategorized" category if there are units without category
4857 		gtk_tree_store_append(tUnitCategories_store, &iter, &iter3);
4858 		gtk_tree_store_set(tUnitCategories_store, &iter, 0, _("Uncategorized"), 1, _("Uncategorized"), -1);
4859 		if(selected_unit_category == _("Uncategorized")) {
4860 			EXPAND_TO_ITER(model, tUnitCategories, iter)
4861 			gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitCategories)), &iter);
4862 		}
4863 	}
4864 	if(!ia_units.empty()) {
4865 		gtk_tree_store_append(tUnitCategories_store, &iter, NULL);
4866 		gtk_tree_store_set(tUnitCategories_store, &iter, 0, _("Inactive"), 1, _("Inactive"), -1);
4867 		if(selected_unit_category == _("Inactive")) {
4868 			EXPAND_TO_ITER(model, tUnitCategories, iter)
4869 			gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitCategories)), &iter);
4870 		}
4871 	}
4872 	if(!gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitCategories)), &model, &iter)) {
4873 		//if no category has been selected (previously selected has been renamed/deleted), select "All"
4874 		selected_unit_category = _("All");
4875 		gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tUnitCategories_store), &iter);
4876 		EXPAND_ITER(model, tUnitCategories, iter)
4877 		gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitCategories)), &iter);
4878 	}
4879 }
4880 
setUnitTreeItem(GtkTreeIter & iter2,Unit * u)4881 void setUnitTreeItem(GtkTreeIter &iter2, Unit *u) {
4882 	gtk_list_store_append(tUnits_store, &iter2);
4883 	string snames, sbase;
4884 	//display name, plural name and short name in the second column
4885 	AliasUnit *au;
4886 	for(size_t i = 1; i <= u->countNames(); i++) {
4887 		if(i > 1) snames += " / ";
4888 		snames += u->getName(i).name;
4889 	}
4890 	//depending on unit type display relation to base unit(s)
4891 	switch(u->subtype()) {
4892 		case SUBTYPE_COMPOSITE_UNIT: {
4893 			snames = "";
4894 			sbase = ((CompositeUnit*) u)->print(false, true, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) tUnits);
4895 			break;
4896 		}
4897 		case SUBTYPE_ALIAS_UNIT: {
4898 			au = (AliasUnit*) u;
4899 			sbase = au->firstBaseUnit()->preferredDisplayName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) tUnits).name;
4900 			if(au->firstBaseExponent() != 1) {
4901 				if(printops.use_unicode_signs && au->firstBaseExponent() == 2) sbase += SIGN_POWER_2;
4902 				else if(printops.use_unicode_signs && au->firstBaseExponent() == 3) sbase += SIGN_POWER_3;
4903 				else {
4904 					sbase += POWER;
4905 					sbase += i2s(au->firstBaseExponent());
4906 				}
4907 			}
4908 			break;
4909 		}
4910 		case SUBTYPE_BASE_UNIT: {
4911 			sbase = "";
4912 			break;
4913 		}
4914 	}
4915 	//display descriptive name (title), or name if no title defined
4916 	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);
4917 	if(u->isCurrency()) {
4918 		unordered_map<string, GdkPixbuf*>::const_iterator it_flag = flag_images.find(u->referenceName());
4919 		if(it_flag != flag_images.end()) {
4920 			gtk_list_store_set(tUnits_store, &iter2, UNITS_FLAG_COLUMN, it_flag->second, -1);
4921 		}
4922 	}
4923 	GtkTreeIter iter;
4924 	if(u == selected_unit && gtk_tree_model_filter_convert_child_iter_to_iter(GTK_TREE_MODEL_FILTER(tUnits_store_filter), &iter, &iter2)) {
4925 		gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnits)), &iter);
4926 	}
4927 }
4928 
4929 /*
4930 	generate the unit tree and units conversion menu in manage units dialog when category selection has changed
4931 */
on_tUnitCategories_selection_changed(GtkTreeSelection * treeselection,gpointer)4932 void on_tUnitCategories_selection_changed(GtkTreeSelection *treeselection, gpointer) {
4933 	GtkTreeModel *model, *model2;
4934 	GtkTreeIter iter, iter2;
4935 	//make sure that no unit conversion is done in the dialog until everthing is updated
4936 	block_unit_convert = true;
4937 	bool no_cat = false, b_all = false, b_inactive = false;
4938 	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnits));
4939 	g_signal_handlers_block_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_units_entry_search_changed, NULL);
4940 	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(units_builder, "units_entry_search")), "");
4941 	g_signal_handlers_unblock_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_units_entry_search_changed, NULL);
4942 	g_signal_handlers_block_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_units_convert_search_changed, NULL);
4943 	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(units_builder, "units_convert_search")), "");
4944 	g_signal_handlers_unblock_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_units_convert_search_changed, NULL);
4945 	g_signal_handlers_block_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tUnits_selection_changed, NULL);
4946 	gtk_list_store_clear(tUnits_store);
4947 	g_signal_handlers_unblock_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tUnits_selection_changed, NULL);
4948 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_button_edit")), FALSE);
4949 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_button_insert")), FALSE);
4950 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_button_delete")), FALSE);
4951 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_button_deactivate")), FALSE);
4952 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_button_convert_to")), FALSE);
4953 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_frame_convert")), FALSE);
4954 	bool b_sel = false;
4955 	if(gtk_tree_selection_get_selected(treeselection, &model, &iter)) {
4956 		bool b_currencies = false;
4957 		gchar *gstr;
4958 		gtk_tree_model_get(model, &iter, 1, &gstr, -1);
4959 		selected_unit_category = gstr;
4960 		if(selected_unit_category == _("All")) {
4961 			b_all = true;
4962 		} else if(selected_unit_category == _("Uncategorized")) {
4963 			no_cat = true;
4964 		} else if(selected_unit_category == _("Inactive")) {
4965 			b_inactive = true;
4966 		}
4967 		if(!b_all && !no_cat && !b_inactive && selected_unit_category[0] == '/') {
4968 			string str = selected_unit_category.substr(1, selected_unit_category.length() - 1);
4969 			ExpressionItem *o;
4970 			size_t l1 = str.length(), l2;
4971 			for(size_t i = 0; i < CALCULATOR->units.size(); i++) {
4972 				o = CALCULATOR->units[i];
4973 				l2 = o->category().length();
4974 				if(o->isActive() && (l2 == l1 || (l2 > l1 && o->category()[l1] == '/')) && o->category().substr(0, l1) == str) {
4975 					if(CALCULATOR->units[i]->isCurrency()) b_currencies = true;
4976 					setUnitTreeItem(iter2, CALCULATOR->units[i]);
4977 					if(!b_sel && selected_to_unit == CALCULATOR->units[i]) b_sel = true;
4978 				}
4979 			}
4980 		} else {
4981 			for(size_t i = 0; i < CALCULATOR->units.size(); i++) {
4982 				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)))) {
4983 					if(!b_all && !no_cat && !b_inactive && !b_currencies && CALCULATOR->units[i]->isCurrency()) b_currencies = true;
4984 					setUnitTreeItem(iter2, CALCULATOR->units[i]);
4985 					if(!b_sel && selected_to_unit == CALCULATOR->units[i]) b_sel = true;
4986 				}
4987 			}
4988 		}
4989 		if(!selected_unit || !gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnits)), &model2, &iter2)) {
4990 			if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tUnits_store_filter), &iter2)) {
4991 				gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnits)), &iter2);
4992 			}
4993 		}
4994 		gtk_tree_view_column_set_visible(units_flag_column, b_currencies);
4995 		gtk_cell_renderer_set_visible(units_convert_flag_renderer, b_currencies);
4996 		g_free(gstr);
4997 	} else {
4998 		selected_unit_category = "";
4999 	}
5000 	if(!b_sel) {
5001 		if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(units_convert_filter), &iter2)) {
5002 			GtkTreePath *path = gtk_tree_model_get_path(units_convert_filter, &iter2);
5003 			on_units_convert_view_row_activated(GTK_TREE_VIEW(units_convert_view), path, NULL, NULL);
5004 			gtk_tree_path_free(path);
5005 		}
5006 	}
5007 	block_unit_convert = false;
5008 	//update conversion display
5009 	convert_in_wUnits();
5010 }
5011 
5012 /*
5013 	unit selection has changed
5014 */
on_tUnits_selection_changed(GtkTreeSelection * treeselection,gpointer)5015 void on_tUnits_selection_changed(GtkTreeSelection *treeselection, gpointer) {
5016 	GtkTreeModel *model;
5017 	GtkTreeIter iter;
5018 	if(gtk_tree_selection_get_selected(treeselection, &model, &iter)) {
5019 		Unit *u;
5020 		gtk_tree_model_get(model, &iter, UNITS_POINTER_COLUMN, &u, -1);
5021 		selected_unit = u;
5022 		for(size_t i = 0; i < CALCULATOR->units.size(); i++) {
5023 			if(CALCULATOR->units[i] == selected_unit) {
5024 				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_frame_convert")), TRUE);
5025 				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());
5026 				//user cannot delete global definitions
5027 				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_button_delete")), CALCULATOR->units[i]->isLocal());
5028 				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_button_convert_to")), TRUE);
5029 				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_button_insert")), CALCULATOR->units[i]->isActive());
5030 				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_button_edit")), !CALCULATOR->units[i]->isBuiltin());
5031 				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_button_deactivate")), TRUE);
5032 				if(CALCULATOR->units[i]->isActive()) {
5033 					gtk_label_set_text_with_mnemonic(GTK_LABEL(gtk_builder_get_object(units_builder, "units_buttonlabel_deactivate")), _("Deacti_vate"));
5034 				} else {
5035 					gtk_label_set_text_with_mnemonic(GTK_LABEL(gtk_builder_get_object(units_builder, "units_buttonlabel_deactivate")), _("Acti_vate"));
5036 				}
5037 			}
5038 		}
5039 	} else {
5040 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_button_edit")), FALSE);
5041 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_button_insert")), FALSE);
5042 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_button_delete")), FALSE);
5043 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_button_deactivate")), FALSE);
5044 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_button_convert_to")), FALSE);
5045 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_frame_convert")), FALSE);
5046 		selected_unit = NULL;
5047 	}
5048 	if(!block_unit_convert) convert_in_wUnits();
5049 }
5050 
update_unit_selector_tree()5051 void update_unit_selector_tree() {
5052 	GtkTreeIter iter, iter2, iter3;
5053 	GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(tUnitSelectorCategories));
5054 	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitSelectorCategories));
5055 	g_signal_handlers_block_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tUnitSelectorCategories_selection_changed, NULL);
5056 	gtk_tree_store_clear(tUnitSelectorCategories_store);
5057 	g_signal_handlers_unblock_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tUnitSelectorCategories_selection_changed, NULL);
5058 	gtk_tree_store_append(tUnitSelectorCategories_store, &iter3, NULL);
5059 	gtk_tree_store_set(tUnitSelectorCategories_store, &iter3, 0, _("All"), 1, _("All"), -1);
5060 	string str;
5061 	tree_struct *item, *item2;
5062 	unit_cats.it = unit_cats.items.begin();
5063 	if(unit_cats.it != unit_cats.items.end()) {
5064 		item = &*unit_cats.it;
5065 		++unit_cats.it;
5066 		item->it = item->items.begin();
5067 	} else {
5068 		item = NULL;
5069 	}
5070 	str = "";
5071 	iter2 = iter3;
5072 	convert_category_map.clear();
5073 	while(item) {
5074 		gtk_tree_store_append(tUnitSelectorCategories_store, &iter, &iter2);
5075 		if(!str.empty()) str += "/";
5076 		str += item->item;
5077 		gtk_tree_store_set(tUnitSelectorCategories_store, &iter, 0, item->item.c_str(), 1, str.c_str(), -1);
5078 		if(str == selected_unit_category) {
5079 			EXPAND_TO_ITER(model, tUnitSelectorCategories, iter)
5080 			gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitSelectorCategories)), &iter);
5081 		}
5082 		convert_category_map[str] = iter;
5083 		while(item && item->it == item->items.end()) {
5084 			size_t str_i = str.rfind("/");
5085 			if(str_i == string::npos) {
5086 				str = "";
5087 			} else {
5088 				str = str.substr(0, str_i);
5089 			}
5090 			item = item->parent;
5091 			gtk_tree_model_iter_parent(model, &iter2, &iter);
5092 			iter = iter2;
5093 		}
5094 		if(item) {
5095 			item2 = &*item->it;
5096 			if(item->it == item->items.begin()) iter2 = iter;
5097 			++item->it;
5098 			item = item2;
5099 			item->it = item->items.begin();
5100 		}
5101 	}
5102 	if(!unit_cats.objects.empty()) {
5103 		//add "Uncategorized" category if there are units without category
5104 		gtk_tree_store_append(tUnitSelectorCategories_store, &iter, &iter3);
5105 		gtk_tree_store_set(tUnitSelectorCategories_store, &iter, 0, _("Uncategorized"), 1, _("Uncategorized"), -1);
5106 		convert_category_map[_("Uncategorized")] = iter;
5107 		if(selected_unit_category == _("Uncategorized")) {
5108 			EXPAND_TO_ITER(model, tUnitSelectorCategories, iter)
5109 			gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitSelectorCategories)), &iter);
5110 		}
5111 	}
5112 	if(!gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitSelectorCategories)), &model, &iter)) {
5113 		//if no category has been selected (previously selected has been renamed/deleted), select "All"
5114 		selected_unit_category = _("All");
5115 		gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tUnitSelectorCategories_store), &iter);
5116 		EXPAND_ITER(model, tUnitSelectorCategories, iter)
5117 		gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitSelectorCategories)), &iter);
5118 	}
5119 }
5120 
on_functions_entry_search_changed(GtkEntry * w,gpointer)5121 void on_functions_entry_search_changed(GtkEntry *w, gpointer) {
5122 	GtkTreeIter iter;
5123 	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tFunctions));
5124 	g_signal_handlers_block_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tFunctions_selection_changed, NULL);
5125 	if(!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tFunctions_store), &iter)) return;
5126 	string str = gtk_entry_get_text(w);
5127 	remove_blank_ends(str);
5128 	do {
5129 		bool b = str.empty();
5130 		MathFunction *u = NULL;
5131 		if(!b) gtk_tree_model_get(GTK_TREE_MODEL(tFunctions_store), &iter, 1, &u, -1);
5132 		if(u) {
5133 			string title = u->title(true);
5134 			remove_blank_ends(title);
5135 			while(title.length() >= str.length()) {
5136 				if(equalsIgnoreCase(str, title.substr(0, str.length()))) {
5137 					b = true;
5138 					break;
5139 				}
5140 				size_t i = title.find(' ');
5141 				if(i == string::npos) break;
5142 				title = title.substr(i + 1);
5143 				remove_blank_ends(title);
5144 			}
5145 			for(size_t i2 = 1; i2 <= u->countNames(); i2++) {
5146 				if(u->getName(i2).case_sensitive) {
5147 					if(str == u->getName(i2).name.substr(0, str.length())) {
5148 						b = true;
5149 						break;
5150 					}
5151 				} else {
5152 					if(equalsIgnoreCase(str, u->getName(i2).name.substr(0, str.length()))) {
5153 						b = true;
5154 						break;
5155 					}
5156 				}
5157 			}
5158 		}
5159 		gtk_list_store_set(tFunctions_store, &iter, 2, b, -1);
5160 	} while(gtk_tree_model_iter_next(GTK_TREE_MODEL(tFunctions_store), &iter));
5161 	g_signal_handlers_unblock_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tFunctions_selection_changed, NULL);
5162 	if(str.empty()) {
5163 		gtk_widget_grab_focus(tFunctions);
5164 	} else {
5165 		if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tFunctions_store_filter), &iter)) {
5166 			gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(tFunctions)));
5167 			gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tFunctions)), &iter);
5168 			GtkTreePath *path = gtk_tree_model_get_path(tFunctions_store_filter, &iter);
5169 			if(path) {
5170 				gtk_tree_view_set_cursor(GTK_TREE_VIEW(tFunctions), path, NULL, FALSE);
5171 				gtk_tree_path_free(path);
5172 			}
5173 		}
5174 	}
5175 }
on_variables_entry_search_changed(GtkEntry * w,gpointer)5176 void on_variables_entry_search_changed(GtkEntry *w, gpointer) {
5177 	GtkTreeIter iter;
5178 	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tVariables));
5179 	g_signal_handlers_block_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tVariables_selection_changed, NULL);
5180 	if(!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tVariables_store), &iter)) return;
5181 	string str = gtk_entry_get_text(w);
5182 	remove_blank_ends(str);
5183 	do {
5184 		bool b = str.empty();
5185 		Variable *u = NULL;
5186 		if(!b) gtk_tree_model_get(GTK_TREE_MODEL(tVariables_store), &iter, 2, &u, -1);
5187 		if(u) {
5188 			string title = u->title(true);
5189 			remove_blank_ends(title);
5190 			while(title.length() >= str.length()) {
5191 				if(equalsIgnoreCase(str, title.substr(0, str.length()))) {
5192 					b = true;
5193 					break;
5194 				}
5195 				size_t i = title.find(' ');
5196 				if(i == string::npos) break;
5197 				title = title.substr(i + 1);
5198 				remove_blank_ends(title);
5199 			}
5200 			for(size_t i2 = 1; i2 <= u->countNames(); i2++) {
5201 				if(u->getName(i2).case_sensitive) {
5202 					if(str == u->getName(i2).name.substr(0, str.length())) {
5203 						b = true;
5204 						break;
5205 					}
5206 				} else {
5207 					if(equalsIgnoreCase(str, u->getName(i2).name.substr(0, str.length()))) {
5208 						b = true;
5209 						break;
5210 					}
5211 				}
5212 			}
5213 		}
5214 		gtk_list_store_set(tVariables_store, &iter, 3, b, -1);
5215 	} while(gtk_tree_model_iter_next(GTK_TREE_MODEL(tVariables_store), &iter));
5216 	g_signal_handlers_unblock_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tVariables_selection_changed, NULL);
5217 	if(str.empty()) {
5218 		gtk_widget_grab_focus(tVariables);
5219 	} else {
5220 		if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tVariables_store_filter), &iter)) {
5221 			gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(tVariables)));
5222 			gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tVariables)), &iter);
5223 			GtkTreePath *path = gtk_tree_model_get_path(tVariables_store_filter, &iter);
5224 			if(path) {
5225 				gtk_tree_view_set_cursor(GTK_TREE_VIEW(tVariables), path, NULL, FALSE);
5226 				gtk_tree_path_free(path);
5227 			}
5228 		}
5229 	}
5230 }
5231 
on_units_entry_search_changed(GtkEntry * w,gpointer)5232 void on_units_entry_search_changed(GtkEntry *w, gpointer) {
5233 	GtkTreeIter iter;
5234 	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnits));
5235 	g_signal_handlers_block_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tUnits_selection_changed, NULL);
5236 	if(!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tUnits_store), &iter)) return;
5237 	string str = gtk_entry_get_text(w);
5238 	remove_blank_ends(str);
5239 	do {
5240 		bool b = str.empty();
5241 		Unit *u = NULL;
5242 		if(!b) gtk_tree_model_get(GTK_TREE_MODEL(tUnits_store), &iter, UNITS_POINTER_COLUMN, &u, -1);
5243 		if(u) {
5244 			b = name_matches(u, str);
5245 			if(!b) b = title_matches(u, str);
5246 			if(!b) b = country_matches(u, str);
5247 		}
5248 		gtk_list_store_set(tUnits_store, &iter, UNITS_VISIBLE_COLUMN, b, -1);
5249 	} while(gtk_tree_model_iter_next(GTK_TREE_MODEL(tUnits_store), &iter));
5250 	g_signal_handlers_unblock_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tUnits_selection_changed, NULL);
5251 	if(str.empty()) {
5252 		gtk_widget_grab_focus(tUnits);
5253 	} else {
5254 		if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tUnits_store_filter), &iter)) {
5255 			gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnits)));
5256 			gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnits)), &iter);
5257 			GtkTreePath *path = gtk_tree_model_get_path(tUnits_store_filter, &iter);
5258 			if(path) {
5259 				gtk_tree_view_set_cursor(GTK_TREE_VIEW(tUnits), path, NULL, FALSE);
5260 				gtk_tree_path_free(path);
5261 			}
5262 		}
5263 	}
5264 }
5265 
on_units_convert_search_changed(GtkEntry * w,gpointer)5266 void on_units_convert_search_changed(GtkEntry *w, gpointer) {
5267 	GtkTreeIter iter;
5268 	if(!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tUnits_store), &iter)) return;
5269 	string str = gtk_entry_get_text(w);
5270 	remove_blank_ends(str);
5271 	do {
5272 		bool b = str.empty();
5273 		Unit *u = NULL;
5274 		if(!b) gtk_tree_model_get(GTK_TREE_MODEL(tUnits_store), &iter, UNITS_POINTER_COLUMN, &u, -1);
5275 		if(u) {
5276 			b = name_matches(u, str);
5277 			if(!b) b = title_matches(u, str);
5278 			if(!b) b = country_matches(u, str);
5279 		}
5280 		gtk_list_store_set(tUnits_store, &iter, UNITS_VISIBLE_COLUMN_CONVERT, b, -1);
5281 	} while(gtk_tree_model_iter_next(GTK_TREE_MODEL(tUnits_store), &iter));
5282 	if(!str.empty()) {
5283 		if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(units_convert_filter), &iter)) {
5284 			gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(units_convert_view)));
5285 			gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(units_convert_view)), &iter);
5286 		}
5287 	}
5288 	while(gtk_events_pending()) gtk_main_iteration();
5289 	//if(gtk_widget_is_visible(units_convert_window)) units_convert_resize_popup();
5290 }
5291 
on_convert_entry_search_changed(GtkEntry * w,gpointer)5292 void on_convert_entry_search_changed(GtkEntry *w, gpointer) {
5293 	GtkTreeIter iter;
5294 	int count = 0;
5295 	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitSelector));
5296 	g_signal_handlers_block_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tUnitSelector_selection_changed, NULL);
5297 	if(!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tUnitSelector_store), &iter)) return;
5298 	string str = gtk_entry_get_text(w);
5299 	remove_blank_ends(str);
5300 	do {
5301 		bool b = str.empty();
5302 		Unit *u = NULL;
5303 		if(!b) gtk_tree_model_get(GTK_TREE_MODEL(tUnitSelector_store), &iter, 1, &u, -1);
5304 		if(u) {
5305 			b = name_matches(u, str);
5306 			if(!b) b = title_matches(u, str);
5307 			if(!b) b = country_matches(u, str);
5308 		}
5309 		if(b) count++;
5310 		gtk_list_store_set(tUnitSelector_store, &iter, 3, b, -1);
5311 	} while(gtk_tree_model_iter_next(GTK_TREE_MODEL(tUnitSelector_store), &iter));
5312 	g_signal_handlers_unblock_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tUnitSelector_selection_changed, NULL);
5313 	if(!str.empty()) {
5314 		if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tUnitSelector_store_filter), &iter)) {
5315 			gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitSelector)));
5316 			gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitSelector)), &iter);
5317 			GtkTreePath *path = gtk_tree_model_get_path(tUnitSelector_store_filter, &iter);
5318 			if(path) {
5319 				gtk_tree_view_set_cursor(GTK_TREE_VIEW(tUnitSelector), path, NULL, FALSE);
5320 				gtk_tree_path_free(path);
5321 			}
5322 		}
5323 		gint start_pos = 0, end_pos = 0;
5324 		gtk_editable_get_selection_bounds(GTK_EDITABLE(w), &start_pos, &end_pos);
5325 		gtk_widget_grab_focus(GTK_WIDGET(w));
5326 		gtk_editable_select_region(GTK_EDITABLE(w), start_pos, end_pos);
5327 	}
5328 }
5329 
setUnitSelectorTreeItem(GtkTreeIter & iter2,Unit * u)5330 void setUnitSelectorTreeItem(GtkTreeIter &iter2, Unit *u) {
5331 	gtk_list_store_append(tUnitSelector_store, &iter2);
5332 	string snames, sbase;
5333 	if(u->isCurrency()) {
5334 		unordered_map<string, GdkPixbuf*>::const_iterator it_flag = flag_images.find(u->referenceName());
5335 		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);
5336 	} else {
5337 		gtk_list_store_set(tUnitSelector_store, &iter2, 0, u->title(true).c_str(), 1, (gpointer) u, 3, TRUE, -1);
5338 	}
5339 }
5340 
5341 /*
5342 	generate the unit tree in conversion tab when category selection has changed
5343 */
on_tUnitSelectorCategories_selection_changed(GtkTreeSelection * treeselection,gpointer)5344 void on_tUnitSelectorCategories_selection_changed(GtkTreeSelection *treeselection, gpointer) {
5345 
5346 	block_unit_selector_convert = true;
5347 
5348 	GtkTreeModel *model;
5349 	GtkTreeIter iter, iter2;
5350 
5351 	bool no_cat = false, b_all = false;
5352 	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitSelector));
5353 	g_signal_handlers_block_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_convert_entry_search_changed, NULL);
5354 	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(main_builder, "convert_entry_search")), "");
5355 	g_signal_handlers_unblock_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_convert_entry_search_changed, NULL);
5356 	g_signal_handlers_block_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tUnitSelector_selection_changed, NULL);
5357 	gtk_list_store_clear(tUnitSelector_store);
5358 	g_signal_handlers_unblock_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tUnitSelector_selection_changed, NULL);
5359 	int count = 0;
5360 	if(gtk_tree_selection_get_selected(treeselection, &model, &iter)) {
5361 		gchar *gstr;
5362 		gtk_tree_model_get(model, &iter, 1, &gstr, -1);
5363 		selected_unit_selector_category = gstr;
5364 		if(selected_unit_selector_category == _("All")) {
5365 			b_all = true;
5366 		} else if(selected_unit_selector_category == _("Uncategorized")) {
5367 			no_cat = true;
5368 		}
5369 		bool b_currencies = false;
5370 		if(!b_all && !no_cat && selected_unit_selector_category[0] == '/') {
5371 			string str = selected_unit_selector_category.substr(1, selected_unit_selector_category.length() - 1);
5372 			for(size_t i = 0; i < CALCULATOR->units.size(); i++) {
5373 				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) {
5374 					if(!b_currencies && CALCULATOR->units[i]->isCurrency()) b_currencies = true;
5375 					setUnitSelectorTreeItem(iter2, CALCULATOR->units[i]);
5376 					count++;
5377 				}
5378 			}
5379 		} else {
5380 			bool list_empty = true;
5381 			for(size_t i = 0; i < CALCULATOR->units.size(); i++) {
5382 				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)) {
5383 					if(!b_currencies && !b_all && !no_cat && CALCULATOR->units[i]->isCurrency()) b_currencies = true;
5384 					setUnitSelectorTreeItem(iter2, CALCULATOR->units[i]);
5385 					count++;
5386 					list_empty = false;
5387 				}
5388 			}
5389 			bool collapse_all = true;
5390 			if(list_empty && !b_all && !no_cat) {
5391 				for(size_t i = 0; i < CALCULATOR->units.size(); i++) {
5392 					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) {
5393 						if(!b_currencies && !b_all && !no_cat && CALCULATOR->units[i]->isCurrency()) b_currencies = true;
5394 						setUnitSelectorTreeItem(iter2, CALCULATOR->units[i]);
5395 						count++;
5396 					}
5397 				}
5398 			} else if(!b_all && !no_cat) {
5399 				GtkTreePath *path = gtk_tree_model_get_path(model, &iter);
5400 				collapse_all = !gtk_tree_view_expand_row(GTK_TREE_VIEW(tUnitSelectorCategories), path, FALSE);
5401 				gtk_tree_path_free(path);
5402 			}
5403 			if(collapse_all) {
5404 				GtkTreePath *path = gtk_tree_model_get_path(model, &iter);
5405 				if(gtk_tree_path_get_depth(path) == 2) {
5406 					GtkTreeIter iter3;
5407 					gtk_tree_model_get_iter_first(model, &iter3);
5408 					if(gtk_tree_model_iter_children(model, &iter2, &iter3)) {
5409 						do {
5410 							GtkTreePath *path2 = gtk_tree_model_get_path(model, &iter2);
5411 							if(gtk_tree_path_compare(path, path2) != 0) gtk_tree_view_collapse_row(GTK_TREE_VIEW(tUnitSelectorCategories), path2);
5412 							gtk_tree_path_free(path2);
5413 						} while(gtk_tree_model_iter_next(model, &iter2));
5414 					}
5415 					gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(tUnitSelectorCategories), path, NULL, FALSE, 0, 0);
5416 				}
5417 				gtk_tree_path_free(path);
5418 			}
5419 		}
5420 		gtk_tree_view_column_set_visible(flag_column, b_currencies);
5421 		g_free(gstr);
5422 	} else {
5423 		selected_unit_selector_category = "";
5424 	}
5425 	block_unit_selector_convert = false;
5426 
5427 }
5428 
on_tUnitSelector_selection_changed(GtkTreeSelection * treeselection,gpointer)5429 void on_tUnitSelector_selection_changed(GtkTreeSelection *treeselection, gpointer) {
5430 	GtkTreeModel *model;
5431 	GtkTreeIter iter;
5432 	if(gtk_tree_selection_get_selected(treeselection, &model, &iter)) {
5433 		Unit *u;
5434 		gtk_tree_model_get(model, &iter, 1, &u, -1);
5435 		keep_unit_selection = true;
5436 		for(size_t i = 0; i < CALCULATOR->units.size(); i++) {
5437 			if(CALCULATOR->units[i] == u) {
5438 				if(u->subtype() == SUBTYPE_COMPOSITE_UNIT) {
5439 					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());
5440 				} else {
5441 					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());
5442 				}
5443 				if(!block_unit_selector_convert) convert_from_convert_entry_unit();
5444 			}
5445 		}
5446 		keep_unit_selection = false;
5447 	}
5448 }
5449 
5450 
update_datasets_tree()5451 void update_datasets_tree() {
5452 	if(!datasets_builder) return;
5453 	GtkTreeIter iter;
5454 	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tDatasets));
5455 	g_signal_handlers_block_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tDatasets_selection_changed, NULL);
5456 	gtk_list_store_clear(tDatasets_store);
5457 	DataSet *ds;
5458 	bool b = false;
5459 	for(size_t i = 1; ; i++) {
5460 		ds = CALCULATOR->getDataSet(i);
5461 		if(!ds) break;
5462 		gtk_list_store_append(tDatasets_store, &iter);
5463 		gtk_list_store_set(tDatasets_store, &iter, 0, ds->title().c_str(), 1, (gpointer) ds, -1);
5464 		if(ds == selected_dataset) {
5465 			g_signal_handlers_unblock_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tDatasets_selection_changed, NULL);
5466 			gtk_tree_selection_select_iter(select, &iter);
5467 			g_signal_handlers_block_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tDatasets_selection_changed, NULL);
5468 			b = true;
5469 		}
5470 	}
5471 	g_signal_handlers_unblock_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tDatasets_selection_changed, NULL);
5472 	if(!b) {
5473 		gtk_tree_selection_unselect_all(select);
5474 		selected_dataset = NULL;
5475 	}
5476 }
5477 
on_tDatasets_selection_changed(GtkTreeSelection * treeselection,gpointer)5478 void on_tDatasets_selection_changed(GtkTreeSelection *treeselection, gpointer) {
5479 	GtkTreeModel *model, *model2;
5480 	GtkTreeIter iter, iter2;
5481 	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tDataObjects));
5482 	gtk_tree_selection_unselect_all(select);
5483 	g_signal_handlers_block_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tDataObjects_selection_changed, NULL);
5484 	gtk_list_store_clear(tDataObjects_store);
5485 	g_signal_handlers_unblock_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tDataObjects_selection_changed, NULL);
5486 	if(gtk_tree_selection_get_selected(treeselection, &model, &iter)) {
5487 		DataSet *ds = NULL;
5488 		gtk_tree_model_get(model, &iter, 1, &ds, -1);
5489 		selected_dataset = ds;
5490 		if(!ds) return;
5491 		DataObjectIter it;
5492 		DataPropertyIter pit;
5493 		DataProperty *dp;
5494 		DataObject *o = ds->getFirstObject(&it);
5495 		bool b = false;
5496 		while(o) {
5497 			b = true;
5498 			gtk_list_store_append(tDataObjects_store, &iter2);
5499 			dp = ds->getFirstProperty(&pit);
5500 			size_t index = 0;
5501 			while(dp) {
5502 				if(!dp->isHidden() && dp->isKey()) {
5503 					gtk_list_store_set(tDataObjects_store, &iter2, index, o->getPropertyDisplayString(dp).c_str(), -1);
5504 					index++;
5505 					if(index > 2) break;
5506 				}
5507 				dp = ds->getNextProperty(&pit);
5508 			}
5509 			while(index < 3) {
5510 				gtk_list_store_set(tDataObjects_store, &iter2, index, "", -1);
5511 				index++;
5512 			}
5513 			gtk_list_store_set(tDataObjects_store, &iter2, 3, (gpointer) o, -1);
5514 			if(o == selected_dataobject) {
5515 				gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tDataObjects)), &iter2);
5516 			}
5517 			o = ds->getNextObject(&it);
5518 		}
5519 		if(b && (!selected_dataobject || !gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(tDataObjects)), &model2, &iter2))) {
5520 			gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tDataObjects_store), &iter2);
5521 			gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tDataObjects)), &iter2);
5522 		}
5523 		GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtk_builder_get_object(datasets_builder, "datasets_textview_description")));
5524 		gtk_text_buffer_set_text(buffer, "", -1);
5525 		GtkTextIter iter;
5526 		string str, str2;
5527 		if(!ds->description().empty()) {
5528 			str = ds->description();
5529 			str += "\n";
5530 			str += "\n";
5531 			gtk_text_buffer_get_end_iter(buffer, &iter);
5532 			gtk_text_buffer_insert(buffer, &iter, str.c_str(), -1);
5533 		}
5534 		str = _("Properties");
5535 		str += "\n";
5536 		gtk_text_buffer_get_end_iter(buffer, &iter);
5537 		gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, str.c_str(), -1, "bold", NULL);
5538 		dp = ds->getFirstProperty(&pit);
5539 		while(dp) {
5540 			if(!dp->isHidden()) {
5541 				str = "";
5542 				if(!dp->title(false).empty()) {
5543 					str += dp->title();
5544 					str += ": ";
5545 				}
5546 				for(size_t i = 1; i <= dp->countNames(); i++) {
5547 					if(i > 1) str += ", ";
5548 					str += dp->getName(i);
5549 				}
5550 				if(dp->isKey()) {
5551 					str += " (";
5552 					str += _("key");
5553 					str += ")";
5554 				}
5555 				str += "\n";
5556 				gtk_text_buffer_get_end_iter(buffer, &iter);
5557 				gtk_text_buffer_insert(buffer, &iter, str.c_str(), -1);
5558 				if(!dp->description().empty()) {
5559 					str = dp->description();
5560 					str += "\n";
5561 					gtk_text_buffer_get_end_iter(buffer, &iter);
5562 					gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, str.c_str(), -1, "italic", NULL);
5563 				}
5564 			}
5565 			dp = ds->getNextProperty(&pit);
5566 		}
5567 		str = "\n";
5568 		str += _("Data Retrieval Function");
5569 		gtk_text_buffer_get_end_iter(buffer, &iter);
5570 		gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, str.c_str(), -1, "bold", NULL);
5571 		Argument *arg;
5572 		Argument default_arg;
5573 		const ExpressionName *ename = &ds->preferredName(false, true, false, false, &can_display_unicode_string_function, (void*) gtk_builder_get_object(datasets_builder, "datasets_textview_description"));
5574 		str = "\n";
5575 		str += ename->name;
5576 		gtk_text_buffer_get_end_iter(buffer, &iter);
5577 		gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, str.c_str(), -1, "bold", "italic", NULL);
5578 		str = "";
5579 		int iargs = ds->maxargs();
5580 		if(iargs < 0) {
5581 			iargs = ds->minargs() + 1;
5582 		}
5583 		str += "(";
5584 		if(iargs != 0) {
5585 			for(int i2 = 1; i2 <= iargs; i2++) {
5586 				if(i2 > ds->minargs()) {
5587 					str += "[";
5588 				}
5589 				if(i2 > 1) {
5590 					str += CALCULATOR->getComma();
5591 					str += " ";
5592 				}
5593 				arg = ds->getArgumentDefinition(i2);
5594 				if(arg && !arg->name().empty()) {
5595 					str2 = arg->name();
5596 				} else {
5597 					str2 = _("argument");
5598 					str2 += " ";
5599 					str2 += i2s(i2);
5600 				}
5601 				str += str2;
5602 				if(i2 > ds->minargs()) {
5603 					str += "]";
5604 				}
5605 			}
5606 			if(ds->maxargs() < 0) {
5607 				str += CALCULATOR->getComma();
5608 				str += " …";
5609 			}
5610 		}
5611 		str += ")";
5612 		for(size_t i2 = 1; i2 <= ds->countNames(); i2++) {
5613 			if(&ds->getName(i2) != ename) {
5614 				str += "\n";
5615 				str += ds->getName(i2).name;
5616 			}
5617 		}
5618 		str += "\n\n";
5619 		gtk_text_buffer_get_end_iter(buffer, &iter);
5620 		gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, str.c_str(), -1, "italic", NULL);
5621 		if(!ds->copyright().empty()) {
5622 			str = "\n";
5623 			str = ds->copyright();
5624 			str += "\n";
5625 			gtk_text_buffer_get_end_iter(buffer, &iter);
5626 			gtk_text_buffer_insert(buffer, &iter, str.c_str(), -1);
5627 		}
5628 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasets_builder, "datasets_button_editset")), TRUE);
5629 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasets_builder, "datasets_button_delset")), ds->isLocal());
5630 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasets_builder, "datasets_button_newobject")), TRUE);
5631 	} else {
5632 		gtk_text_buffer_set_text(gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtk_builder_get_object(datasets_builder, "datasets_textview_description"))), "", -1);
5633 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasets_builder, "datasets_button_editset")), FALSE);
5634 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasets_builder, "datasets_button_delset")), FALSE);
5635 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasets_builder, "datasets_button_newobject")), FALSE);
5636 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasets_builder, "datasets_button_editobject")), FALSE);
5637 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasets_builder, "datasets_button_delobject")), FALSE);
5638 		selected_dataset = NULL;
5639 	}
5640 }
5641 
update_dataobjects()5642 void update_dataobjects() {
5643 	on_tDatasets_selection_changed(gtk_tree_view_get_selection(GTK_TREE_VIEW(tDatasets)), NULL);
5644 }
5645 
on_dataset_button_function_clicked(GtkButton * w,gpointer user_data)5646 void on_dataset_button_function_clicked(GtkButton *w, gpointer user_data) {
5647 	DataProperty *dp = (DataProperty*) user_data;
5648 	DataObject *o = selected_dataobject;
5649 	DataSet *ds = NULL;
5650 	if(o) ds = dp->parentSet();
5651 	if(ds && o) {
5652 		string str = ds->preferredDisplayName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) w).name;
5653 		str += "(";
5654 		str += o->getProperty(ds->getPrimaryKeyProperty());
5655 		str += CALCULATOR->getComma();
5656 		str += " ";
5657 		str += dp->getName();
5658 		str += ")";
5659 		insert_text(str.c_str());
5660 	}
5661 }
on_tDataObjects_selection_changed(GtkTreeSelection * treeselection,gpointer)5662 void on_tDataObjects_selection_changed(GtkTreeSelection *treeselection, gpointer) {
5663 	GtkTreeModel *model;
5664 	GtkTreeIter iter;
5665 	GtkWidget *ptable = GTK_WIDGET(gtk_builder_get_object(datasets_builder, "datasets_grid_properties"));
5666 	GList *childlist = gtk_container_get_children(GTK_CONTAINER(ptable));
5667 	for(guint i = 0; ; i++) {
5668 		GtkWidget *w = (GtkWidget*) g_list_nth_data(childlist, i);
5669 		if(!w) break;
5670 		gtk_widget_destroy(w);
5671 	}
5672 	g_list_free(childlist);
5673 	if(gtk_tree_selection_get_selected(treeselection, &model, &iter)) {
5674 		DataObject *o = NULL;
5675 		gtk_tree_model_get(model, &iter, 3, &o, -1);
5676 		selected_dataobject = o;
5677 		if(!o) return;
5678 		DataSet *ds = o->parentSet();
5679 		if(!ds) return;
5680 		DataPropertyIter it;
5681 		DataProperty *dp = ds->getFirstProperty(&it);
5682 		string sval;
5683 		int rows = 1;
5684 		gtk_grid_remove_column(GTK_GRID(ptable), 0);
5685 		gtk_grid_remove_column(GTK_GRID(ptable), 1);
5686 		gtk_grid_remove_column(GTK_GRID(ptable), 2);
5687 		GtkWidget *button, *label;
5688 		string str;
5689 		while(dp) {
5690 			if(!dp->isHidden()) {
5691 				sval = o->getPropertyDisplayString(dp);
5692 				if(!sval.empty()) {
5693 					label = gtk_label_new(NULL);
5694 					str = "<span weight=\"bold\">"; str += dp->title(); str += ":"; str += "</span>";
5695 					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);
5696 #if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 12
5697 					gtk_widget_set_margin_end(label, 20);
5698 #else
5699 					gtk_widget_set_margin_right(label, 20);
5700 #endif
5701 					gtk_grid_attach(GTK_GRID(ptable), label, 0, rows - 1, 1 , 1);
5702 					label = gtk_label_new(NULL);
5703 					gtk_widget_set_hexpand(label, TRUE);
5704 					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);
5705 					gtk_grid_attach(GTK_GRID(ptable), label, 1, rows - 1, 1, 1);
5706 					button = gtk_button_new();
5707 					gtk_container_add(GTK_CONTAINER(button), gtk_image_new_from_icon_name("edit-paste", GTK_ICON_SIZE_BUTTON));
5708 					gtk_widget_set_halign(button, GTK_ALIGN_END);
5709 					//gtk_widget_set_valign(button, GTK_ALIGN_CENTER);
5710 					gtk_grid_attach(GTK_GRID(ptable), button, 2, rows - 1, 1, 1);
5711 					g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(on_dataset_button_function_clicked), (gpointer) dp);
5712 					rows++;
5713 				}
5714 			}
5715 			dp = ds->getNextProperty(&it);
5716 		}
5717 		gtk_widget_show_all(ptable);
5718 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasets_builder, "datasets_button_editobject")), TRUE);
5719 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasets_builder, "datasets_button_delobject")), o->isUserModified());
5720 	} else {
5721 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasets_builder, "datasets_button_editobject")), FALSE);
5722 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasets_builder, "datasets_button_delobject")), FALSE);
5723 		selected_dataobject = NULL;
5724 	}
5725 }
5726 
on_tDataProperties_selection_changed(GtkTreeSelection * treeselection,gpointer)5727 void on_tDataProperties_selection_changed(GtkTreeSelection *treeselection, gpointer) {
5728 	GtkTreeModel *model;
5729 	GtkTreeIter iter;
5730 	selected_dataproperty = NULL;
5731 	if(gtk_tree_selection_get_selected(treeselection, &model, &iter)) {
5732 		gtk_tree_model_get(model, &iter, 3, &selected_dataproperty, -1);
5733 	}
5734 	if(selected_dataproperty) {
5735 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasetedit_builder, "dataset_edit_button_edit_property")), selected_dataproperty->isUserModified());
5736 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasetedit_builder, "dataset_edit_button_del_property")), selected_dataproperty->isUserModified());
5737 	} else {
5738 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasetedit_builder, "dataset_edit_button_edit_property")), FALSE);
5739 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasetedit_builder, "dataset_edit_button_del_property")), FALSE);
5740 	}
5741 }
5742 
5743 
on_tPlotFunctions_selection_changed(GtkTreeSelection * treeselection,gpointer)5744 void on_tPlotFunctions_selection_changed(GtkTreeSelection *treeselection, gpointer) {
5745 	GtkTreeModel *model;
5746 	GtkTreeIter iter;
5747 	selected_argument = NULL;
5748 	if(gtk_tree_selection_get_selected(treeselection, &model, &iter)) {
5749 		gchar *gstr1, *gstr2, *gstr3;
5750 		gint type, smoothing, style, axis, rows;
5751 		gtk_tree_model_get(model, &iter, 0, &gstr1, 1, &gstr2, 2, &style, 3, &smoothing, 4, &type, 5, &axis, 6, &rows, 9, &gstr3, -1);
5752 		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_expression")), gstr2);
5753 		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_variable")), gstr3);
5754 		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_title")), gstr1);
5755 		gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(plot_builder, "plot_combobox_style")), style);
5756 		gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(plot_builder, "plot_combobox_smoothing")), smoothing);
5757 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_radiobutton_vector")), type == 1);
5758 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_radiobutton_paired")), type == 2);
5759 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_radiobutton_yaxis1")), axis != 2);
5760 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_radiobutton_yaxis2")), axis == 2);
5761 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_checkbutton_rows")), rows);
5762 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_button_remove")), TRUE);
5763 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_button_modify")), TRUE);
5764 		g_free(gstr1);
5765 		g_free(gstr2);
5766 		g_free(gstr3);
5767 	} else {
5768 		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_expression")), "");
5769 		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_variable")), "");
5770 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_button_modify")), FALSE);
5771 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_button_remove")), FALSE);
5772 	}
5773 }
5774 
on_tSubfunctions_selection_changed(GtkTreeSelection * treeselection,gpointer)5775 void on_tSubfunctions_selection_changed(GtkTreeSelection *treeselection, gpointer) {
5776 	GtkTreeModel *model;
5777 	GtkTreeIter iter;
5778 	selected_subfunction = 0;
5779 	if(gtk_tree_selection_get_selected(treeselection, &model, &iter)) {
5780 		gboolean g_b = FALSE;
5781 		guint index = 0;
5782 		gchar *gstr;
5783 		gtk_tree_model_get(model, &iter, 1, &gstr, 3, &index, 4, &g_b, -1);
5784 		selected_subfunction = index;
5785 		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(functionedit_builder, "function_edit_entry_subexpression")), gstr);
5786 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(functionedit_builder, "function_edit_checkbutton_precalculate")), g_b);
5787 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_button_modify_subfunction")), TRUE);
5788 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_button_remove_subfunction")), TRUE);
5789 		g_free(gstr);
5790 	} else {
5791 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_button_modify_subfunction")), FALSE);
5792 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_button_remove_subfunction")), FALSE);
5793 	}
5794 }
5795 
on_tFunctionArguments_selection_changed(GtkTreeSelection * treeselection,gpointer)5796 void on_tFunctionArguments_selection_changed(GtkTreeSelection *treeselection, gpointer) {
5797 	GtkTreeModel *model;
5798 	GtkTreeIter iter;
5799 	selected_argument = NULL;
5800 	if(gtk_tree_selection_get_selected(treeselection, &model, &iter)) {
5801 		Argument *arg;
5802 		gtk_tree_model_get(model, &iter, 2, &arg, -1);
5803 		selected_argument = arg;
5804 		int menu_index = MENU_ARGUMENT_TYPE_FREE;
5805 		if(selected_argument) {
5806 			gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(functionedit_builder, "function_edit_entry_argument_name")), selected_argument->name().c_str());
5807 			switch(selected_argument->type()) {
5808 				case ARGUMENT_TYPE_TEXT: {
5809 					menu_index = MENU_ARGUMENT_TYPE_TEXT;
5810 					break;
5811 				}
5812 				case ARGUMENT_TYPE_SYMBOLIC: {
5813 					menu_index = MENU_ARGUMENT_TYPE_SYMBOLIC;
5814 					break;
5815 				}
5816 				case ARGUMENT_TYPE_DATE: {
5817 					menu_index = MENU_ARGUMENT_TYPE_DATE;
5818 					break;
5819 				}
5820 				case ARGUMENT_TYPE_INTEGER: {
5821 					menu_index = MENU_ARGUMENT_TYPE_INTEGER;
5822 					break;
5823 				}
5824 				case ARGUMENT_TYPE_NUMBER: {
5825 					menu_index = MENU_ARGUMENT_TYPE_NUMBER;
5826 					break;
5827 				}
5828 				case ARGUMENT_TYPE_VECTOR: {
5829 					menu_index = MENU_ARGUMENT_TYPE_VECTOR;
5830 					break;
5831 				}
5832 				case ARGUMENT_TYPE_MATRIX: {
5833 					menu_index = MENU_ARGUMENT_TYPE_MATRIX;
5834 					break;
5835 				}
5836 				case ARGUMENT_TYPE_EXPRESSION_ITEM: {
5837 					menu_index = MENU_ARGUMENT_TYPE_EXPRESSION_ITEM;
5838 					break;
5839 				}
5840 				case ARGUMENT_TYPE_FUNCTION: {
5841 					menu_index = MENU_ARGUMENT_TYPE_FUNCTION;
5842 					break;
5843 				}
5844 				case ARGUMENT_TYPE_UNIT: {
5845 					menu_index = MENU_ARGUMENT_TYPE_UNIT;
5846 					break;
5847 				}
5848 				case ARGUMENT_TYPE_VARIABLE: {
5849 					menu_index = MENU_ARGUMENT_TYPE_VARIABLE;
5850 					break;
5851 				}
5852 				case ARGUMENT_TYPE_FILE: {
5853 					menu_index = MENU_ARGUMENT_TYPE_FILE;
5854 					break;
5855 				}
5856 				case ARGUMENT_TYPE_BOOLEAN: {
5857 					menu_index = MENU_ARGUMENT_TYPE_BOOLEAN;
5858 					break;
5859 				}
5860 				case ARGUMENT_TYPE_ANGLE: {
5861 					menu_index = MENU_ARGUMENT_TYPE_ANGLE;
5862 					break;
5863 				}
5864 				case ARGUMENT_TYPE_DATA_OBJECT: {
5865 					menu_index = MENU_ARGUMENT_TYPE_DATA_OBJECT;
5866 					break;
5867 				}
5868 				case ARGUMENT_TYPE_DATA_PROPERTY: {
5869 					menu_index = MENU_ARGUMENT_TYPE_DATA_PROPERTY;
5870 					break;
5871 				}
5872 			}
5873 		} else {
5874 			gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(functionedit_builder, "function_edit_entry_argument_name")), "");
5875 		}
5876 		gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(functionedit_builder, "function_edit_combobox_argument_type")), menu_index);
5877 		if(!(get_edited_function() && get_edited_function()->isBuiltin())) {
5878 			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_button_rules")), TRUE);
5879 			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_button_remove_argument")), TRUE);
5880 		}
5881 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_button_modify_argument")), TRUE);
5882 	} else {
5883 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_button_modify_argument")), FALSE);
5884 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_button_remove_argument")), FALSE);
5885 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_button_rules")), FALSE);
5886 	}
5887 }
update_function_arguments_list(MathFunction * f)5888 void update_function_arguments_list(MathFunction *f) {
5889 	if(!functionedit_builder) return;
5890 	selected_argument = NULL;
5891 	gtk_list_store_clear(tFunctionArguments_store);
5892 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_button_modify_argument")), FALSE);
5893 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_button_remove_argument")), FALSE);
5894 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_button_rules")), FALSE);
5895 	if(f) {
5896 		GtkTreeIter iter;
5897 		Argument *arg;
5898 		int args = f->maxargs();
5899 		if(args < 0) {
5900 			args = f->minargs() + 1;
5901 		}
5902 		Argument defarg;
5903 		string str, str2;
5904 		for(int i = 1; i <= args; i++) {
5905 			gtk_list_store_append(tFunctionArguments_store, &iter);
5906 			arg = f->getArgumentDefinition(i);
5907 			if(arg) {
5908 				arg = arg->copy();
5909 				str = arg->printlong();
5910 				str2 = arg->name();
5911 			} else {
5912 				str = defarg.printlong();
5913 				str2 = "";
5914 			}
5915 			gtk_list_store_set(tFunctionArguments_store, &iter, 0, str2.c_str(), 1, str.c_str(), 2, (gpointer) arg, -1);
5916 		}
5917 	}
5918 }
5919 
on_tNames_selection_changed(GtkTreeSelection * treeselection,gpointer)5920 void on_tNames_selection_changed(GtkTreeSelection *treeselection, gpointer) {
5921 	GtkTreeModel *model;
5922 	GtkTreeIter iter;
5923 	selected_subfunction = 0;
5924 	if(gtk_tree_selection_get_selected(treeselection, &model, &iter)) {
5925 		gboolean abbreviation = FALSE, suffix = FALSE, unicode = FALSE, plural = FALSE, reference = FALSE, avoid_input = FALSE, case_sensitive = FALSE, completion_only = FALSE;
5926 		gchar *name;
5927 		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);
5928 		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(namesedit_builder, "names_edit_entry_name")), name);
5929 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_abbreviation")), abbreviation);
5930 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_suffix")), suffix);
5931 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_unicode")), unicode);
5932 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_plural")), plural);
5933 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_reference")), reference);
5934 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_avoid_input")), avoid_input);
5935 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_case_sensitive")), case_sensitive);
5936 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_completion_only")), completion_only);
5937 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(namesedit_builder, "names_edit_button_modify")), TRUE);
5938 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(namesedit_builder, "names_edit_button_remove")), TRUE);
5939 		g_free(name);
5940 	} else {
5941 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(namesedit_builder, "names_edit_button_modify")), FALSE);
5942 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(namesedit_builder, "names_edit_button_remove")), FALSE);
5943 	}
5944 }
5945 
shortcut_to_text(guint key,guint state)5946 string shortcut_to_text(guint key, guint state) {
5947 	string str;
5948 #ifdef GDK_WINDOWING_QUARTZ
5949 	if(state & GDK_LOCK_MASK) {str += "Lock";}
5950 	if(state & GDK_CONTROL_MASK) {str += "\xe2\x8c\x83";}
5951 	if(state & GDK_SUPER_MASK) {str += "Super";}
5952 	if(state & GDK_HYPER_MASK) {str += "Hyper";}
5953 	if(state & GDK_META_MASK) {str += "\xe2\x8c\x98";}
5954 	if(state & GDK_MOD1_MASK) {str += "\xe2\x8c\xa5";}
5955 	if(state & GDK_SHIFT_MASK) {str += "\xe2\x87\xa7";}
5956 	if(state & GDK_MOD2_MASK) {str += "Mod2";}
5957 	if(state & GDK_MOD3_MASK) {str += "Mod3";}
5958 	if(state & GDK_MOD4_MASK) {str += "Mod4";}
5959 	if(state & GDK_MOD5_MASK) {str += "Mod5";}
5960 #else
5961 	if(state & GDK_LOCK_MASK) {if(!str.empty()) str += "+"; str += "Lock";}
5962 	if(state & GDK_CONTROL_MASK) {if(!str.empty()) str += "+"; str += "Ctrl";}
5963 	if(state & GDK_SUPER_MASK) {if(!str.empty()) str += "+"; str += "Super";}
5964 	if(state & GDK_HYPER_MASK) {if(!str.empty()) str += "+"; str += "Hyper";}
5965 	if(state & GDK_META_MASK) {if(!str.empty()) str += "+"; str += "Meta";}
5966 	if(state & GDK_MOD1_MASK) {if(!str.empty()) str += "+"; str += "Alt";}
5967 	if(state & GDK_SHIFT_MASK) {if(!str.empty()) str += "+"; str += "Shift";}
5968 	if(state & GDK_MOD2_MASK) {if(!str.empty()) str += "+"; str += "Mod2";}
5969 	if(state & GDK_MOD3_MASK) {if(!str.empty()) str += "+"; str += "Mod3";}
5970 	if(state & GDK_MOD4_MASK) {if(!str.empty()) str += "+"; str += "Mod4";}
5971 	if(state & GDK_MOD5_MASK) {if(!str.empty()) str += "+"; str += "Mod5";}
5972 	if(!str.empty()) str += "+";
5973 #endif
5974 	gunichar uni = gdk_keyval_to_unicode(key);
5975 	if(uni == 0 || !g_unichar_isprint(uni) || g_unichar_isspace(uni)) {
5976 		str += gdk_keyval_name(key);
5977 	} else {
5978 		uni = g_unichar_toupper(uni);
5979 		char s[7];
5980 		s[g_unichar_to_utf8(uni, s)] = '\0';
5981 		str += s;
5982 	}
5983 	return str;
5984 }
shortcut_type_text(int type,bool return_null)5985 const gchar *shortcut_type_text(int type, bool return_null) {
5986 	switch(type) {
5987 		case SHORTCUT_TYPE_FUNCTION: {return _("Insert function"); break;}
5988 		case SHORTCUT_TYPE_FUNCTION_WITH_DIALOG: {return _("Insert function (dialog)"); break;}
5989 		case SHORTCUT_TYPE_VARIABLE: {return _("Insert variable"); break;}
5990 		case SHORTCUT_TYPE_UNIT: {return _("Insert unit"); break;}
5991 		case SHORTCUT_TYPE_TEXT: {return _("Insert text"); break;}
5992 		case SHORTCUT_TYPE_DATE: {return _("Insert date"); break;}
5993 		case SHORTCUT_TYPE_VECTOR: {return _("Insert vector"); break;}
5994 		case SHORTCUT_TYPE_MATRIX: {return _("Insert matrix"); break;}
5995 		case SHORTCUT_TYPE_SMART_PARENTHESES: {return _("Insert smart parentheses"); break;}
5996 		case SHORTCUT_TYPE_CONVERT: {return _("Convert to unit"); break;}
5997 		case SHORTCUT_TYPE_CONVERT_ENTRY: {return _("Convert to unit (entry)"); break;}
5998 		case SHORTCUT_TYPE_OPTIMAL_UNIT: {return _("Convert to optimal unit"); break;}
5999 		case SHORTCUT_TYPE_BASE_UNITS: {return _("Convert to base units"); break;}
6000 		case SHORTCUT_TYPE_OPTIMAL_PREFIX: {return _("Convert to optimal prefix"); break;}
6001 		case SHORTCUT_TYPE_TO_NUMBER_BASE: {return _("Convert to number base"); break;}
6002 		case SHORTCUT_TYPE_FACTORIZE: {return _("Factorize result"); break;}
6003 		case SHORTCUT_TYPE_EXPAND: {return _("Expand result"); break;}
6004 		case SHORTCUT_TYPE_PARTIAL_FRACTIONS: {return _("Expand partial fractions"); break;}
6005 		case SHORTCUT_TYPE_SET_UNKNOWNS: {return _("Set unknowns"); break;}
6006 		case SHORTCUT_TYPE_RPN_DOWN: {return _("RPN: down"); break;}
6007 		case SHORTCUT_TYPE_RPN_UP: {return _("RPN: up"); break;}
6008 		case SHORTCUT_TYPE_RPN_SWAP: {return _("RPN: swap"); break;}
6009 		case SHORTCUT_TYPE_RPN_COPY: {return _("RPN: copy"); break;}
6010 		case SHORTCUT_TYPE_RPN_LASTX: {return _("RPN: lastx"); break;}
6011 		case SHORTCUT_TYPE_RPN_DELETE: {return _("RPN: delete register"); break;}
6012 		case SHORTCUT_TYPE_RPN_CLEAR: {return _("RPN: clear stack"); break;}
6013 		case SHORTCUT_TYPE_META_MODE: {return _("Load meta mode"); break;}
6014 		case SHORTCUT_TYPE_INPUT_BASE: {return _("Set expression base"); break;}
6015 		case SHORTCUT_TYPE_OUTPUT_BASE: {return _("Set result base"); break;}
6016 		case SHORTCUT_TYPE_EXACT_MODE: {return _("Toggle exact mode"); break;}
6017 		case SHORTCUT_TYPE_DEGREES: {return _("Set angle unit to degrees"); break;}
6018 		case SHORTCUT_TYPE_RADIANS: {return _("Set angle unit to radians"); break;}
6019 		case SHORTCUT_TYPE_GRADIANS: {return _("Set angle unit to gradians"); break;}
6020 		case SHORTCUT_TYPE_FRACTIONS: {return _("Toggle simple fractions"); break;}
6021 		case SHORTCUT_TYPE_MIXED_FRACTIONS: {return _("Toggle mixed fractions"); break;}
6022 		case SHORTCUT_TYPE_SCIENTIFIC_NOTATION: {return _("Toggle scientific notation"); break;}
6023 		case SHORTCUT_TYPE_SIMPLE_NOTATION: {return _("Toggle simple notation"); break;}
6024 		case SHORTCUT_TYPE_RPN_MODE: {return _("Toggle RPN mode"); break;}
6025 		case SHORTCUT_TYPE_AUTOCALC: {return _("Toggle calculate as you type"); break;}
6026 		case SHORTCUT_TYPE_PROGRAMMING: {return _("Toggle programming keypad"); break;}
6027 		case SHORTCUT_TYPE_KEYPAD: {return _("Show keypad"); break;}
6028 		case SHORTCUT_TYPE_HISTORY: {return _("Show history"); break;}
6029 		case SHORTCUT_TYPE_HISTORY_SEARCH: {return _("Search history"); break;}
6030 		case SHORTCUT_TYPE_CONVERSION: {return _("Show conversion"); break;}
6031 		case SHORTCUT_TYPE_STACK: {return _("Show RPN stack"); break;}
6032 		case SHORTCUT_TYPE_MINIMAL: {return _("Toggle minimal window"); break;}
6033 		case SHORTCUT_TYPE_MANAGE_VARIABLES: {return _("Manage variables"); break;}
6034 		case SHORTCUT_TYPE_MANAGE_FUNCTIONS: {return _("Manage functions"); break;}
6035 		case SHORTCUT_TYPE_MANAGE_UNITS: {return _("Manage units"); break;}
6036 		case SHORTCUT_TYPE_MANAGE_DATA_SETS: {return _("Manage data sets"); break;}
6037 		case SHORTCUT_TYPE_STORE: {return _("Store result"); break;}
6038 		case SHORTCUT_TYPE_MEMORY_CLEAR: {return _("MC (memory clear)"); break;}
6039 		case SHORTCUT_TYPE_MEMORY_RECALL: {return _("MR (memory recall)"); break;}
6040 		case SHORTCUT_TYPE_MEMORY_STORE: {return _("MS (memory store)"); break;}
6041 		case SHORTCUT_TYPE_MEMORY_ADD: {return _("M+ (memory plus)"); break;}
6042 		case SHORTCUT_TYPE_MEMORY_SUBTRACT: {return _("M− (memory minus)"); break;}
6043 		case SHORTCUT_TYPE_NEW_VARIABLE: {return _("New variable"); break;}
6044 		case SHORTCUT_TYPE_NEW_FUNCTION: {return _("New function"); break;}
6045 		case SHORTCUT_TYPE_PLOT: {return _("Open plot functions/data"); break;}
6046 		case SHORTCUT_TYPE_NUMBER_BASES: {return _("Open convert number bases"); break;}
6047 		case SHORTCUT_TYPE_FLOATING_POINT: {return _("Open floating point conversion"); break;}
6048 		case SHORTCUT_TYPE_CALENDARS: {return _("Open calender conversion"); break;}
6049 		case SHORTCUT_TYPE_PERCENTAGE_TOOL: {return _("Open percentage calculation tool"); break;}
6050 		case SHORTCUT_TYPE_PERIODIC_TABLE: {return _("Open periodic table"); break;}
6051 		case SHORTCUT_TYPE_UPDATE_EXRATES: {return _("Update exchange rates"); break;}
6052 		case SHORTCUT_TYPE_COPY_RESULT: {return _("Copy result"); break;}
6053 		case SHORTCUT_TYPE_SAVE_IMAGE: {return _("Save result image"); break;}
6054 		case SHORTCUT_TYPE_HELP: {return _("Help"); break;}
6055 		case SHORTCUT_TYPE_QUIT: {return _("Quit"); break;}
6056 		case SHORTCUT_TYPE_CHAIN_MODE: {return _("Toggle chain mode"); break;}
6057 	}
6058 	if(return_null) return NULL;
6059 	return "-";
6060 }
update_accels()6061 void update_accels() {
6062 	for(unordered_map<guint64, keyboard_shortcut>::iterator it = keyboard_shortcuts.begin(); it != keyboard_shortcuts.end(); ++it) {
6063 		switch(it->second.type) {
6064 			case SHORTCUT_TYPE_DATE: {
6065 				gtk_accel_label_set_accel(GTK_ACCEL_LABEL(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(main_builder, "menu_item_insert_date")))), it->second.key, (GdkModifierType) it->second.modifier);
6066 				break;
6067 			}
6068 			case SHORTCUT_TYPE_VECTOR: {
6069 				gtk_accel_label_set_accel(GTK_ACCEL_LABEL(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(main_builder, "menu_item_insert_vector")))), it->second.key, (GdkModifierType) it->second.modifier);
6070 				break;
6071 			}
6072 			case SHORTCUT_TYPE_MATRIX: {
6073 				gtk_accel_label_set_accel(GTK_ACCEL_LABEL(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(main_builder, "menu_item_insert_matrix")))), it->second.key, (GdkModifierType) it->second.modifier);
6074 				break;
6075 			}
6076 			case SHORTCUT_TYPE_SMART_PARENTHESES: {
6077 				if(custom_buttons[5].type[0] == -1) {
6078 					gchar *gstr = gtk_widget_get_tooltip_text(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_brace_wrap")));
6079 					if(gstr) {
6080 						string str = gstr;
6081 						g_free(gstr);
6082 						size_t i = str.find("\n");
6083 						if(i != string::npos && str.rfind("(", i) == string::npos) {
6084 							string str2 = " (";
6085 							str2 += shortcut_to_text(it->second.key, it->second.modifier);
6086 							str2 += ")";
6087 							str.insert(i, str2);
6088 							gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_brace_wrap")), str.c_str());
6089 						}
6090 					}
6091 				}
6092 				break;
6093 			}
6094 			case SHORTCUT_TYPE_CONVERT_ENTRY: {
6095 				gtk_accel_label_set_accel(GTK_ACCEL_LABEL(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(main_builder, "menu_item_convert_to_custom_unit")))), it->second.key, (GdkModifierType) it->second.modifier);
6096 				break;
6097 			}
6098 			case SHORTCUT_TYPE_OPTIMAL_UNIT: {
6099 				gtk_accel_label_set_accel(GTK_ACCEL_LABEL(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(main_builder, "menu_item_convert_to_best_unit")))), it->second.key, (GdkModifierType) it->second.modifier);
6100 				break;
6101 			}
6102 			case SHORTCUT_TYPE_BASE_UNITS: {
6103 				gtk_accel_label_set_accel(GTK_ACCEL_LABEL(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(main_builder, "menu_item_convert_to_base_units")))), it->second.key, (GdkModifierType) it->second.modifier);
6104 				break;
6105 			}
6106 			case SHORTCUT_TYPE_FACTORIZE: {
6107 				gtk_accel_label_set_accel(GTK_ACCEL_LABEL(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(main_builder, "menu_item_factorize")))), it->second.key, (GdkModifierType) it->second.modifier);
6108 				break;
6109 			}
6110 			case SHORTCUT_TYPE_EXPAND: {
6111 				gtk_accel_label_set_accel(GTK_ACCEL_LABEL(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(main_builder, "menu_item_simplify")))), it->second.key, (GdkModifierType) it->second.modifier);
6112 				break;
6113 			}
6114 			case SHORTCUT_TYPE_PARTIAL_FRACTIONS: {
6115 				gtk_accel_label_set_accel(GTK_ACCEL_LABEL(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(main_builder, "menu_item_expand_partial_fractions")))), it->second.key, (GdkModifierType) it->second.modifier);
6116 				break;
6117 			}
6118 			case SHORTCUT_TYPE_SET_UNKNOWNS: {
6119 				gtk_accel_label_set_accel(GTK_ACCEL_LABEL(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(main_builder, "menu_item_set_unknowns")))), it->second.key, (GdkModifierType) it->second.modifier);
6120 				break;
6121 			}
6122 			case SHORTCUT_TYPE_RPN_UP: {
6123 				string str = _("Rotate the stack or move selected register up");
6124 				str += " (";
6125 				str += shortcut_to_text(it->second.key, it->second.modifier);
6126 				str += ")";
6127 				gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_registerup")), str.c_str());
6128 				break;
6129 			}
6130 			case SHORTCUT_TYPE_RPN_DOWN: {
6131 				string str = _("Rotate the stack or move selected register down");
6132 				str += " (";
6133 				str += shortcut_to_text(it->second.key, it->second.modifier);
6134 				str += ")";
6135 				gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_registerdown")), str.c_str());
6136 				break;
6137 			}
6138 			case SHORTCUT_TYPE_RPN_SWAP: {
6139 				string str = _("Swap the two top values or move the selected value to the top of the stack");
6140 				str += " (";
6141 				str += shortcut_to_text(it->second.key, it->second.modifier);
6142 				str += ")";
6143 				gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_registerswap")), str.c_str());
6144 				break;
6145 			}
6146 			case SHORTCUT_TYPE_RPN_COPY: {
6147 				string str = _("Copy the selected or top value to the top of the stack");
6148 				str += " (";
6149 				str += shortcut_to_text(it->second.key, it->second.modifier);
6150 				str += ")";
6151 				gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_copyregister")), str.c_str());
6152 				break;
6153 			}
6154 			case SHORTCUT_TYPE_RPN_LASTX: {
6155 				string str = _("Enter the top value from before the last numeric operation");
6156 				str += " (";
6157 				str += shortcut_to_text(it->second.key, it->second.modifier);
6158 				str += ")";
6159 				gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_lastx")), str.c_str());
6160 				break;
6161 			}
6162 			case SHORTCUT_TYPE_RPN_DELETE: {
6163 				string str = _("Delete the top or selected value");
6164 				str += " (";
6165 				str += shortcut_to_text(it->second.key, it->second.modifier);
6166 				str += ")";
6167 				gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_deleteregister")), str.c_str());
6168 				break;
6169 			}
6170 			case SHORTCUT_TYPE_RPN_CLEAR: {
6171 				string str = _("Clear the RPN stack");
6172 				str += " (";
6173 				str += shortcut_to_text(it->second.key, it->second.modifier);
6174 				str += ")";
6175 				gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_clearstack")), str.c_str());
6176 				break;
6177 			}
6178 			case SHORTCUT_TYPE_DEGREES: {
6179 				gtk_accel_label_set_accel(GTK_ACCEL_LABEL(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(main_builder, "menu_item_degrees")))), it->second.key, (GdkModifierType) it->second.modifier);
6180 				break;
6181 			}
6182 			case SHORTCUT_TYPE_RADIANS: {
6183 				gtk_accel_label_set_accel(GTK_ACCEL_LABEL(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(main_builder, "menu_item_radians")))), it->second.key, (GdkModifierType) it->second.modifier);
6184 				break;
6185 			}
6186 			case SHORTCUT_TYPE_GRADIANS: {
6187 				gtk_accel_label_set_accel(GTK_ACCEL_LABEL(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(main_builder, "menu_item_gradians")))), it->second.key, (GdkModifierType) it->second.modifier);
6188 				break;
6189 			}
6190 			case SHORTCUT_TYPE_RPN_MODE: {
6191 				gtk_accel_label_set_accel(GTK_ACCEL_LABEL(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(main_builder, "menu_item_rpn_mode")))), it->second.key, (GdkModifierType) it->second.modifier);
6192 				break;
6193 			}
6194 			case SHORTCUT_TYPE_AUTOCALC: {
6195 				gtk_accel_label_set_accel(GTK_ACCEL_LABEL(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(main_builder, "menu_item_autocalc")))), it->second.key, (GdkModifierType) it->second.modifier);
6196 				break;
6197 			}
6198 			case SHORTCUT_TYPE_HISTORY_SEARCH: {
6199 				gtk_accel_label_set_accel(GTK_ACCEL_LABEL(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(main_builder, "popup_menu_item_history_search")))), it->second.key, (GdkModifierType) it->second.modifier);
6200 				break;
6201 			}
6202 			case SHORTCUT_TYPE_PROGRAMMING: {
6203 				string str = _("Show/hide programming keypad");
6204 				str += " (";
6205 				str += shortcut_to_text(it->second.key, it->second.modifier);
6206 				str += ")";
6207 				gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_programmers_keypad")), str.c_str());
6208 				break;
6209 			}
6210 			case SHORTCUT_TYPE_MINIMAL: {
6211 				gtk_accel_label_set_accel(GTK_ACCEL_LABEL(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(main_builder, "menu_item_minimal_mode")))), it->second.key, (GdkModifierType) it->second.modifier);
6212 				break;
6213 			}
6214 			case SHORTCUT_TYPE_MANAGE_VARIABLES: {
6215 				gtk_accel_label_set_accel(GTK_ACCEL_LABEL(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(main_builder, "menu_item_manage_variables")))), it->second.key, (GdkModifierType) it->second.modifier);
6216 				break;
6217 			}
6218 			case SHORTCUT_TYPE_MANAGE_FUNCTIONS: {
6219 				gtk_accel_label_set_accel(GTK_ACCEL_LABEL(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(main_builder, "menu_item_manage_functions")))), it->second.key, (GdkModifierType) it->second.modifier);
6220 				break;
6221 			}
6222 			case SHORTCUT_TYPE_MANAGE_UNITS: {
6223 				gtk_accel_label_set_accel(GTK_ACCEL_LABEL(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(main_builder, "menu_item_manage_units")))), it->second.key, (GdkModifierType) it->second.modifier);
6224 				break;
6225 			}
6226 			case SHORTCUT_TYPE_MANAGE_DATA_SETS: {
6227 				gtk_accel_label_set_accel(GTK_ACCEL_LABEL(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(main_builder, "menu_item_datasets")))), it->second.key, (GdkModifierType) it->second.modifier);
6228 				break;
6229 			}
6230 			case SHORTCUT_TYPE_STORE: {
6231 				gtk_accel_label_set_accel(GTK_ACCEL_LABEL(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(main_builder, "menu_item_save")))), it->second.key, (GdkModifierType) it->second.modifier);
6232 				break;
6233 			}
6234 			case SHORTCUT_TYPE_NEW_VARIABLE: {
6235 				gtk_accel_label_set_accel(GTK_ACCEL_LABEL(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(main_builder, "menu_item_new_variable")))), it->second.key, (GdkModifierType) it->second.modifier);
6236 				break;
6237 			}
6238 			case SHORTCUT_TYPE_NEW_FUNCTION: {
6239 				gtk_accel_label_set_accel(GTK_ACCEL_LABEL(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(main_builder, "menu_item_new_function_simple")))), it->second.key, (GdkModifierType) it->second.modifier);
6240 				break;
6241 			}
6242 			case SHORTCUT_TYPE_PLOT: {
6243 				gtk_accel_label_set_accel(GTK_ACCEL_LABEL(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(main_builder, "menu_item_plot_functions")))), it->second.key, (GdkModifierType) it->second.modifier);
6244 				break;
6245 			}
6246 			case SHORTCUT_TYPE_NUMBER_BASES: {
6247 				gtk_accel_label_set_accel(GTK_ACCEL_LABEL(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(main_builder, "menu_item_convert_number_bases")))), it->second.key, (GdkModifierType) it->second.modifier);
6248 				break;
6249 			}
6250 			case SHORTCUT_TYPE_FLOATING_POINT: {
6251 				gtk_accel_label_set_accel(GTK_ACCEL_LABEL(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(main_builder, "menu_item_convert_floatingpoint")))), it->second.key, (GdkModifierType) it->second.modifier);
6252 				break;
6253 			}
6254 			case SHORTCUT_TYPE_CALENDARS: {
6255 				gtk_accel_label_set_accel(GTK_ACCEL_LABEL(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(main_builder, "menu_item_show_calendarconversion_dialog")))), it->second.key, (GdkModifierType) it->second.modifier);
6256 				break;
6257 			}
6258 			case SHORTCUT_TYPE_PERCENTAGE_TOOL: {
6259 				gtk_accel_label_set_accel(GTK_ACCEL_LABEL(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(main_builder, "menu_item_show_percentage_dialog")))), it->second.key, (GdkModifierType) it->second.modifier);
6260 				break;
6261 			}
6262 			case SHORTCUT_TYPE_PERIODIC_TABLE: {
6263 				gtk_accel_label_set_accel(GTK_ACCEL_LABEL(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(main_builder, "menu_item_periodic_table")))), it->second.key, (GdkModifierType) it->second.modifier);
6264 				break;
6265 			}
6266 			case SHORTCUT_TYPE_UPDATE_EXRATES: {
6267 				gtk_accel_label_set_accel(GTK_ACCEL_LABEL(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(main_builder, "menu_item_fetch_exchange_rates")))), it->second.key, (GdkModifierType) it->second.modifier);
6268 				break;
6269 			}
6270 			case SHORTCUT_TYPE_COPY_RESULT: {
6271 				gtk_accel_label_set_accel(GTK_ACCEL_LABEL(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(main_builder, "menu_item_copy")))), it->second.key, (GdkModifierType) it->second.modifier);
6272 				break;
6273 			}
6274 			case SHORTCUT_TYPE_SAVE_IMAGE: {
6275 				gtk_accel_label_set_accel(GTK_ACCEL_LABEL(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(main_builder, "menu_item_save_image")))), it->second.key, (GdkModifierType) it->second.modifier);
6276 				break;
6277 			}
6278 			case SHORTCUT_TYPE_HELP: {
6279 				gtk_accel_label_set_accel(GTK_ACCEL_LABEL(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(main_builder, "menu_item_help")))), it->second.key, (GdkModifierType) it->second.modifier);
6280 				break;
6281 			}
6282 			case SHORTCUT_TYPE_QUIT: {
6283 				gtk_accel_label_set_accel(GTK_ACCEL_LABEL(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(main_builder, "menu_item_quit")))), it->second.key, (GdkModifierType) it->second.modifier);
6284 				break;
6285 			}
6286 			case SHORTCUT_TYPE_CHAIN_MODE: {
6287 				gtk_accel_label_set_accel(GTK_ACCEL_LABEL(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(main_builder, "menu_item_chain_mode")))), it->second.key, (GdkModifierType) it->second.modifier);
6288 				break;
6289 			}
6290 		}
6291 	}
6292 }
6293 
6294 /*
6295 	generate unit submenu in expression menu
6296 */
create_umenu()6297 void create_umenu() {
6298 	GtkWidget *item;
6299 	GtkWidget *sub, *sub2, *sub3;
6300 	item = GTK_WIDGET(gtk_builder_get_object(main_builder, "units_menu"));
6301 	sub = gtk_menu_new(); gtk_widget_show (sub); gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), sub);
6302 
6303 	u_menu = sub;
6304 	sub2 = sub;
6305 	Unit *u;
6306 	tree_struct *titem, *titem2;
6307 	unit_cats.rit = unit_cats.items.rbegin();
6308 	if(unit_cats.rit != unit_cats.items.rend()) {
6309 		titem = &*unit_cats.rit;
6310 		++unit_cats.rit;
6311 		titem->rit = titem->items.rbegin();
6312 	} else {
6313 		titem = NULL;
6314 	}
6315 	stack<GtkWidget*> menus;
6316 	menus.push(sub);
6317 	sub3 = sub;
6318 	while(titem) {
6319 		bool b_empty = titem->items.size() == 0;
6320 		if(b_empty) {
6321 			for(size_t i = 0; i < titem->objects.size(); i++) {
6322 				u = (Unit*) titem->objects[i];
6323 				if(u->isActive() && !u->isHidden()) {
6324 					b_empty = false;
6325 					break;
6326 				}
6327 			}
6328 		}
6329 		if(!b_empty) {
6330 			SUBMENU_ITEM_PREPEND(titem->item.c_str(), sub3)
6331 			menus.push(sub);
6332 			sub3 = sub;
6333 			bool is_currencies = false;
6334 			for(size_t i = 0; i < titem->objects.size(); i++) {
6335 				u = (Unit*) titem->objects[i];
6336 				if(!is_currencies && u->isCurrency()) is_currencies = true;
6337 				if(u->isActive() && !u->isHidden()) {
6338 					if(is_currencies) {MENU_ITEM_WITH_POINTER_AND_FLAG(u->title(true).c_str(), insert_unit, u)}
6339 					else {MENU_ITEM_WITH_POINTER(u->title(true).c_str(), insert_unit, u)}
6340 				}
6341 			}
6342 			if(is_currencies) {
6343 				SUBMENU_ITEM_PREPEND(_("more"), sub3)
6344 				for(size_t i = 0; i < titem->objects.size(); i++) {
6345 					u = (Unit*) titem->objects[i];
6346 					if(u->isActive() && u->isHidden()) {
6347 						MENU_ITEM_WITH_POINTER_AND_FLAG(u->title(true).c_str(), insert_unit, u)
6348 					}
6349 				}
6350 			}
6351 		} else {
6352 			titem = titem->parent;
6353 		}
6354 		while(titem && titem->rit == titem->items.rend()) {
6355 			titem = titem->parent;
6356 			menus.pop();
6357 			if(menus.size() > 0) sub3 = menus.top();
6358 		}
6359 		if(titem) {
6360 			titem2 = &*titem->rit;
6361 			++titem->rit;
6362 			titem = titem2;
6363 			titem->rit = titem->items.rbegin();
6364 		}
6365 	}
6366 	sub = sub2;
6367 	for(size_t i = 0; i < unit_cats.objects.size(); i++) {
6368 		u = (Unit*) unit_cats.objects[i];
6369 		if(u->isActive() && !u->isHidden()) {
6370 			MENU_ITEM_WITH_POINTER(u->title(true).c_str(), insert_unit, u)
6371 		}
6372 	}
6373 
6374 	MENU_SEPARATOR
6375 	item = gtk_menu_item_new_with_label(_("Prefixes"));
6376 	gtk_widget_show (item);
6377 	gtk_menu_shell_append(GTK_MENU_SHELL(sub), item);
6378 	create_pmenu(item);
6379 
6380 }
6381 
6382 /*
6383 	generate unit submenu in result menu
6384 */
create_umenu2()6385 void create_umenu2() {
6386 	GtkWidget *item;
6387 	GtkWidget *sub, *sub2, *sub3;
6388 	item = GTK_WIDGET(gtk_builder_get_object(main_builder, "menu_item_result_units"));
6389 	sub = gtk_menu_new(); gtk_widget_show (sub); gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), sub);
6390 	u_menu2 = sub;
6391 	sub2 = sub;
6392 	Unit *u;
6393 	tree_struct *titem, *titem2;
6394 	unit_cats.rit = unit_cats.items.rbegin();
6395 	if(unit_cats.rit != unit_cats.items.rend()) {
6396 		titem = &*unit_cats.rit;
6397 		++unit_cats.rit;
6398 		titem->rit = titem->items.rbegin();
6399 	} else {
6400 		titem = NULL;
6401 	}
6402 	stack<GtkWidget*> menus;
6403 	menus.push(sub);
6404 	sub3 = sub;
6405 	while(titem) {
6406 		bool b_empty = titem->items.size() == 0;
6407 		if(b_empty) {
6408 			for(size_t i = 0; i < titem->objects.size(); i++) {
6409 				u = (Unit*) titem->objects[i];
6410 				if(u->isActive() && !u->isHidden()) {
6411 					b_empty = false;
6412 					break;
6413 				}
6414 			}
6415 		}
6416 		if(!b_empty) {
6417 			SUBMENU_ITEM_PREPEND(titem->item.c_str(), sub3)
6418 			menus.push(sub);
6419 			sub3 = sub;
6420 			bool is_currencies = false;
6421 			for(size_t i = 0; i < titem->objects.size(); i++) {
6422 				u = (Unit*) titem->objects[i];
6423 				if(!is_currencies && u->isCurrency()) is_currencies = true;
6424 				if(u->isActive() && !u->isHidden()) {
6425 					if(is_currencies) {MENU_ITEM_WITH_POINTER_AND_FLAG(u->title(true).c_str(), convert_to_unit, u)}
6426 					else {MENU_ITEM_WITH_POINTER(u->title(true).c_str(), convert_to_unit, u)}
6427 				}
6428 			}
6429 			if(is_currencies) {
6430 				SUBMENU_ITEM_PREPEND(_("more"), sub3)
6431 				for(size_t i = 0; i < titem->objects.size(); i++) {
6432 					u = (Unit*) titem->objects[i];
6433 					if(u->isActive() && u->isHidden()) {
6434 						MENU_ITEM_WITH_POINTER_AND_FLAG(u->title(true).c_str(), convert_to_unit, u)
6435 					}
6436 				}
6437 			}
6438 		} else {
6439 			titem = titem->parent;
6440 		}
6441 		while(titem && titem->rit == titem->items.rend()) {
6442 			titem = titem->parent;
6443 			menus.pop();
6444 			if(menus.size() > 0) sub3 = menus.top();
6445 		}
6446 		if(titem) {
6447 			titem2 = &*titem->rit;
6448 			++titem->rit;
6449 			titem = titem2;
6450 			titem->rit = titem->items.rbegin();
6451 		}
6452 	}
6453 	sub = sub2;
6454 	for(size_t i = 0; i < unit_cats.objects.size(); i++) {
6455 		u = (Unit*) unit_cats.objects[i];
6456 		if(u->isActive() && !u->isHidden()) {
6457 			MENU_ITEM_WITH_POINTER(u->title(true).c_str(), convert_to_unit, u)
6458 		}
6459 	}
6460 }
6461 
6462 /*
6463 	recreate unit menus and update unit manager (when units have changed)
6464 */
update_umenus()6465 void update_umenus() {
6466 	gtk_widget_destroy(u_menu);
6467 	gtk_widget_destroy(u_menu2);
6468 	generate_units_tree_struct();
6469 	create_umenu();
6470 	recreate_recent_units();
6471 	create_umenu2();
6472 	update_units_tree();
6473 	update_unit_selector_tree();
6474 	update_completion();
6475 }
6476 
6477 /*
6478 	generate variables submenu in expression menu
6479 */
create_vmenu()6480 void create_vmenu() {
6481 
6482 	GtkWidget *item;
6483 	GtkWidget *sub, *sub2, *sub3;
6484 	item = GTK_WIDGET(gtk_builder_get_object(main_builder, "variables_menu"));
6485 	sub = gtk_menu_new(); gtk_widget_show (sub); gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), sub);
6486 
6487 	v_menu = sub;
6488 	sub2 = sub;
6489 	Variable *v;
6490 	tree_struct *titem, *titem2;
6491 	variable_cats.rit = variable_cats.items.rbegin();
6492 	if(variable_cats.rit != variable_cats.items.rend()) {
6493 		titem = &*variable_cats.rit;
6494 		++variable_cats.rit;
6495 		titem->rit = titem->items.rbegin();
6496 	} else {
6497 		titem = NULL;
6498 	}
6499 
6500 	stack<GtkWidget*> menus;
6501 	menus.push(sub);
6502 	sub3 = sub;
6503 	while(titem) {
6504 		bool b_empty = titem->items.size() == 0;
6505 		if(b_empty) {
6506 			for(size_t i = 0; i < titem->objects.size(); i++) {
6507 				v = (Variable*) titem->objects[i];
6508 				if(v->isActive() && !v->isHidden()) {
6509 					b_empty = false;
6510 					break;
6511 				}
6512 			}
6513 		}
6514 		if(!b_empty) {
6515 			SUBMENU_ITEM_PREPEND(titem->item.c_str(), sub3)
6516 			menus.push(sub);
6517 			sub3 = sub;
6518 			for(size_t i = 0; i < titem->objects.size(); i++) {
6519 				v = (Variable*) titem->objects[i];
6520 				if(v->isActive() && !v->isHidden()) {
6521 					MENU_ITEM_WITH_POINTER(v->title(true).c_str(), insert_variable, v);
6522 				}
6523 			}
6524 		} else {
6525 			titem = titem->parent;
6526 		}
6527 		while(titem && titem->rit == titem->items.rend()) {
6528 			titem = titem->parent;
6529 			menus.pop();
6530 			if(menus.size() > 0) sub3 = menus.top();
6531 		}
6532 		if(titem) {
6533 			titem2 = &*titem->rit;
6534 			++titem->rit;
6535 			titem = titem2;
6536 			titem->rit = titem->items.rbegin();
6537 		}
6538 	}
6539 	sub = sub2;
6540 
6541 	for(size_t i = 0; i < variable_cats.objects.size(); i++) {
6542 		v = (Variable*) variable_cats.objects[i];
6543 		if(v->isActive() && !v->isHidden()) {
6544 			MENU_ITEM_WITH_POINTER(v->title(true).c_str(), insert_variable, v);
6545 		}
6546 	}
6547 
6548 }
6549 
6550 
6551 /*
6552 	generate prefixes submenu in expression menu
6553 */
create_pmenu(GtkWidget * item)6554 void create_pmenu(GtkWidget *item) {
6555 //	GtkWidget *item;
6556 	GtkWidget *sub;
6557 //	item = GTK_WIDGET(gtk_builder_get_object(main_builder, "menu_item_expression_prefixes"));
6558 	sub = gtk_menu_new(); gtk_widget_show (sub); gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), sub);
6559 	PangoFontDescription *font_desc;
6560 	gtk_style_context_get(gtk_widget_get_style_context(item), GTK_STATE_FLAG_NORMAL, GTK_STYLE_PROPERTY_FONT, &font_desc, NULL);
6561 	int index = 0;
6562 	Prefix *p = CALCULATOR->getPrefix(index);
6563 	while(p) {
6564 		gchar *gstr = NULL;
6565 		switch(p->type()) {
6566 			case PREFIX_DECIMAL: {
6567 				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());
6568 				break;
6569 			}
6570 			case PREFIX_BINARY: {
6571 				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());
6572 				break;
6573 			}
6574 			case PREFIX_NUMBER: {
6575 				gstr = g_strdup_printf("%s", p->name(false, true, &can_display_unicode_string_function, (void*) item).c_str());
6576 				break;
6577 			}
6578 		}
6579 		MENU_ITEM_WITH_POINTER(gstr, insert_prefix, p)
6580 		gtk_label_set_use_markup(GTK_LABEL(gtk_bin_get_child(GTK_BIN(item))), TRUE);
6581 		g_free(gstr);
6582 		index++;
6583 		p = CALCULATOR->getPrefix(index);
6584 	}
6585 	pango_font_description_free(font_desc);
6586 }
6587 
6588 /*
6589 	generate prefixes submenu in result menu
6590 */
create_pmenu2()6591 void create_pmenu2() {
6592 	GtkWidget *item;
6593 	GtkWidget *sub;
6594 	item = GTK_WIDGET(gtk_builder_get_object(main_builder, "menu_item_result_prefixes"));
6595 	sub = gtk_menu_new(); gtk_widget_show (sub); gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), sub);
6596 	int index = 0;
6597 	MENU_ITEM_WITH_POINTER(_("No Prefix"), on_menu_item_set_prefix_activate, CALCULATOR->decimal_null_prefix)
6598 	MENU_ITEM_WITH_POINTER(_("Optimal Prefix"), on_menu_item_set_prefix_activate, NULL)
6599 	Prefix *p = CALCULATOR->getPrefix(index);
6600 	while(p) {
6601 		gchar *gstr = NULL;
6602 		switch(p->type()) {
6603 			case PREFIX_DECIMAL: {
6604 				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());
6605 				break;
6606 			}
6607 			case PREFIX_BINARY: {
6608 				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());
6609 				break;
6610 			}
6611 			case PREFIX_NUMBER: {
6612 				gstr = g_strdup_printf("%s", p->name(false, true, &can_display_unicode_string_function, (void*) item).c_str());
6613 				break;
6614 			}
6615 		}
6616 		MENU_ITEM_WITH_POINTER(gstr, on_menu_item_set_prefix_activate, p)
6617 		gtk_label_set_use_markup(GTK_LABEL(gtk_bin_get_child(GTK_BIN(item))), TRUE);
6618 		g_free(gstr);
6619 		index++;
6620 		p = CALCULATOR->getPrefix(index);
6621 	}
6622 }
6623 
6624 /*
6625 	recreate variables menu and update variable manager (when variables have changed)
6626 */
update_vmenu()6627 void update_vmenu() {
6628 	if(variable_cats.items.empty() && variable_cats.objects.empty()) return;
6629 	gtk_widget_destroy(v_menu);
6630 	generate_variables_tree_struct();
6631 	create_vmenu();
6632 	recreate_recent_variables();
6633 	update_variables_tree();
6634 	update_completion();
6635 	update_mb_sto_menu();
6636 }
6637 
6638 /*
6639 	generate functions submenu in expression menu
6640 */
create_fmenu()6641 void create_fmenu() {
6642 	GtkWidget *item;
6643 	GtkWidget *sub, *sub2, *sub3;
6644 	item = GTK_WIDGET(gtk_builder_get_object(main_builder, "functions_menu"));
6645 	sub = gtk_menu_new(); gtk_widget_show (sub); gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), sub);
6646 	f_menu = sub;
6647 	sub2 = sub;
6648 	MathFunction *f;
6649 	tree_struct *titem, *titem2;
6650 	function_cats.rit = function_cats.items.rbegin();
6651 	if(function_cats.rit != function_cats.items.rend()) {
6652 		titem = &*function_cats.rit;
6653 		++function_cats.rit;
6654 		titem->rit = titem->items.rbegin();
6655 	} else {
6656 		titem = NULL;
6657 	}
6658 	stack<GtkWidget*> menus;
6659 	menus.push(sub);
6660 	sub3 = sub;
6661 	while(titem) {
6662 		bool b_empty = titem->items.size() == 0;
6663 		if(b_empty) {
6664 			for(size_t i = 0; i < titem->objects.size(); i++) {
6665 				f = (MathFunction*) titem->objects[i];
6666 				if(f->isActive() && !f->isHidden()) {
6667 					b_empty = false;
6668 					break;
6669 				}
6670 			}
6671 		}
6672 		if(!b_empty) {
6673 			SUBMENU_ITEM_PREPEND(titem->item.c_str(), sub3)
6674 			for(size_t i = 0; i < titem->objects.size(); i++) {
6675 				f = (MathFunction*) titem->objects[i];
6676 				if(f->isActive() && !f->isHidden()) {
6677 					MENU_ITEM_WITH_POINTER(f->title(true).c_str(), insert_function, f)
6678 				}
6679 			}
6680 			menus.push(sub);
6681 			sub3 = sub;
6682 		} else {
6683 			titem = titem->parent;
6684 		}
6685 		while(titem && titem->rit == titem->items.rend()) {
6686 			titem = titem->parent;
6687 			menus.pop();
6688 			if(menus.size() > 0) sub3 = menus.top();
6689 		}
6690 		if(titem) {
6691 			titem2 = &*titem->rit;
6692 			++titem->rit;
6693 			titem = titem2;
6694 			titem->rit = titem->items.rbegin();
6695 		}
6696 	}
6697 	sub = sub2;
6698 	for(size_t i = 0; i < function_cats.objects.size(); i++) {
6699 		f = (MathFunction*) function_cats.objects[i];
6700 		if(f->isActive() && !f->isHidden()) {
6701 			MENU_ITEM_WITH_POINTER(f->title(true).c_str(), insert_function, f)
6702 		}
6703 	}
6704 }
6705 
sub_suffix(const ExpressionName * ename)6706 string sub_suffix(const ExpressionName *ename) {
6707 	size_t i = ename->name.rfind('_');
6708 	bool b = i == string::npos || i == ename->name.length() - 1 || i == 0;
6709 	size_t i2 = 1;
6710 	string str;
6711 	if(b) {
6712 		if(is_in(NUMBERS, ename->name[ename->name.length() - 1])) {
6713 			while(ename->name.length() > i2 + 1 && is_in(NUMBERS, ename->name[ename->name.length() - 1 - i2])) {
6714 					i2++;
6715 			}
6716 		}
6717 		str += ename->name.substr(0, ename->name.length() - i2);
6718 	} else {
6719 		str += ename->name.substr(0, i);
6720 	}
6721 	str += "<span size=\"small\"><sub>";
6722 	if(b) str += ename->name.substr(ename->name.length() - i2, i2);
6723 	else str += ename->name.substr(i + 1, ename->name.length() - (i + 1));
6724 	str += "</sub></span>";
6725 	return str;
6726 }
6727 
6728 GtkTreeIter completion_separator_iter;
6729 
update_completion()6730 void update_completion() {
6731 
6732 	GtkTreeIter iter;
6733 
6734 	gtk_list_store_clear(completion_store);
6735 
6736 	gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(completion_store), 1, GTK_SORT_ASCENDING);
6737 
6738 	string str, title;
6739 	for(size_t i = 0; i < CALCULATOR->functions.size(); i++) {
6740 		if(CALCULATOR->functions[i]->isActive()) {
6741 			gtk_list_store_append(completion_store, &iter);
6742 			const ExpressionName *ename, *ename_r;
6743 			ename_r = &CALCULATOR->functions[i]->preferredInputName(false, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext);
6744 			if(ename_r->suffix && ename_r->name.length() > 1) {
6745 				str = sub_suffix(ename_r);
6746 			} else {
6747 				str = ename_r->name;
6748 			}
6749 			str += "()";
6750 			for(size_t name_i = 1; name_i <= CALCULATOR->functions[i]->countNames(); name_i++) {
6751 				ename = &CALCULATOR->functions[i]->getName(name_i);
6752 				if(ename && ename != ename_r && !ename->completion_only && !ename->plural && (!ename->unicode || can_display_unicode_string_function(ename->name.c_str(), (void*) expressiontext))) {
6753 					str += " <i>";
6754 					if(ename->suffix && ename->name.length() > 1) {
6755 						str += sub_suffix(ename);
6756 					} else {
6757 						str += ename->name;
6758 					}
6759 					str += "()</i>";
6760 				}
6761 			}
6762 			gtk_list_store_set(completion_store, &iter, 0, str.c_str(), 1, CALCULATOR->functions[i]->title(true, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) expressiontext).c_str(), 2, CALCULATOR->functions[i], 3, FALSE, 4, 0, 6, PANGO_WEIGHT_NORMAL, 7, 0, 8, 1, -1);
6763 		}
6764 	}
6765 	for(size_t i = 0; i < CALCULATOR->variables.size(); i++) {
6766 		if(CALCULATOR->variables[i]->isActive()) {
6767 			gtk_list_store_append(completion_store, &iter);
6768 			const ExpressionName *ename, *ename_r;
6769 			bool b = false;
6770 			ename_r = &CALCULATOR->variables[i]->preferredInputName(false, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext);
6771 			for(size_t name_i = 1; name_i <= CALCULATOR->variables[i]->countNames(); name_i++) {
6772 				ename = &CALCULATOR->variables[i]->getName(name_i);
6773 				if(ename && ename != ename_r && !ename->completion_only && !ename->plural && (!ename->unicode || can_display_unicode_string_function(ename->name.c_str(), (void*) expressiontext))) {
6774 					if(!b) {
6775 						if(ename_r->suffix && ename_r->name.length() > 1) {
6776 							str = sub_suffix(ename_r);
6777 						} else {
6778 							str = ename_r->name;
6779 						}
6780 						b = true;
6781 					}
6782 					str += " <i>";
6783 					if(ename->suffix && ename->name.length() > 1) {
6784 						str += sub_suffix(ename);
6785 					} else {
6786 						str += ename->name;
6787 					}
6788 					str += "</i>";
6789 				}
6790 			}
6791 			if(!b && ename_r->suffix && ename_r->name.length() > 1) {
6792 				str = sub_suffix(ename_r);
6793 				b = true;
6794 			}
6795 			if(printops.use_unicode_signs && can_display_unicode_string_function("→", (void*) expressiontext)) {
6796 				size_t pos = 0;
6797 				if(b) {
6798 					pos = str.find("_to_");
6799 				} else {
6800 					pos = ename_r->name.find("_to_");
6801 					if(pos != string::npos) {
6802 						str = ename_r->name;
6803 						b = true;
6804 					}
6805 				}
6806 				if(b) {
6807 					while(pos != string::npos) {
6808 						if((pos == 1 && str[0] == 'm') || (pos > 1 && str[pos - 1] == 'm' && str[pos - 2] == '>')) {
6809 							str.replace(pos, 4, "<span size=\"small\"><sup>-1</sup></span>→");
6810 						} else {
6811 							str.replace(pos, 4, "→");
6812 						}
6813 						pos = str.find("_to_", pos);
6814 					}
6815 				}
6816 			}
6817 			if(!CALCULATOR->variables[i]->title(false).empty()) {
6818 				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, 1, -1);
6819 				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, 1, -1);
6820 			} else {
6821 				Variable *v = CALCULATOR->variables[i];
6822 				string title;
6823 				if(is_answer_variable(v)) {
6824 					title = _("a previous result");
6825 				} else if(v->isKnown()) {
6826 					if(((KnownVariable*) v)->isExpression()) {
6827 						ParseOptions pa = evalops.parse_options; pa.base = 10;
6828 						title = CALCULATOR->localizeExpression(((KnownVariable*) v)->expression(), pa);
6829 						if(title.length() > 30) {title = title.substr(0, 30); title += "…";}
6830 						else if(!((KnownVariable*) v)->unit().empty()) {title += " "; title += ((KnownVariable*) v)->unit();}
6831 					} else {
6832 						if(((KnownVariable*) v)->get().isMatrix()) {
6833 							title = _("matrix");
6834 						} else if(((KnownVariable*) v)->get().isVector()) {
6835 							title = _("vector");
6836 						} else {
6837 							PrintOptions po;
6838 							po.interval_display = INTERVAL_DISPLAY_SIGNIFICANT_DIGITS;
6839 							title = CALCULATOR->print(((KnownVariable*) v)->get(), 30, po);
6840 							if(title.length() > 30) {title = title.substr(0, 30); title += "…";}
6841 						}
6842 					}
6843 				} else {
6844 					if(((UnknownVariable*) v)->assumptions()) {
6845 						switch(((UnknownVariable*) v)->assumptions()->sign()) {
6846 							case ASSUMPTION_SIGN_POSITIVE: {title = _("positive"); break;}
6847 							case ASSUMPTION_SIGN_NONPOSITIVE: {title = _("non-positive"); break;}
6848 							case ASSUMPTION_SIGN_NEGATIVE: {title = _("negative"); break;}
6849 							case ASSUMPTION_SIGN_NONNEGATIVE: {title = _("non-negative"); break;}
6850 							case ASSUMPTION_SIGN_NONZERO: {title = _("non-zero"); break;}
6851 							default: {}
6852 						}
6853 						if(!title.empty() && ((UnknownVariable*) v)->assumptions()->type() != ASSUMPTION_TYPE_NONE) title += " ";
6854 						switch(((UnknownVariable*) v)->assumptions()->type()) {
6855 							case ASSUMPTION_TYPE_INTEGER: {title += _("integer"); break;}
6856 							case ASSUMPTION_TYPE_RATIONAL: {title += _("rational"); break;}
6857 							case ASSUMPTION_TYPE_REAL: {title += _("real"); break;}
6858 							case ASSUMPTION_TYPE_COMPLEX: {title += _("complex"); break;}
6859 							case ASSUMPTION_TYPE_NUMBER: {title += _("number"); break;}
6860 							case ASSUMPTION_TYPE_NONMATRIX: {title += _("(not matrix)"); break;}
6861 							default: {}
6862 						}
6863 						if(title.empty()) title = _("unknown");
6864 					} else {
6865 						title = _("default assumptions");
6866 					}
6867 				}
6868 				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, 1, -1);
6869 				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, 1, -1);
6870 			}
6871 		}
6872 	}
6873 	for(size_t i = 0; i < CALCULATOR->units.size(); i++) {
6874 		Unit *u = CALCULATOR->units[i];
6875 		if(u->isActive()) {
6876 			if(u->subtype() != SUBTYPE_COMPOSITE_UNIT) {
6877 				gtk_list_store_append(completion_store, &iter);
6878 				const ExpressionName *ename, *ename_r;
6879 				bool b = false;
6880 				ename_r = &u->preferredInputName(false, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext);
6881 				for(size_t name_i = 1; name_i <= u->countNames(); name_i++) {
6882 					ename = &u->getName(name_i);
6883 					if(ename && ename != ename_r && !ename->completion_only && !ename->plural && (!ename->unicode || can_display_unicode_string_function(ename->name.c_str(), (void*) expressiontext))) {
6884 						if(!b) {
6885 							if(ename_r->suffix && ename_r->name.length() > 1) {
6886 								str = sub_suffix(ename_r);
6887 							} else {
6888 								str = ename_r->name;
6889 							}
6890 							b = true;
6891 						}
6892 						str += " <i>";
6893 						if(ename->suffix && ename->name.length() > 1) {
6894 							str += sub_suffix(ename);
6895 						} else {
6896 							str += ename->name;
6897 						}
6898 						str += "</i>";
6899 					}
6900 				}
6901 				if(!b && ename_r->suffix && ename_r->name.length() > 1) {
6902 					str = sub_suffix(ename_r);
6903 					b = true;
6904 				}
6905 				unordered_map<string, GdkPixbuf*>::const_iterator it_flag = flag_images.end();
6906 				title = u->title(true, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) expressiontext);
6907 				if(u->isCurrency()) {
6908 					it_flag = flag_images.find(u->referenceName());
6909 				} else if(u->isSIUnit() && !u->category().empty() && title[title.length() - 1] != ')') {
6910 					size_t i_slash = string::npos;
6911 					if(u->category().length() > 1) i_slash = u->category().rfind("/", u->category().length() - 2);
6912 					if(i_slash != string::npos) i_slash++;
6913 					if(title.length() + u->category().length() - (i_slash == string::npos ? 0 : i_slash) < 35) {
6914 						title += " (";
6915 						if(i_slash == string::npos) title += u->category();
6916 						else title += u->category().substr(i_slash, u->category().length() - i_slash);
6917 						title += ")";
6918 					}
6919 				}
6920 				if(b) gtk_list_store_set(completion_store, &iter, 0, str.c_str(), 1, 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, 1, -1);
6921 				else gtk_list_store_set(completion_store, &iter, 0, ename_r->name.c_str(), 1, 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, 1, -1);
6922 			} else if(!u->isHidden()) {
6923 				CompositeUnit *cu = (CompositeUnit*) u;
6924 				Prefix *prefix = NULL;
6925 				int exp = 1;
6926 				if(cu->countUnits() == 1 && (u = cu->get(1, &exp, &prefix)) != NULL && prefix != NULL && exp == 1) {
6927 					str = "";
6928 					for(size_t name_i = 0; name_i < 3; name_i++) {
6929 						const string *pname;
6930 						if(name_i == 1) pname = &prefix->shortName(false);
6931 						else if(name_i == 2) pname = &prefix->longName(false);
6932 						else pname = &prefix->unicodeName(false);
6933 						if(!pname->empty()) {
6934 							bool b_italic = !str.empty();
6935 							if(b_italic) str += " <i>";
6936 							str += *pname;
6937 							str += u->preferredInputName(name_i != 2, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext).name;
6938 							if(b_italic) str += "</i>";
6939 						}
6940 					}
6941 				} else {
6942 					str = cu->print(false, true, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) expressiontext);
6943 					size_t i_pow = str.find("^");
6944 					while(i_pow != string::npos) {
6945 						size_t i_end = str.find_first_of(NUMBERS);
6946 						if(i_end == string::npos) break;
6947 						if(i_end != str.length() - 1) {
6948 							i_end = str.find_first_not_of(NUMBERS, i_end + 1);
6949 						}
6950 						str.erase(i_pow, 1);
6951 						if(i_end == string::npos) str += "</sup></span>";
6952 						else str.insert(i_end, "</sup></span>");
6953 						str.insert(i_pow, "<span size=\"small\"><sup>");
6954 						if(i_end == string::npos) break;
6955 						i_pow = str.find("^", i_pow + 1);
6956 					}
6957 					if(printops.multiplication_sign == MULTIPLICATION_SIGN_DOT) gsub(saltdot, sdot, str);
6958 					gsub("_unit", "", str);
6959 					gsub("_eunit", "<span size=\"small\"><sub>e</sub></span>", str);
6960 				}
6961 				gtk_list_store_append(completion_store, &iter);
6962 				size_t i_slash = string::npos;
6963 				if(cu->category().length() > 1) i_slash = cu->category().rfind("/", cu->category().length() - 2);
6964 				if(i_slash != string::npos) i_slash++;
6965 				title = cu->title(true, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) expressiontext);
6966 				if(cu->isSIUnit() && !cu->category().empty()) {
6967 					if(title.length() + cu->category().length() - (i_slash == string::npos ? 0 : i_slash) < 35 && title[title.length() - 1] != ')') {
6968 						title += " (";
6969 						if(i_slash == string::npos) title += cu->category();
6970 						else title += cu->category().substr(i_slash, cu->category().length() - i_slash);
6971 						title += ")";
6972 					} else {
6973 						if(i_slash == string::npos) title = cu->category();
6974 						else title = cu->category().substr(i_slash, cu->category().length() - i_slash);
6975 					}
6976 				}
6977 				gtk_list_store_set(completion_store, &iter, 0, str.c_str(), 1, title.c_str(), 2, cu, 3, FALSE, 4, 0, 5, NULL, 6, PANGO_WEIGHT_NORMAL, 7, 0, 8, 1, -1);
6978 			}
6979 		}
6980 	}
6981 	PangoFontDescription *font_desc;
6982 	gtk_style_context_get(gtk_widget_get_style_context(completion_view), GTK_STATE_FLAG_NORMAL, GTK_STYLE_PROPERTY_FONT, &font_desc, NULL);
6983 	for(size_t i = 1; ; i++) {
6984 		Prefix *p = CALCULATOR->getPrefix(i);
6985 		if(!p) break;
6986 		gtk_list_store_append(completion_store, &iter);
6987 		str = "";
6988 		for(size_t name_i = 1; name_i <= 3; name_i++) {
6989 			const string *pstr;
6990 			if(name_i == 1) pstr = &p->longName(false);
6991 			else if(name_i == 2) pstr = &p->unicodeName(false);
6992 			else pstr = &p->shortName(false);
6993 			if(!pstr->empty()) {
6994 				if(!str.empty()) {
6995 					str += " <i>";
6996 					str += *pstr;
6997 					str += "</i>";
6998 				} else {
6999 					str += *pstr;
7000 				}
7001 			}
7002 		}
7003 		gchar *gstr = NULL;
7004 		switch(p->type()) {
7005 			case PREFIX_DECIMAL: {
7006 				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());
7007 				break;
7008 			}
7009 			case PREFIX_BINARY: {
7010 				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());
7011 				break;
7012 			}
7013 			case PREFIX_NUMBER: {
7014 				gstr = g_strdup_printf("%s: %s", _("Prefix"), ((NumberPrefix*) p)->value().print().c_str());
7015 				break;
7016 			}
7017 		}
7018 		gtk_list_store_set(completion_store, &iter, 0, str.c_str(), 1, gstr, 2, p, 3, FALSE, 4, 0, 5, NULL, 6, PANGO_WEIGHT_NORMAL, 7, 0, 8, 2, -1);
7019 		g_free(gstr);
7020 	}
7021 	pango_font_description_free(font_desc);
7022 	string str2;
7023 #define COMPLETION_CONVERT_STRING(x) str = _(x); if(str != x) {str += " <i>"; str += x; str += "</i>";}
7024 #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>";}
7025 	COMPLETION_CONVERT_STRING2("angle", "phasor")
7026 	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, 400, -1);
7027 	COMPLETION_CONVERT_STRING("bases")
7028 	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, 201, -1);
7029 	COMPLETION_CONVERT_STRING("base")
7030 	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, 101, -1);
7031 	COMPLETION_CONVERT_STRING("base ")
7032 	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, 200, -1);
7033 	COMPLETION_CONVERT_STRING("bijective")
7034 	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, 290, -1);
7035 	COMPLETION_CONVERT_STRING("binary") str += " <i>"; str += "bin"; str += "</i>";
7036 	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, 202, -1);
7037 	COMPLETION_CONVERT_STRING("calendars")
7038 	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, 500, -1);
7039 	COMPLETION_CONVERT_STRING("cis")
7040 	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, 401, -1);
7041 	COMPLETION_CONVERT_STRING("decimal") str += " <i>"; str += "dec"; str += "</i>";
7042 	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, 210, -1);
7043 	COMPLETION_CONVERT_STRING("duodecimal") str += " <i>"; str += "duo"; str += "</i>";
7044 	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, 212, -1);
7045 	COMPLETION_CONVERT_STRING("exponential")
7046 	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, 402, -1);
7047 	COMPLETION_CONVERT_STRING("factors")
7048 	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, 600, -1);
7049 	COMPLETION_CONVERT_STRING("fp16") str += " <i>"; str += "binary16"; str += "</i>";
7050 	gtk_list_store_append(completion_store, &iter); gtk_list_store_set(completion_store, &iter, 0, str.c_str(), 1, _("16-bit floating point binary format"), 2, NULL, 3, FALSE, 4, 0, 6, PANGO_WEIGHT_NORMAL, 7, 0, 8, 310, -1);
7051 	COMPLETION_CONVERT_STRING("fp32") str += " <i>"; str += "binary32"; str += "</i>"; str += " <i>"; str += "float"; str += "</i>";
7052 	gtk_list_store_append(completion_store, &iter); gtk_list_store_set(completion_store, &iter, 0, str.c_str(), 1, _("32-bit floating point binary format"), 2, NULL, 3, FALSE, 4, 0, 6, PANGO_WEIGHT_NORMAL, 7, 0, 8, 311, -1);
7053 	COMPLETION_CONVERT_STRING("fp64") str += " <i>"; str += "binary64"; str += "</i>"; str += " <i>"; str += "double"; str += "</i>";
7054 	gtk_list_store_append(completion_store, &iter); gtk_list_store_set(completion_store, &iter, 0, str.c_str(), 1, _("64-bit floating point binary format"), 2, NULL, 3, FALSE, 4, 0, 6, PANGO_WEIGHT_NORMAL, 7, 0, 8, 312, -1);
7055 	COMPLETION_CONVERT_STRING("fp80");
7056 	gtk_list_store_append(completion_store, &iter); gtk_list_store_set(completion_store, &iter, 0, str.c_str(), 1, _("80-bit (x86) floating point binary format"), 2, NULL, 3, FALSE, 4, 0, 6, PANGO_WEIGHT_NORMAL, 7, 0, 8, 313, -1);
7057 	COMPLETION_CONVERT_STRING("fp128") str += " <i>"; str += "binary128"; str += "</i>";
7058 	gtk_list_store_append(completion_store, &iter); gtk_list_store_set(completion_store, &iter, 0, str.c_str(), 1, _("128-bit floating point binary format"), 2, NULL, 3, FALSE, 4, 0, 6, PANGO_WEIGHT_NORMAL, 7, 0, 8, 314, -1);
7059 	COMPLETION_CONVERT_STRING("fraction")
7060 	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, 300, -1);
7061 	COMPLETION_CONVERT_STRING("hexadecimal") str += " <i>"; str += "hex"; str += "</i>";
7062 	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, 216, -1);
7063 	COMPLETION_CONVERT_STRING("mixed")
7064 	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, 102, -1);
7065 	COMPLETION_CONVERT_STRING("octal") str += " <i>"; str += "oct"; str += "</i>";
7066 	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, 208, -1);
7067 	COMPLETION_CONVERT_STRING("optimal")
7068 	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, 100, -1);
7069 	COMPLETION_CONVERT_STRING("partial fraction")
7070 	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, 601, -1);
7071 	COMPLETION_CONVERT_STRING("polar")
7072 	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, 403, -1);
7073 	COMPLETION_CONVERT_STRING2("rectangular", "cartesian")
7074 	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, 404, -1);
7075 	COMPLETION_CONVERT_STRING("roman")
7076 	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, 280, -1);
7077 	COMPLETION_CONVERT_STRING("sexagesimal") str += " <i>"; str += "sexa"; str += "</i>";
7078 	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, 292, -1);
7079 	COMPLETION_CONVERT_STRING("time")
7080 	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, 293, -1);
7081 	COMPLETION_CONVERT_STRING("unicode")
7082 	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, 281, -1);
7083 	COMPLETION_CONVERT_STRING("utc")
7084 	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, 501, -1);
7085 	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, 0, -1);
7086 	gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(completion_store), GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, GTK_SORT_ASCENDING);
7087 }
7088 
7089 /*
7090 	recreate functions menu and update function manager (when functions have changed)
7091 */
update_fmenu()7092 void update_fmenu() {
7093 	if(function_cats.items.empty() && function_cats.objects.empty()) return;
7094 	gtk_widget_destroy(f_menu);
7095 	generate_functions_tree_struct();
7096 	create_fmenu();
7097 	recreate_recent_functions();
7098 	update_completion();
7099 	update_functions_tree();
7100 }
7101 
7102 
get_value_string(const MathStructure & mstruct_,bool rlabel=false,Prefix * prefix=NULL)7103 string get_value_string(const MathStructure &mstruct_, bool rlabel = false, Prefix *prefix = NULL) {
7104 	printops.allow_non_usable = rlabel;
7105 	printops.prefix = prefix;
7106 	string str = CALCULATOR->print(mstruct_, 100, printops);
7107 	printops.allow_non_usable = false;
7108 	printops.prefix = NULL;
7109 	return str;
7110 }
7111 
7112 
draw_background(cairo_t * cr,gint w,gint h)7113 void draw_background(cairo_t *cr, gint w, gint h) {
7114 /*	GdkRGBA rgba;
7115 	gtk_style_context_get_background_color(gtk_widget_get_style_context(resultview), gtk_widget_get_state_flags(resultview);, &rgba);
7116 	gdk_cairo_set_source_rgba(cr, &rgba);
7117 	cairo_rectangle(cr, 0, 0, w, h);
7118 	cairo_fill(cr);*/
7119 }
7120 
7121 #define PAR_SPACE 1
7122 #define PAR_WIDTH (scaledown + ips.power_depth > 1 ? par_width / 1.7 : (scaledown + ips.power_depth > 0 ? par_width / 1.4 : par_width)) + (PAR_SPACE * 2)
7123 
get_left_parenthesis(gint arc_w,gint arc_h,int,GdkRGBA * color)7124 cairo_surface_t *get_left_parenthesis(gint arc_w, gint arc_h, int, GdkRGBA *color) {
7125 	gint scalefactor = gtk_widget_get_scale_factor(expressiontext);
7126 	cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, arc_w * scalefactor, arc_h * scalefactor);
7127 	cairo_surface_set_device_scale(s, scalefactor, scalefactor);
7128 	cairo_t *cr = cairo_create(s);
7129 	gdk_cairo_set_source_rgba(cr, color);
7130 	cairo_save(cr);
7131 	double hscale = 2;
7132 	double radius = arc_w - PAR_SPACE * 2;
7133 	if(radius * 2 * hscale > arc_h - 4) hscale = (arc_h - 4) / (radius * 2.0);
7134 	cairo_scale(cr, 1, hscale);
7135 	cairo_arc(cr, radius + PAR_SPACE, (arc_h - 2) / hscale - radius, radius, 1.8708, 3.14159);
7136 	cairo_arc(cr, radius + PAR_SPACE, radius + 2, radius, 3.14159, 4.41239);
7137 	cairo_restore(cr);
7138 	cairo_set_line_width(cr, arc_w > 7 ? 2 : 1);
7139 	cairo_stroke(cr);
7140 	cairo_destroy(cr);
7141 	return s;
7142 }
get_right_parenthesis(gint arc_w,gint arc_h,int,GdkRGBA * color)7143 cairo_surface_t *get_right_parenthesis(gint arc_w, gint arc_h, int, GdkRGBA *color) {
7144 	gint scalefactor = gtk_widget_get_scale_factor(expressiontext);
7145 	cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, arc_w * scalefactor, arc_h * scalefactor);
7146 	cairo_surface_set_device_scale(s, scalefactor, scalefactor);
7147 	cairo_t *cr = cairo_create(s);
7148 	gdk_cairo_set_source_rgba(cr, color);
7149 	cairo_save(cr);
7150 	double hscale = 2;
7151 	double radius = arc_w - PAR_SPACE * 2;
7152 	if(radius * 2 * hscale > arc_h - 4) hscale = (arc_h - 4) / (radius * 2.0);
7153 	cairo_scale(cr, 1, hscale);
7154 	cairo_arc(cr, PAR_SPACE, radius + 2, radius, -1.2708, 0);
7155 	cairo_arc(cr, PAR_SPACE, (arc_h - 2) / hscale - radius, radius, 0, 1.2708);
7156 	cairo_restore(cr);
7157 	cairo_set_line_width(cr, arc_w > 7 ? 2 : 1);
7158 	cairo_stroke(cr);
7159 	cairo_destroy(cr);
7160 	return s;
7161 }
7162 
get_image_blank_width(cairo_surface_t * surface,int * x1,int * x2)7163 void get_image_blank_width(cairo_surface_t *surface, int *x1, int *x2) {
7164 	int w = cairo_image_surface_get_width(surface);
7165 	int h = cairo_image_surface_get_height(surface);
7166 	unsigned char *data = cairo_image_surface_get_data(surface);
7167 	int stride = cairo_image_surface_get_stride(surface);
7168 	int first_col = w;
7169 	int last_col = -1;
7170 	for(int i = 0; i < h; i++) {
7171 		unsigned char *row = data + i * stride;
7172 		if(x1) {
7173 			for(int j = 0; j < first_col; j++) {
7174 				for(int s_i = 0; s_i < 4; s_i++) {
7175 					if(*(row + 4 * j + s_i) != 0) {
7176 						first_col = j;
7177 						if(first_col > last_col) last_col = first_col;
7178 						break;
7179 					}
7180 				}
7181 			}
7182 		}
7183 		if((first_col != w || !x1) && x2) {
7184 			for(int j = w - 1; j > last_col; j--) {
7185 				for(int s_i = 0; s_i < 4; s_i++) {
7186 					if(*(row + 4 * j + s_i) != 0) {
7187 						last_col = j;
7188 						break;
7189 					}
7190 				}
7191 			}
7192 		}
7193 	}
7194 	if(x1) *x1 = first_col;
7195 	if(x2) *x2 = last_col;
7196 }
get_image_blank_height(cairo_surface_t * surface,int * y1,int * y2)7197 void get_image_blank_height(cairo_surface_t *surface, int *y1, int *y2) {
7198 	int w = cairo_image_surface_get_width(surface);
7199 	int h = cairo_image_surface_get_height(surface);
7200 	unsigned char *data = cairo_image_surface_get_data(surface);
7201 	int stride = cairo_image_surface_get_stride(surface);
7202 	if(y1) {
7203 		*y1 = 0;
7204 		for(int i = 0; i < h - 1; i++) {
7205 			unsigned char *row = data + i * stride;
7206 			for(int j = 0; j < w; j++) {
7207 				for(int s_i = 0; s_i < 4; s_i++) {
7208 					if(*(row + 4 * j + s_i) != 0) {
7209 						*y1 = i;
7210 						j = w; i = h;
7211 						break;
7212 					}
7213 				}
7214 			}
7215 		}
7216 	}
7217 	if(y2) {
7218 		*y2 = h;
7219 		for(int i = h - 1; i > 0; i--) {
7220 			unsigned char *row = data + i * stride;
7221 			for(int j = 0; j < w; j++) {
7222 				for(int s_i = 0; s_i < 4; s_i++) {
7223 					if(*(row + 4 * j + s_i) != 0) {
7224 						*y2 = i;
7225 						j = w; i = 0;
7226 						break;
7227 					}
7228 				}
7229 			}
7230 		}
7231 	}
7232 }
7233 
7234 #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))))
7235 
draw_structure(MathStructure & m,PrintOptions po,bool caf,InternalPrintStruct ips,gint * point_central,int scaledown,GdkRGBA * color,gint * x_offset,gint * w_offset,gint max_width)7236 cairo_surface_t *draw_structure(MathStructure &m, PrintOptions po, bool caf, InternalPrintStruct ips, gint *point_central, int scaledown, GdkRGBA *color, gint *x_offset, gint *w_offset, gint max_width) {
7237 
7238 	if(CALCULATOR->aborted()) return NULL;
7239 
7240 	gint scalefactor = gtk_widget_get_scale_factor(expressiontext);
7241 
7242 	if(ips.depth == 0 && po.is_approximate) *po.is_approximate = false;
7243 
7244 	cairo_surface_t *surface = NULL;
7245 	cairo_t *cr = NULL;
7246 	GdkRGBA rgba;
7247 	if(!color) {
7248 		gtk_style_context_get_color(gtk_widget_get_style_context(resultview), gtk_widget_get_state_flags(resultview), &rgba);
7249 		color = &rgba;
7250 	}
7251 	gint w, h;
7252 	gint central_point = 0;
7253 	gint offset_x = 0;
7254 	gint offset_w = 0;
7255 
7256 	InternalPrintStruct ips_n = ips;
7257 	if(m.isApproximate()) ips_n.parent_approximate = true;
7258 	if(m.precision() > 0 && (ips_n.parent_precision < 1 || m.precision() < ips_n.parent_precision)) ips_n.parent_precision = m.precision();
7259 
7260 	// angle/phasor notation: x+y*i=a*cis(b)=a∠b
7261 	if(caf && m.isMultiplication() && m.size() == 2 && m[1].isFunction() && m[1].size() == 1 && m[1].function()->referenceName() == "cis") {
7262 
7263 		ips_n.depth++;
7264 
7265 		vector<cairo_surface_t*> surface_terms;
7266 
7267 		vector<gint> hpt;
7268 		vector<gint> wpt;
7269 		vector<gint> cpt;
7270 		gint sign_w, sign_h, wtmp, htmp, hetmp = 0, w = 0, h = 0, dh = 0, uh = 0, space_w = 0;
7271 
7272 		PangoLayout *layout_sign = NULL;
7273 
7274 		if(can_display_unicode_string_function_exact("∠", (void*) resultview)) {
7275 			layout_sign = gtk_widget_create_pango_layout(resultview, NULL);
7276 			PANGO_TTP(layout_sign, "∠");
7277 			pango_layout_get_pixel_size(layout_sign, &sign_w, &sign_h);
7278 			w = sign_w;
7279 			uh = sign_h / 2 + sign_h % 2;
7280 			dh = sign_h / 2;
7281 		}
7282 		for(size_t i = 0; i < 2; i++) {
7283 			hetmp = 0;
7284 			ips_n.wrap = false;
7285 			surface_terms.push_back(draw_structure(i == 0 ? m[0] : m[1][0], po, caf, ips_n, &hetmp, scaledown, color));
7286 			if(CALCULATOR->aborted()) {
7287 				for(size_t i = 0; i < surface_terms.size(); i++) {
7288 					if(surface_terms[i]) cairo_surface_destroy(surface_terms[i]);
7289 				}
7290 				return NULL;
7291 			}
7292 			wtmp = cairo_image_surface_get_width(surface_terms[i]) / scalefactor;
7293 			htmp = cairo_image_surface_get_height(surface_terms[i]) / scalefactor;
7294 			hpt.push_back(htmp);
7295 			cpt.push_back(hetmp);
7296 			wpt.push_back(wtmp);
7297 			w += wtmp;
7298 			if(htmp - hetmp > uh) {
7299 				uh = htmp - hetmp;
7300 			}
7301 			if(hetmp > dh) {
7302 				dh = hetmp;
7303 			}
7304 		}
7305 
7306 		central_point = dh;
7307 		h = dh + uh;
7308 
7309 		if(!layout_sign) {
7310 			space_w = 5;
7311 			sign_h = (h * 6) / 10;
7312 			sign_w = sign_h;
7313 			w += sign_w;
7314 		}
7315 
7316 		w += space_w * 2;
7317 
7318 		double divider = 1.0;
7319 		if(ips.power_depth >= 1) divider = 1.5;
7320 		surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
7321 		cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
7322 		cr = cairo_create(surface);
7323 		w = 0;
7324 		for(size_t i = 0; i < surface_terms.size(); i++) {
7325 			if(!CALCULATOR->aborted()) {
7326 				gdk_cairo_set_source_rgba(cr, color);
7327 				if(i > 0) {
7328 					w += space_w;
7329 					if(layout_sign) {
7330 						cairo_move_to(cr, w, uh - sign_h / 2 - sign_h % 2);
7331 						pango_cairo_show_layout(cr, layout_sign);
7332 					} else {
7333 						cairo_move_to(cr, w, h - 2 / divider - (h - sign_h) / 2);
7334 						cairo_line_to(cr, w + (sign_w * 3) / 4, (h - sign_h) / 2);
7335 						cairo_move_to(cr, w, h - 2 / divider - (h - sign_h) / 2);
7336 						cairo_line_to(cr, w + sign_w, h - 2 / divider - (h - sign_h) / 2);
7337 						cairo_set_line_width(cr, 2 / divider);
7338 						cairo_stroke(cr);
7339 					}
7340 					w += sign_w;
7341 					w += space_w;
7342 				}
7343 				cairo_set_source_surface(cr, surface_terms[i], w, uh - (hpt[i] - cpt[i]));
7344 				cairo_paint(cr);
7345 				w += wpt[i];
7346 			}
7347 			cairo_surface_destroy(surface_terms[i]);
7348 		}
7349 		if(layout_sign) g_object_unref(layout_sign);
7350 	} else {
7351 		switch(m.type()) {
7352 			case STRUCT_NUMBER: {
7353 				string str;
7354 				string exp = "";
7355 				bool exp_minus = false;
7356 				ips_n.exp = &exp;
7357 				ips_n.exp_minus = &exp_minus;
7358 				unordered_map<void*, string>::iterator it = number_map.find((void*) &m.number());
7359 				string value_str;
7360 				if(it != number_map.end()) {
7361 					value_str += it->second;
7362 					if(number_approx_map.find((void*) &m.number()) != number_approx_map.end()) {
7363 						if(po.is_approximate && !(*po.is_approximate) && number_approx_map[(void*) &m.number()]) *po.is_approximate = true;
7364 					}
7365 					if(number_exp_map.find((void*) &m.number()) != number_exp_map.end()) {
7366 						exp = number_exp_map[(void*) &m.number()];
7367 						exp_minus = number_exp_minus_map[(void*) &m.number()];
7368 					}
7369 				} else {
7370 					bool was_approx = (po.is_approximate && *po.is_approximate);
7371 					if(po.is_approximate) *po.is_approximate = false;
7372 					value_str = m.number().print(po, ips_n);
7373 					if(po.base == BASE_HEXADECIMAL && po.base_display == BASE_DISPLAY_NORMAL) {
7374 						gsub("0x", "", value_str);
7375 						size_t l = value_str.find(po.decimalpoint());
7376 						if(l == string::npos) l = value_str.length();
7377 						size_t i_after_minus = 0;
7378 						if(m.number().isNegative()) {
7379 							if(l > 1 && value_str[0] == '-') i_after_minus = 1;
7380 							else if(value_str.find("−") == 0) i_after_minus = strlen("−");
7381 						}
7382 						for(int i = (int) l - 2; i > (int) i_after_minus; i -= 2) {
7383 							value_str.insert(i, 1, ' ');
7384 						}
7385 						if(po.binary_bits == 0 && value_str.length() > i_after_minus + 1 && value_str[i_after_minus] == ' ') value_str.insert(i_after_minus + 1, 1, '0');
7386 					} else if(po.base == BASE_OCTAL && po.base_display == BASE_DISPLAY_NORMAL) {
7387 						if(value_str.length() > 1 && value_str[0] == '0' && is_in(NUMBERS, value_str[1])) value_str.erase(0, 1);
7388 					}
7389 					number_map[(void*) &m.number()] = value_str;
7390 					number_exp_map[(void*) &m.number()] = exp;
7391 					number_exp_minus_map[(void*) &m.number()] = exp_minus;
7392 					if(po.is_approximate) {
7393 						number_approx_map[(void*) &m.number()] = po.is_approximate && *po.is_approximate;
7394 					} else {
7395 						number_approx_map[(void*) &m.number()] = FALSE;
7396 					}
7397 					number_base_map[(void*) &m.number()] = "";
7398 					if(po.is_approximate && was_approx) *po.is_approximate = true;
7399 				}
7400 				if((!use_e_notation || (po.base != BASE_DECIMAL && po.base >= 2 && po.base <= 36)) && !exp.empty()) {
7401 					if(value_str == "1") {
7402 						MathStructure mnr(m_one);
7403 						mnr.raise(m_one);
7404 						number_map[(void*) &mnr[0].number()] = (po.base != BASE_DECIMAL && po.base >= 2 && po.base <= 36) ? i2s(po.base) : "10";
7405 						if(exp_minus) {
7406 							mnr[1].transform(STRUCT_NEGATE);
7407 							number_map[(void*) &mnr[1][0].number()] = exp;
7408 						} else {
7409 							number_map[(void*) &mnr[1].number()] = exp;
7410 						}
7411 						surface = draw_structure(mnr, po, caf, ips, point_central, scaledown, color, x_offset, w_offset, max_width);
7412 						if(exp_minus) number_map.erase(&mnr[1][0].number());
7413 						else number_map.erase(&mnr[1].number());
7414 						number_map.erase(&mnr[0].number());
7415 						return surface;
7416 					} else {
7417 						MathStructure mnr(m_one);
7418 						mnr.multiply(m_one);
7419 						number_map[(void*) &mnr[0].number()] = value_str;
7420 						number_approx_map[(void*) &mnr[0].number()] = number_approx_map[(void*) &m.number()];
7421 						mnr[1].raise(m_one);
7422 						number_map[(void*) &mnr[1][0].number()] = (po.base != BASE_DECIMAL && po.base >= 2 && po.base <= 36) ? i2s(po.base) : "10";
7423 						if(exp_minus) {
7424 							mnr[1][1].transform(STRUCT_NEGATE);
7425 							number_map[(void*) &mnr[1][1][0].number()] = exp;
7426 						} else {
7427 							number_map[(void*) &mnr[1][1].number()] = exp;
7428 						}
7429 						surface = draw_structure(mnr, po, caf, ips, point_central, scaledown, color, x_offset, w_offset, max_width);
7430 						if(exp_minus) number_map.erase(&mnr[1][1][0].number());
7431 						else number_map.erase(&mnr[1][1].number());
7432 						number_map.erase(&mnr[1][0].number());
7433 						number_map.erase(&mnr[0].number());
7434 						number_approx_map.erase(&mnr[0].number());
7435 						return surface;
7436 					}
7437 				}
7438 				if(exp.empty() && (po.base == BASE_SEXAGESIMAL || po.base == BASE_TIME)) {
7439 					string estr;
7440 					if(po.lower_case_e) {TTP(estr, "e");}
7441 					else {TTP_SMALL(estr, "E");}
7442 					if(po.lower_case_e) gsub("e", estr, value_str);
7443 					else gsub("E", estr, value_str);
7444 				}
7445 				string value_str_bak, str_bak;
7446 				vector<gint> pos_x;
7447 				vector<PangoLayout*> pos_nr;
7448 				gint pos_h = 0, pos_y = 0;
7449 				gint wle = 0;
7450 				if(max_width > 0) {
7451 					PangoLayout *layout_equals = gtk_widget_create_pango_layout(resultview, NULL);
7452 					if((po.is_approximate && *po.is_approximate) || m.isApproximate()) {
7453 						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))) {
7454 							PANGO_TT(layout_equals, SIGN_ALMOST_EQUAL);
7455 						} else {
7456 
7457 							string str;
7458 							TTB(str);
7459 							str += "= ";
7460 							str += _("approx.");
7461 							TTE(str);
7462 							pango_layout_set_markup(layout_equals, str.c_str(), -1);
7463 						}
7464 					} else {
7465 						PANGO_TT(layout_equals, "=");
7466 					}
7467 					CALCULATE_SPACE_W
7468 					PangoRectangle rect, lrect;
7469 					pango_layout_get_pixel_extents(layout_equals, &rect, &lrect);
7470 					wle = lrect.width - offset_x + space_w;
7471 					if(rect.x < 0) wle -= rect.x;
7472 					g_object_unref(layout_equals);
7473 				}
7474 				PangoLayout *layout = gtk_widget_create_pango_layout(resultview, NULL);
7475 				bool multiline = false;
7476 				int base = po.base;
7477 				if(base <= BASE_FP16 && base >= BASE_FP80) base =  BASE_BINARY;
7478 				for(int try_i = 0; try_i <= 2; try_i++) {
7479 					if(try_i == 1) {
7480 						value_str_bak = value_str;
7481 						size_t i = string::npos, l = 0;
7482 						if(base == BASE_BINARY || (base == BASE_DECIMAL && po.digit_grouping != DIGIT_GROUPING_NONE)) {
7483 							i = value_str.find(" ", value_str.length() / 2);
7484 							l = 1;
7485 							if(i == string::npos && base == BASE_DECIMAL) {
7486 								if(po.digit_grouping != DIGIT_GROUPING_LOCALE) {
7487 									l = strlen(THIN_SPACE);
7488 									i = value_str.find(THIN_SPACE, value_str.length() / 2 - 1);
7489 
7490 								} else if(!CALCULATOR->local_digit_group_separator.empty()) {
7491 									l = CALCULATOR->local_digit_group_separator.length();
7492 									i = value_str.find(CALCULATOR->local_digit_group_separator, value_str.length() / 2 - (l == 3 ? 1 : 0));
7493 								}
7494 							}
7495 						}
7496 						if(i == string::npos && base != BASE_BINARY) {
7497 							l = 0;
7498 							i = value_str.length() / 2 + 2;
7499 							if(base == BASE_DECIMAL && (po.digit_grouping == DIGIT_GROUPING_STANDARD || (po.digit_grouping == DIGIT_GROUPING_LOCALE && CALCULATOR->local_digit_group_separator != " "))) {
7500 								size_t i2 = 0;
7501 								while(true) {
7502 									i2 = value_str.find(po.digit_grouping == DIGIT_GROUPING_LOCALE ? CALCULATOR->local_digit_group_separator : THIN_SPACE, i2 + 1);
7503 									if(i2 == string::npos || i2 == value_str.length() - 1) break;
7504 									i++;
7505 								}
7506 								if(i >= value_str.length()) i = string::npos;
7507 							}
7508 							while(value_str[i] < 0) {
7509 								i++;
7510 								if(i >= value_str.length()) {i = string::npos; break;}
7511 							}
7512 						}
7513 						if(i == string::npos) {
7514 							break;
7515 						} else {
7516 							if(l == 0) value_str.insert(i, 1, '\n');
7517 							else if(l == 1) value_str[i] = '\n';
7518 							else {value_str.erase(i, l - 1); value_str[i] = '\n';}
7519 							if(base == BASE_DECIMAL) pango_layout_set_alignment(layout, PANGO_ALIGN_RIGHT);
7520 							multiline = true;
7521 						}
7522 					} else if(try_i == 2) {
7523 						if(base == BASE_BINARY) {
7524 							PangoLayoutIter *iter = pango_layout_get_iter(layout);
7525 							PangoRectangle crect;
7526 							string str2;
7527 							size_t n_begin = (value_str.length() + 1) % 20;
7528 							for(size_t i = 0; i == 0 || pango_layout_iter_next_char(iter); i++) {
7529 								if((i % 20 == n_begin) || i == value_str.length() - 1) {
7530 									pango_layout_iter_get_char_extents(iter, &crect);
7531 									pango_extents_to_pixels(&crect, NULL);
7532 									PangoLayout *layout_pos = gtk_widget_create_pango_layout(resultview, NULL);
7533 									str2 = "";
7534 									TTB_XSMALL(str2);
7535 									if(i == value_str.length() - 1) str2 += "0";
7536 									else str2 += i2s(((value_str.length() - n_begin) - (value_str.length() - n_begin) / 5) - ((i - n_begin) - (i - n_begin) / 5) - 1);
7537 									TTE(str2);
7538 									pango_layout_set_markup(layout_pos, str2.c_str(), -1);
7539 									pos_nr.push_back(layout_pos);
7540 									if(i == value_str.length() - 1) {
7541 										pango_layout_get_pixel_size(layout_pos, &w, &pos_h);
7542 										pos_x.push_back(crect.x + (crect.width - w) / 2);
7543 										break;
7544 									} else {
7545 										pos_x.push_back(crect.x);
7546 									}
7547 								}
7548 							}
7549 							pango_layout_iter_free(iter);
7550 						}
7551 						break;
7552 					}
7553 					TTBP(str)
7554 					str += value_str;
7555 					if(!exp.empty()) {
7556 						if(po.lower_case_e) {TTP(str, "e");}
7557 						else {TTP_SMALL(str, "E");}
7558 						if(exp_minus) {
7559 							str += "-";
7560 						}
7561 						str += exp;
7562 					}
7563 					bool twos = (((po.base == BASE_BINARY && po.twos_complement) || (po.base == BASE_HEXADECIMAL && po.hexadecimal_twos_complement)) && m.number().isNegative() && value_str.find(SIGN_MINUS) == string::npos && value_str.find("-") == string::npos);
7564 					if(base != BASE_DECIMAL && (twos || po.base_display != BASE_DISPLAY_ALTERNATIVE || (base != BASE_HEXADECIMAL && base != BASE_BINARY && base != BASE_OCTAL)) && (base > 0 || base <= BASE_CUSTOM) && base <= 36) {
7565 						if(!multiline) {
7566 							string str2 = str;
7567 							TTE(str2)
7568 							pango_layout_set_markup(layout, str2.c_str(), -1);
7569 							pango_layout_get_pixel_size(layout, NULL, &central_point);
7570 						}
7571 						TTBP_SMALL(str)
7572 						str += "<sub>";
7573 						string str_base;
7574 						if(it != number_map.end()) {
7575 							str_base = number_base_map[(void*) &m.number()];
7576 						} else {
7577 							switch(base) {
7578 								case BASE_GOLDEN_RATIO: {str_base = "<i>φ</i>"; break;}
7579 								case BASE_SUPER_GOLDEN_RATIO: {str_base = "<i>ψ</i>"; break;}
7580 								case BASE_PI: {str_base = "<i>π</i>"; break;}
7581 								case BASE_E: {str_base = "<i>e</i>"; break;}
7582 								case BASE_SQRT2: {str_base = "√2"; break;}
7583 								case BASE_UNICODE: {str_base = "Unicode"; break;}
7584 								case BASE_BIJECTIVE_26: {str_base = "b26"; break;}
7585 								case BASE_CUSTOM: {str_base = CALCULATOR->customOutputBase().print(CALCULATOR->messagePrintOptions()); break;}
7586 								default: {str_base = i2s(base);}
7587 							}
7588 							if(twos) str_base += '-';
7589 							number_base_map[(void*) &m.number()] = str_base;
7590 						}
7591 						str += str_base;
7592 						str += "</sub>";
7593 						TTE(str)
7594 					}
7595 					TTE(str)
7596 					pango_layout_set_markup(layout, str.c_str(), -1);
7597 					if(max_width > 0 && exp.empty() && ((base >= 2 && base <= 36 && base != BASE_DUODECIMAL) || (base == BASE_CUSTOM && CALCULATOR->customOutputBase().isInteger() && CALCULATOR->customOutputBase() <= 62 && CALCULATOR->customOutputBase() >= -62))) {
7598 						pango_layout_get_pixel_size(layout, &w, NULL);
7599 						if(w + wle > max_width) {
7600 							if(try_i == 1) {
7601 								str = str_bak;
7602 								pango_layout_set_markup(layout, str.c_str(), -1);
7603 								multiline = false;
7604 								if(base != BASE_BINARY) break;
7605 							} else {
7606 								str_bak = str;
7607 								str = "";
7608 							}
7609 						} else {
7610 							break;
7611 						}
7612 					} else {
7613 						break;
7614 					}
7615 				}
7616 				PangoRectangle rect, lrect;
7617 				pango_layout_get_pixel_extents(layout, &rect, &lrect);
7618 				w = lrect.width;
7619 				h = lrect.height;
7620 				if(rect.x < 0) {
7621 					w -= rect.x;
7622 					if(rect.width > w) {
7623 						offset_w = rect.width - w;
7624 						w = rect.width;
7625 					}
7626 					offset_x = -rect.x;
7627 				} else {
7628 					if(rect.width + rect.x > w) {
7629 						offset_w = rect.width + rect.x - w;
7630 						w = rect.width + rect.x;
7631 					}
7632 				}
7633 				if(multiline) {
7634 					pango_layout_line_get_pixel_extents(pango_layout_get_line(layout, 0), NULL, &lrect);
7635 					central_point = h - (lrect.height / 2 + lrect.height % 2);
7636 				} else if(central_point != 0) {
7637 					pos_y = central_point;
7638 					if(pos_h + pos_y > h) h = pos_h + pos_y;
7639 					central_point = h - (central_point / 2 + central_point % 2);
7640 				} else {
7641 					central_point = h / 2;
7642 					pos_y = h;
7643 					h += pos_h;
7644 				}
7645 				if(rect.y < 0) {
7646 					h -= rect.y;
7647 					pos_y -= rect.y;
7648 				}
7649 				surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
7650 				cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
7651 				cr = cairo_create(surface);
7652 				gdk_cairo_set_source_rgba(cr, color);
7653 				cairo_move_to(cr, offset_x, rect.y < 0 ? -rect.y : 0);
7654 				pango_cairo_show_layout(cr, layout);
7655 				for(size_t i = 0; i < pos_nr.size(); i++) {
7656 					cairo_move_to(cr, pos_x[i], pos_y);
7657 					pango_cairo_show_layout(cr, pos_nr[i]);
7658 					g_object_unref(pos_nr[i]);
7659 				}
7660 				g_object_unref(layout);
7661 				break;
7662 			}
7663 			case STRUCT_ABORTED: {}
7664 			case STRUCT_SYMBOLIC: {
7665 				PangoLayout *layout = gtk_widget_create_pango_layout(resultview, NULL);
7666 				string str;
7667 				str = "<i>";
7668 				TTBP(str)
7669 				str += m.symbol();
7670 				TTE(str)
7671 				str += "</i>";
7672 				pango_layout_set_markup(layout, str.c_str(), -1);
7673 				PangoRectangle rect, lrect;
7674 				pango_layout_get_pixel_extents(layout, &rect, &lrect);
7675 				w = lrect.width;
7676 				h = lrect.height;
7677 				if(rect.x < 0) {
7678 					w -= rect.x;
7679 					if(rect.width > w) {
7680 						offset_w = rect.width - w;
7681 						w = rect.width;
7682 					}
7683 					offset_x = -rect.x;
7684 				} else {
7685 					if(rect.width + rect.x > w) {
7686 						offset_w = rect.width + rect.x - w;
7687 						w = rect.width + rect.x;
7688 					}
7689 				}
7690 				central_point = h / 2;
7691 				if(rect.y < 0) h -= rect.y;
7692 				surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
7693 				cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
7694 				cr = cairo_create(surface);
7695 				gdk_cairo_set_source_rgba(cr, color);
7696 				cairo_move_to(cr, offset_x, rect.y < 0 ? -rect.y : 0);
7697 				pango_cairo_show_layout(cr, layout);
7698 				g_object_unref(layout);
7699 				break;
7700 			}
7701 			case STRUCT_DATETIME: {
7702 				PangoLayout *layout = gtk_widget_create_pango_layout(resultview, NULL);
7703 				string str;
7704 				TTBP(str)
7705 				unordered_map<void*, string>::iterator it = date_map.find((void*) m.datetime());
7706 				if(it != date_map.end()) {
7707 					str += it->second;
7708 					if(date_approx_map.find((void*) m.datetime()) != date_approx_map.end()) {
7709 						if(po.is_approximate && !(*po.is_approximate) && date_approx_map[(void*) m.datetime()]) *po.is_approximate = true;
7710 					}
7711 				} else {
7712 					bool was_approx = (po.is_approximate && *po.is_approximate);
7713 					if(po.is_approximate) *po.is_approximate = false;
7714 					string value_str = m.datetime()->print(po);
7715 					date_map[(void*) m.datetime()] = value_str;
7716 					date_approx_map[(void*) m.datetime()] = po.is_approximate && *po.is_approximate;
7717 					if(po.is_approximate && was_approx) *po.is_approximate = true;
7718 					str += value_str;
7719 				}
7720 				TTE(str)
7721 				pango_layout_set_markup(layout, str.c_str(), -1);
7722 				PangoRectangle rect, lrect;
7723 				pango_layout_get_pixel_extents(layout, &rect, &lrect);
7724 				w = lrect.width;
7725 				h = lrect.height;
7726 				if(rect.x < 0) {
7727 					w -= rect.x;
7728 					if(rect.width > w) {
7729 						offset_w = rect.width - w;
7730 						w = rect.width;
7731 					}
7732 					offset_x = -rect.x;
7733 				} else {
7734 					if(rect.width + rect.x > w) {
7735 						offset_w = rect.width + rect.x - w;
7736 						w = rect.width + rect.x;
7737 					}
7738 				}
7739 				central_point = h / 2;
7740 				if(rect.y < 0) h -= rect.y;
7741 				surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
7742 				cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
7743 				cr = cairo_create(surface);
7744 				gdk_cairo_set_source_rgba(cr, color);
7745 				cairo_move_to(cr, offset_x, rect.y < 0 ? -rect.y : 0);
7746 				pango_cairo_show_layout(cr, layout);
7747 				g_object_unref(layout);
7748 				break;
7749 			}
7750 			case STRUCT_ADDITION: {
7751 				ips_n.depth++;
7752 
7753 				vector<cairo_surface_t*> surface_terms;
7754 				vector<gint> hpt, wpt, cpt, xpt;
7755 				gint plus_w, plus_h, minus_w, minus_h, wtmp, htmp, hetmp = 0, w = 0, h = 0, dh = 0, uh = 0, xtmp = 0, wotmp = 0;
7756 
7757 				CALCULATE_SPACE_W
7758 				PangoLayout *layout_plus = gtk_widget_create_pango_layout(resultview, NULL);
7759 				PANGO_TTP(layout_plus, "+");
7760 				pango_layout_get_pixel_size(layout_plus, &plus_w, &plus_h);
7761 				PangoLayout *layout_minus = gtk_widget_create_pango_layout(resultview, NULL);
7762 				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))) {
7763 					PANGO_TTP(layout_minus, SIGN_MINUS);
7764 				} else {
7765 					PANGO_TTP(layout_minus, "-");
7766 				}
7767 				pango_layout_get_pixel_size(layout_minus, &minus_w, &minus_h);
7768 				for(size_t i = 0; i < m.size(); i++) {
7769 					hetmp = 0;
7770 					if(m[i].type() == STRUCT_NEGATE && i > 0) {
7771 						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);
7772 						surface_terms.push_back(draw_structure(m[i][0], po, caf, ips_n, &hetmp, scaledown, color, &xtmp, &wotmp));
7773 					} else {
7774 						ips_n.wrap = m[i].needsParenthesis(po, ips_n, m, i + 1, ips.division_depth > 0 || ips.power_depth > 0, ips.power_depth > 0);
7775 						surface_terms.push_back(draw_structure(m[i], po, caf, ips_n, &hetmp, scaledown, color, &xtmp, &wotmp));
7776 					}
7777 					if(CALCULATOR->aborted()) {
7778 						for(size_t i = 0; i < surface_terms.size(); i++) {
7779 							if(surface_terms[i]) cairo_surface_destroy(surface_terms[i]);
7780 						}
7781 						g_object_unref(layout_minus);
7782 						g_object_unref(layout_plus);
7783 						return NULL;
7784 					}
7785 					if(i == 0) {
7786 						offset_x = xtmp;
7787 						xtmp = 0;
7788 					} else if(i == m.size() - 1) {
7789 						offset_w = wotmp;
7790 						wotmp = 0;
7791 					}
7792 					wtmp = cairo_image_surface_get_width(surface_terms[i]) / scalefactor;
7793 					htmp = cairo_image_surface_get_height(surface_terms[i]) / scalefactor;
7794 					hpt.push_back(htmp);
7795 					cpt.push_back(hetmp);
7796 					wpt.push_back(wtmp);
7797 					xpt.push_back(xtmp);
7798 					w -= xtmp;
7799 					w += wtmp;
7800 					if(m[i].type() == STRUCT_NEGATE && i > 0) {
7801 						w += minus_w;
7802 						if(minus_h / 2 > dh) {
7803 							dh = minus_h / 2;
7804 						}
7805 						if(minus_h / 2 + minus_h % 2 > uh) {
7806 							uh = minus_h / 2 + minus_h % 2;
7807 						}
7808 					} else if(i > 0) {
7809 						w += plus_w;
7810 						if(plus_h / 2 > dh) {
7811 							dh = plus_h / 2;
7812 						}
7813 						if(plus_h / 2 + plus_h % 2 > uh) {
7814 							uh = plus_h / 2 + plus_h % 2;
7815 						}
7816 					}
7817 					if(htmp - hetmp > uh) {
7818 						uh = htmp - hetmp;
7819 					}
7820 					if(hetmp > dh) {
7821 						dh = hetmp;
7822 					}
7823 				}
7824 				w += space_w * (surface_terms.size() - 1) * 2;
7825 				central_point = dh;
7826 				h = dh + uh;
7827 				surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
7828 				cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
7829 				cr = cairo_create(surface);
7830 				w = 0;
7831 				for(size_t i = 0; i < surface_terms.size(); i++) {
7832 					if(!CALCULATOR->aborted()) {
7833 						gdk_cairo_set_source_rgba(cr, color);
7834 						if(i > 0) {
7835 							w += space_w;
7836 							if(m[i].type() == STRUCT_NEGATE) {
7837 								cairo_move_to(cr, w, uh - minus_h / 2 - minus_h % 2);
7838 								pango_cairo_show_layout(cr, layout_minus);
7839 								w += minus_w;
7840 							} else {
7841 								cairo_move_to(cr, w, uh - plus_h / 2 - plus_h % 2);
7842 								pango_cairo_show_layout(cr, layout_plus);
7843 								w += plus_w;
7844 							}
7845 							w += space_w;
7846 						}
7847 						w -= xpt[i];
7848 						cairo_set_source_surface(cr, surface_terms[i], w, uh - (hpt[i] - cpt[i]));
7849 						cairo_paint(cr);
7850 						w += wpt[i];
7851 					}
7852 					cairo_surface_destroy(surface_terms[i]);
7853 				}
7854 				g_object_unref(layout_minus);
7855 				g_object_unref(layout_plus);
7856 				break;
7857 			}
7858 			case STRUCT_NEGATE: {
7859 				ips_n.depth++;
7860 
7861 				gint minus_w, minus_h, uh, dh, h, w, ctmp, htmp, wtmp, hpa, cpa, xtmp;
7862 
7863 				PangoLayout *layout_minus = gtk_widget_create_pango_layout(resultview, NULL);
7864 
7865 				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))) {
7866 					PANGO_TTP(layout_minus, SIGN_MINUS);
7867 				} else {
7868 					PANGO_TTP(layout_minus, "-");
7869 				}
7870 				PangoRectangle rect, lrect;
7871 				pango_layout_get_pixel_extents(layout_minus, &rect, &lrect);
7872 				minus_w = lrect.width;
7873 				minus_h = lrect.height;
7874 				if(rect.x < 0) {
7875 					minus_w -= rect.x;
7876 					offset_x = -rect.x;
7877 				}
7878 
7879 				w = minus_w + 1;
7880 				uh = minus_h / 2 + minus_h % 2;
7881 				dh = minus_h / 2;
7882 
7883 				ips_n.wrap = m[0].isPower() ? m[0][0].needsParenthesis(po, ips_n, m, 1, ips.division_depth > 0 || ips.power_depth > 0, ips.power_depth > 0) : m[0].needsParenthesis(po, ips_n, m, 1, ips.division_depth > 0 || ips.power_depth > 0, ips.power_depth > 0);
7884 				cairo_surface_t *surface_arg = draw_structure(m[0], po, caf, ips_n, &ctmp, scaledown, color, &xtmp, &offset_w, ips.depth == 0 && max_width > 0 ? max_width - minus_w : -1);
7885 				if(!surface_arg) {
7886 					g_object_unref(layout_minus);
7887 					return NULL;
7888 				}
7889 				wtmp = cairo_image_surface_get_width(surface_arg) / scalefactor;
7890 				htmp = cairo_image_surface_get_height(surface_arg) / scalefactor;
7891 				hpa = htmp;
7892 				cpa = ctmp;
7893 				w += wtmp - xtmp;
7894 				if(ctmp > dh) {
7895 					dh = ctmp;
7896 				}
7897 				if(htmp - ctmp > uh) {
7898 					uh = htmp - ctmp;
7899 				}
7900 
7901 				h = uh + dh;
7902 				central_point = dh;
7903 
7904 				surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
7905 				cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
7906 				cr = cairo_create(surface);
7907 
7908 				w = offset_x;
7909 				gdk_cairo_set_source_rgba(cr, color);
7910 				cairo_move_to(cr, w, uh - minus_h / 2 - minus_h % 2);
7911 				pango_cairo_show_layout(cr, layout_minus);
7912 				w += minus_w + 1 - xtmp;
7913 				cairo_set_source_surface(cr, surface_arg, w, uh - (hpa - cpa));
7914 				cairo_paint(cr);
7915 				cairo_surface_destroy(surface_arg);
7916 
7917 				g_object_unref(layout_minus);
7918 				break;
7919 			}
7920 			case STRUCT_MULTIPLICATION: {
7921 
7922 				ips_n.depth++;
7923 
7924 				vector<cairo_surface_t*> surface_terms;
7925 				vector<gint> hpt, wpt, cpt, xpt, wopt;
7926 				gint mul_w = 0, mul_h = 0, altmul_w = 0, altmul_h = 0, wtmp, htmp, hetmp = 0, w = 0, h = 0, dh = 0, uh = 0, xtmp = 0, wotmp = 0;
7927 
7928 				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())));
7929 
7930 				CALCULATE_SPACE_W
7931 				PangoLayout *layout_mul = NULL, *layout_altmul = NULL;
7932 
7933 				bool par_prev = false;
7934 				vector<int> nm;
7935 				for(size_t i = 0; i < m.size(); i++) {
7936 					hetmp = 0;
7937 					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);
7938 					surface_terms.push_back(draw_structure((b_cis && i == 1) ? m[i][0] : m[i], po, caf, ips_n, &hetmp, scaledown, color, &xtmp, &wotmp));
7939 					if(CALCULATOR->aborted()) {
7940 						for(size_t i = 0; i < surface_terms.size(); i++) {
7941 							if(surface_terms[i]) cairo_surface_destroy(surface_terms[i]);
7942 						}
7943 						g_object_unref(layout_mul);
7944 						return NULL;
7945 					}
7946 					wtmp = cairo_image_surface_get_width(surface_terms[i]) / scalefactor;
7947 					if(i == 0) {
7948 						offset_x = xtmp;
7949 						xtmp = 0;
7950 					} else if(i == m.size() - 1) {
7951 						offset_w = wotmp;
7952 						wotmp = 0;
7953 					}
7954 					htmp = cairo_image_surface_get_height(surface_terms[i]) / scalefactor;
7955 					hpt.push_back(htmp);
7956 					cpt.push_back(hetmp);
7957 					wpt.push_back(wtmp);
7958 					xpt.push_back(xtmp);
7959 					wopt.push_back(wotmp);
7960 					w -= wotmp;
7961 					w -= xtmp;
7962 					w += wtmp;
7963 					if(i > 0) {
7964 						if(b_cis || !po.short_multiplication) {
7965 							nm.push_back(MULTIPLICATION_SIGN_OPERATOR);
7966 						} else {
7967 							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));
7968 							if(nm[i] == MULTIPLICATION_SIGN_NONE && m[i].isPower() && m[i][0].isUnit() && po.use_unicode_signs && po.abbreviate_names && m[i][0].unit() == CALCULATOR->getDegUnit()) {
7969 								PrintOptions po2 = po;
7970 								po2.use_unicode_signs = false;
7971 								nm[i] = m[i].neededMultiplicationSign(po2, 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);
7972 							}
7973 						}
7974 						if(nm[i] != MULTIPLICATION_SIGN_NONE) {
7975 							w += wopt[i - 1];
7976 							wopt[i - 1] = 0;
7977 						}
7978 						switch(nm[i]) {
7979 							case MULTIPLICATION_SIGN_SPACE: {
7980 								w += space_w;
7981 								break;
7982 							}
7983 							case MULTIPLICATION_SIGN_OPERATOR_SHORT: {}
7984 							case MULTIPLICATION_SIGN_OPERATOR: {
7985 								if(!b_cis && po.place_units_separately && po.multiplication_sign == MULTIPLICATION_SIGN_X && m[i].isUnit_exp() && m[i - 1].isUnit_exp() && (!po.can_display_unicode_string_function || (*po.can_display_unicode_string_function) (SIGN_MIDDLEDOT, po.can_display_unicode_string_arg))) {
7986 									if(!layout_altmul) {
7987 										string str;
7988 										TTP_SMALL(str, SIGN_MIDDLEDOT);
7989 										layout_altmul = gtk_widget_create_pango_layout(resultview, NULL);
7990 										pango_layout_set_markup(layout_altmul, str.c_str(), -1);
7991 										pango_layout_get_pixel_size(layout_altmul, &altmul_w, &altmul_h);
7992 									}
7993 									w += altmul_w + (space_w / 2) * 2;
7994 									if(altmul_h / 2 > dh) {
7995 										dh = altmul_h / 2;
7996 									}
7997 									if(altmul_h / 2 + altmul_h % 2 > uh) {
7998 										uh = altmul_h / 2 + altmul_h % 2;
7999 									}
8000 									break;
8001 								}
8002 								if(!layout_mul) {
8003 									string str;
8004 									if(b_cis) {
8005 										TTP(str, "cis");
8006 									} 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))) {
8007 										TTP_SMALL(str, SIGN_MULTIDOT);
8008 									} 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))) {
8009 										TTP_SMALL(str, SIGN_MIDDLEDOT);
8010 									} 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))) {
8011 										TTP_SMALL(str, SIGN_MULTIPLICATION);
8012 									} else {
8013 										TTP(str, "*");
8014 									}
8015 									layout_mul = gtk_widget_create_pango_layout(resultview, NULL);
8016 									pango_layout_set_markup(layout_mul, str.c_str(), -1);
8017 									pango_layout_get_pixel_size(layout_mul, &mul_w, &mul_h);
8018 								}
8019 								if(nm[i] == MULTIPLICATION_SIGN_OPERATOR_SHORT && m[i].isUnit_exp() && m[i - 1].isUnit_exp()) w += mul_w + (space_w / 2) * 2;
8020 								else if(nm[i] == MULTIPLICATION_SIGN_OPERATOR_SHORT) w += mul_w;
8021 								else w += mul_w + space_w * 2;
8022 								if(mul_h / 2 > dh) {
8023 									dh = mul_h / 2;
8024 								}
8025 								if(mul_h / 2 + mul_h % 2 > uh) {
8026 									uh = mul_h / 2 + mul_h % 2;
8027 								}
8028 								break;
8029 							}
8030 							default: {
8031 								if(par_prev || (m[i - 1].size() && m[i - 1].type() != STRUCT_POWER)) {
8032 									w += xtmp;
8033 									xpt[i] = 0;
8034 									w += wopt[i - 1];
8035 									wopt[i - 1] = 0;
8036 								}
8037 								w++;
8038 							}
8039 						}
8040 					} else {
8041 						nm.push_back(-1);
8042 					}
8043 					if(htmp - hetmp > uh) {
8044 						uh = htmp - hetmp;
8045 					}
8046 					if(hetmp > dh) {
8047 						dh = hetmp;
8048 					}
8049 					par_prev = ips_n.wrap;
8050 					if(par_prev && i > 0 && nm[i] != MULTIPLICATION_SIGN_NONE) {
8051 						wpt[i - 1] -= ips.power_depth > 0 ? 2 : 3;
8052 						w -= ips.power_depth > 0 ? 2 : 3;
8053 					}
8054 				}
8055 				cairo_surface_t *flag_s = NULL;
8056 				gint flag_width = 0;
8057 				size_t flag_i = 0;
8058 				if(m.size() == 2 && ((m[0].isUnit() && m[0].unit()->isCurrency() && m[1].isNumber()) || (m[1].isUnit() && m[1].unit()->isCurrency() && m[0].isNumber()))) {
8059 					size_t i_unit = 0;
8060 					if(m[1].isUnit()) {
8061 						i_unit = 1;
8062 						flag_i = 1;
8063 					} else if(nm[1] == MULTIPLICATION_SIGN_NONE) {
8064 						flag_i = 1;
8065 					}
8066 					string imagefile = "/qalculate-gtk/flags/"; imagefile += m[i_unit].unit()->referenceName(); imagefile += ".png";
8067 					GdkPixbuf *pixbuf = NULL;
8068 					h = hpt[flag_i];
8069 					if(h < 48) pixbuf = gdk_pixbuf_new_from_resource_at_scale(imagefile.c_str(), -1, h / 3, TRUE, NULL);
8070 					else pixbuf = gdk_pixbuf_new_from_resource(imagefile.c_str(), NULL);
8071 					if(pixbuf) {
8072 						flag_s = gdk_cairo_surface_create_from_pixbuf(pixbuf, 1, NULL);
8073 						flag_width = cairo_image_surface_get_width(flag_s);
8074 						w += flag_width + 2;
8075 						g_object_unref(pixbuf);
8076 					}
8077 				}
8078 				central_point = dh;
8079 				h = dh + uh;
8080 				surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
8081 				cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
8082 				cr = cairo_create(surface);
8083 				w = 0;
8084 				for(size_t i = 0; i < surface_terms.size(); i++) {
8085 					if(!CALCULATOR->aborted()) {
8086 						gdk_cairo_set_source_rgba(cr, color);
8087 						if(i > 0) {
8088 							switch(nm[i]) {
8089 								case MULTIPLICATION_SIGN_SPACE: {
8090 									w += space_w;
8091 									break;
8092 								}
8093 								case MULTIPLICATION_SIGN_OPERATOR: {}
8094 								case MULTIPLICATION_SIGN_OPERATOR_SHORT: {
8095 									if(layout_altmul && m[i].isUnit_exp() && m[i - 1].isUnit_exp()) {
8096 										w += space_w / 2;
8097 										cairo_move_to(cr, w, uh - altmul_h / 2 - altmul_h % 2);
8098 										pango_cairo_show_layout(cr, layout_altmul);
8099 										w += altmul_w;
8100 										w += space_w / 2;
8101 									} else {
8102 										if(nm[i] == MULTIPLICATION_SIGN_OPERATOR_SHORT && m[i].isUnit_exp() && m[i - 1].isUnit_exp()) w += space_w / 2;
8103 										else if(nm[i] == MULTIPLICATION_SIGN_OPERATOR) w += space_w;
8104 										cairo_move_to(cr, w, uh - mul_h / 2 - mul_h % 2);
8105 										pango_cairo_show_layout(cr, layout_mul);
8106 										w += mul_w;
8107 										if(nm[i] == MULTIPLICATION_SIGN_OPERATOR_SHORT && m[i].isUnit_exp() && m[i - 1].isUnit_exp()) w += space_w / 2;
8108 										else if(nm[i] == MULTIPLICATION_SIGN_OPERATOR) w += space_w;
8109 									}
8110 									break;
8111 								}
8112 								default: {w++;}
8113 							}
8114 						}
8115 						w -= xpt[i];
8116 						cairo_set_source_surface(cr, surface_terms[i], w, uh - (hpt[i] - cpt[i]));
8117 						cairo_paint(cr);
8118 						w += wpt[i];
8119 						w -= wopt[i];
8120 						if(flag_s && i == 0 && flag_i == 0) {
8121 							gdk_cairo_set_source_rgba(cr, color);
8122 							cairo_set_source_surface(cr, flag_s, w + 2, uh - (hpt[i] - cpt[i]) + hpt[i] / 8);
8123 							cairo_paint(cr);
8124 							cairo_surface_destroy(flag_s);
8125 							flag_s = NULL;
8126 							w += flag_width + 2;
8127 						}
8128 					}
8129 					cairo_surface_destroy(surface_terms[i]);
8130 				}
8131 				if(flag_s) {
8132 					if(!CALCULATOR->aborted()) {
8133 						gdk_cairo_set_source_rgba(cr, color);
8134 						cairo_set_source_surface(cr, flag_s, w + 2, uh - (hpt.back() - cpt.back()) + hpt.back() / 8);
8135 						cairo_paint(cr);
8136 					}
8137 					cairo_surface_destroy(flag_s);
8138 				}
8139 				if(layout_mul) g_object_unref(layout_mul);
8140 				if(layout_altmul) g_object_unref(layout_altmul);
8141 				break;
8142 			}
8143 			case STRUCT_INVERSE: {}
8144 			case STRUCT_DIVISION: {
8145 
8146 				ips_n.depth++;
8147 				ips_n.division_depth++;
8148 
8149 				gint den_uh, den_w, den_dh, num_w, num_dh, num_uh, dh = 0, uh = 0, w = 0, h = 0, xtmp1, xtmp2, wotmp1, wotmp2;
8150 
8151 				bool flat = ips.division_depth > 0 || ips.power_depth > 0;
8152 				bool b_units = false;
8153 				if(po.place_units_separately) {
8154 					b_units = true;
8155 					size_t i = 0;
8156 					if(m.isDivision()) {
8157 						i = 1;
8158 					}
8159 					if(m[i].isMultiplication()) {
8160 						for(size_t i2 = 0; i2 < m[i].size(); i2++) {
8161 							if(!m[i][i2].isUnit_exp()) {
8162 								b_units = false;
8163 								break;
8164 							}
8165 						}
8166 					} else if(!m[i].isUnit_exp()) {
8167 						b_units = false;
8168 					}
8169 					if(b_units) {
8170 						ips_n.division_depth--;
8171 						flat = true;
8172 					}
8173 				}
8174 
8175 				cairo_surface_t *num_surface = NULL, *den_surface = NULL;
8176 				if(m.type() == STRUCT_DIVISION) {
8177 					ips_n.wrap = (!m[0].isDivision() || !flat || ips.division_depth > 0 || ips.power_depth > 0) && !b_units && m[0].needsParenthesis(po, ips_n, m, 1, flat, ips.power_depth > 0);
8178 					num_surface = draw_structure(m[0], po, caf, ips_n, &num_dh, scaledown, color, &xtmp1, &wotmp1);
8179 				} else {
8180 					MathStructure onestruct(1, 1);
8181 					ips_n.wrap = false;
8182 					num_surface = draw_structure(onestruct, po, caf, ips_n, &num_dh, scaledown, color, &xtmp1, &wotmp1);
8183 				}
8184 				if(!num_surface) {
8185 					return NULL;
8186 				}
8187 				num_w = cairo_image_surface_get_width(num_surface) / scalefactor;
8188 				h = cairo_image_surface_get_height(num_surface) / scalefactor;
8189 				num_uh = h - num_dh;
8190 				if(m.type() == STRUCT_DIVISION) {
8191 					ips_n.wrap = m[1].needsParenthesis(po, ips_n, m, 2, flat, ips.power_depth > 0);
8192 					den_surface = draw_structure(m[1], po, caf, ips_n, &den_dh, scaledown, color, &xtmp2, &wotmp2);
8193 				} else {
8194 					ips_n.wrap = m[0].needsParenthesis(po, ips_n, m, 2, flat, ips.power_depth > 0);
8195 					den_surface = draw_structure(m[0], po, caf, ips_n, &den_dh, scaledown, color, &xtmp2, &wotmp2);
8196 				}
8197 				if(!den_surface) {
8198 					cairo_surface_destroy(num_surface);
8199 					return NULL;
8200 				}
8201 				den_w = cairo_image_surface_get_width(den_surface) / scalefactor;
8202 				h = cairo_image_surface_get_height(den_surface) / scalefactor;
8203 				den_uh = h - den_dh;
8204 				h = 0;
8205 				if(flat) {
8206 					offset_x = xtmp1;
8207 					offset_w = wotmp2;
8208 					gint div_w, div_h, space_w = 0;
8209 					PangoLayout *layout_div = gtk_widget_create_pango_layout(resultview, NULL);
8210 					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))) {
8211 						PANGO_TTP(layout_div, SIGN_DIVISION);
8212 					} 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))) {
8213 						PANGO_TTP(layout_div, SIGN_DIVISION_SLASH);
8214 						PangoRectangle rect;
8215 						pango_layout_get_pixel_extents(layout_div, &rect, NULL);
8216 						if(rect.x < 0) space_w = -rect.x;
8217 					} else {
8218 						PANGO_TTP(layout_div, "/");
8219 					}
8220 					pango_layout_get_pixel_size(layout_div, &div_w, &div_h);
8221 					w = num_w + den_w - xtmp2 + space_w * 2 + div_w;
8222 					dh = num_dh; uh = num_uh;
8223 					if(den_dh > dh) dh = den_dh;
8224 					if(den_uh > uh) uh = den_uh;
8225 					if(div_h / 2 > dh) {
8226 						dh = div_h / 2;
8227 					}
8228 					if(div_h / 2 + div_h % 2 > uh) {
8229 						uh = div_h / 2 + div_h % 2;
8230 					}
8231 					h = uh + dh;
8232 					central_point = dh;
8233 					surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
8234 					cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
8235 					cr = cairo_create(surface);
8236 					gdk_cairo_set_source_rgba(cr, color);
8237 					w = 0;
8238 					cairo_set_source_surface(cr, num_surface, w, uh - num_uh);
8239 					cairo_paint(cr);
8240 					w += num_w;
8241 					w += space_w;
8242 					gdk_cairo_set_source_rgba(cr, color);
8243 					cairo_move_to(cr, w, uh - div_h / 2 - div_h % 2);
8244 					pango_cairo_show_layout(cr, layout_div);
8245 					w += div_w;
8246 					w += space_w;
8247 					w -= xtmp2;
8248 					cairo_set_source_surface(cr, den_surface, w, uh - den_uh);
8249 					cairo_paint(cr);
8250 					g_object_unref(layout_div);
8251 				} else {
8252 					num_w = num_w - xtmp1 - wotmp1;
8253 					den_w = den_w - xtmp2 - wotmp2;
8254 					int y1n;
8255 					get_image_blank_height(num_surface, &y1n, NULL);
8256 					y1n /= scalefactor;
8257 					num_uh -= y1n;
8258 					int y2d;
8259 					get_image_blank_height(den_surface, NULL, &y2d);
8260 					y2d = ::ceil((y2d + 1) / scalefactor);
8261 					den_dh -= (den_dh + den_uh - y2d);
8262 					gint wfr;
8263 					dh = den_dh + den_uh + 3;
8264 					uh = num_dh + num_uh + 3;
8265 					wfr = den_w;
8266 					if(num_w > wfr) wfr = num_w;
8267 					w = wfr;
8268 					h = uh + dh;
8269 					central_point = dh;
8270 					gint w_extra = ips.depth > 0 ? 4 : 1;
8271 					gint num_pos = (wfr - num_w) / 2;
8272 					gint den_pos = (wfr - den_w) / 2;
8273 					if(num_pos - xtmp1 < 0) offset_x = -(num_pos - xtmp1);
8274 					if(den_pos - xtmp2 < -offset_x) offset_x = -(den_pos - xtmp2);
8275 					if(num_pos + num_w + wotmp1 > w) offset_w = (num_pos + num_w + wotmp1) - w;
8276 					if((den_pos + den_w + wotmp2) - w > offset_w) offset_w = (den_pos + den_w + wotmp2) - w;
8277 					w += offset_x + offset_w;
8278 					wfr = w;
8279 					if(num_pos - (wotmp1 + xtmp1) > den_pos) num_pos = (wfr - num_w) / 2;
8280 					else num_pos += offset_x;
8281 					if(den_pos - (wotmp2 + xtmp2) > num_pos) den_pos = (wfr - den_w) / 2;
8282 					else den_pos += offset_x;
8283 					wfr += 2; w += 2; num_pos++; den_pos++;
8284 					w += w_extra * 2;
8285 					surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
8286 					cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
8287 					cr = cairo_create(surface);
8288 					gdk_cairo_set_source_rgba(cr, color);
8289 					w = w_extra;
8290 					cairo_set_source_surface(cr, num_surface, w + num_pos - xtmp1, -y1n);
8291 					cairo_paint(cr);
8292 					gdk_cairo_set_source_rgba(cr, color);
8293 					cairo_move_to(cr, w, uh);
8294 					cairo_line_to(cr, w + wfr, uh);
8295 					cairo_set_line_width(cr, 2);
8296 					cairo_stroke(cr);
8297 					cairo_set_source_surface(cr, den_surface, w + den_pos - xtmp2, uh + 3);
8298 					cairo_paint(cr);
8299 					offset_x = 0;
8300 					offset_w = 0;
8301 				}
8302 				if(num_surface) cairo_surface_destroy(num_surface);
8303 				if(den_surface) cairo_surface_destroy(den_surface);
8304 				break;
8305 			}
8306 			case STRUCT_POWER: {
8307 
8308 				ips_n.depth++;
8309 
8310 				gint base_w, base_h, exp_w, exp_h, w = 0, h = 0, ctmp = 0;
8311 				CALCULATE_SPACE_W
8312 				ips_n.wrap = SHOW_WITH_ROOT_SIGN(m[0]) || m[0].needsParenthesis(po, ips_n, m, 1, ips.division_depth > 0, false);
8313 				cairo_surface_t *surface_base = NULL;
8314 				if(m[0].isUnit() && po.use_unicode_signs && po.abbreviate_names && m[0].unit() == CALCULATOR->getDegUnit()) {
8315 					PrintOptions po2 = po;
8316 					po2.use_unicode_signs = false;
8317 					surface_base = draw_structure(m[0], po2, caf, ips_n, &central_point, scaledown, color, &offset_x);
8318 				} else {
8319 					surface_base = draw_structure(m[0], po, caf, ips_n, &central_point, scaledown, color, &offset_x);
8320 				}
8321 				if(!surface_base) {
8322 					return NULL;
8323 				}
8324 				base_w = cairo_image_surface_get_width(surface_base) / scalefactor;
8325 				base_h = cairo_image_surface_get_height(surface_base) / scalefactor;
8326 
8327 				ips_n.power_depth++;
8328 				ips_n.wrap = false;
8329 				PrintOptions po2 = po;
8330 				po2.show_ending_zeroes = false;
8331 				cairo_surface_t *surface_exp = draw_structure(m[1], po2, caf, ips_n, &ctmp, scaledown, color);
8332 				if(!surface_exp) {
8333 					cairo_surface_destroy(surface_base);
8334 					return NULL;
8335 				}
8336 				exp_w = cairo_image_surface_get_width(surface_exp) / scalefactor;
8337 				exp_h = cairo_image_surface_get_height(surface_exp) / scalefactor;
8338 				h = base_h;
8339 				w = base_w;
8340 				if(exp_h <= h) {
8341 					h += exp_h / 5;
8342 				} else {
8343 					h += exp_h - base_h / 1.5;
8344 				}
8345 				w += exp_w;
8346 
8347 				surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
8348 				cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
8349 				cr = cairo_create(surface);
8350 				gdk_cairo_set_source_rgba(cr, color);
8351 				w = 0;
8352 				cairo_set_source_surface(cr, surface_base, w, h - base_h);
8353 				cairo_paint(cr);
8354 				cairo_surface_destroy(surface_base);
8355 				w += base_w;
8356 				gdk_cairo_set_source_rgba(cr, color);
8357 				cairo_set_source_surface(cr, surface_exp, w, 0);
8358 				cairo_paint(cr);
8359 				cairo_surface_destroy(surface_exp);
8360 
8361 				break;
8362 			}
8363 			case STRUCT_LOGICAL_AND: {
8364 				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]) {
8365 					ips_n.depth++;
8366 
8367 					vector<cairo_surface_t*> surface_terms;
8368 					vector<gint> hpt, wpt, cpt, xpt;
8369 					gint sign_w, sign_h, sign2_w, sign2_h, wtmp, htmp, hetmp = 0, w = 0, h = 0, dh = 0, uh = 0, xtmp = 0;
8370 					CALCULATE_SPACE_W
8371 
8372 					hetmp = 0;
8373 					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);
8374 					surface_terms.push_back(draw_structure(m[0][1], po, caf, ips_n, &hetmp, scaledown, color));
8375 					if(CALCULATOR->aborted()) {
8376 						return NULL;
8377 					}
8378 					wtmp = cairo_image_surface_get_width(surface_terms[0]) / scalefactor;
8379 					htmp = cairo_image_surface_get_height(surface_terms[0]) / scalefactor;
8380 					hpt.push_back(htmp);
8381 					cpt.push_back(hetmp);
8382 					wpt.push_back(wtmp);
8383 					w += wtmp;
8384 					if(htmp - hetmp > uh) {
8385 						uh = htmp - hetmp;
8386 					}
8387 					if(hetmp > dh) {
8388 						dh = hetmp;
8389 					}
8390 					hetmp = 0;
8391 					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);
8392 					surface_terms.push_back(draw_structure(m[0][0], po, caf, ips_n, &hetmp, scaledown, color, &offset_x, NULL));
8393 					if(CALCULATOR->aborted()) {
8394 						cairo_surface_destroy(surface_terms[0]);
8395 						return NULL;
8396 					}
8397 					wtmp = cairo_image_surface_get_width(surface_terms[1]) / scalefactor;
8398 					htmp = cairo_image_surface_get_height(surface_terms[1]) / scalefactor;
8399 					hpt.push_back(htmp);
8400 					cpt.push_back(hetmp);
8401 					wpt.push_back(wtmp);
8402 					xpt.push_back(0);
8403 					w += wtmp;
8404 					if(htmp - hetmp > uh) {
8405 						uh = htmp - hetmp;
8406 					}
8407 					if(hetmp > dh) {
8408 						dh = hetmp;
8409 					}
8410 					hetmp = 0;
8411 					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);
8412 					surface_terms.push_back(draw_structure(m[1][1], po, caf, ips_n, &hetmp, scaledown, color, &xtmp, &offset_w));
8413 					if(CALCULATOR->aborted()) {
8414 						cairo_surface_destroy(surface_terms[0]);
8415 						cairo_surface_destroy(surface_terms[1]);
8416 						return NULL;
8417 					}
8418 					wtmp = cairo_image_surface_get_width(surface_terms[2]) / scalefactor;
8419 					htmp = cairo_image_surface_get_height(surface_terms[2]) / scalefactor;
8420 					hpt.push_back(htmp);
8421 					cpt.push_back(hetmp);
8422 					wpt.push_back(wtmp);
8423 					xpt.push_back(xtmp);
8424 					w -= xtmp;
8425 					w += wtmp;
8426 					if(htmp - hetmp > uh) {
8427 						uh = htmp - hetmp;
8428 					}
8429 					if(hetmp > dh) {
8430 						dh = hetmp;
8431 					}
8432 
8433 					PangoLayout *layout_sign = gtk_widget_create_pango_layout(resultview, NULL);
8434 					string str;
8435 					TTBP(str);
8436 					switch(m[0].comparisonType()) {
8437 						case COMPARISON_LESS: {
8438 							str += "&gt;";
8439 							break;
8440 						}
8441 						case COMPARISON_GREATER: {
8442 							str += "&lt;";
8443 							break;
8444 						}
8445 						case COMPARISON_EQUALS_LESS: {
8446 							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))) {
8447 								str += SIGN_GREATER_OR_EQUAL;
8448 							} else {
8449 								str += "&gt;=";
8450 							}
8451 							break;
8452 						}
8453 						case COMPARISON_EQUALS_GREATER: {
8454 							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))) {
8455 								str += SIGN_LESS_OR_EQUAL;
8456 							} else {
8457 								str += "&lt;=";
8458 							}
8459 							break;
8460 						}
8461 						default: {}
8462 					}
8463 					TTE(str);
8464 					pango_layout_set_markup(layout_sign, str.c_str(), -1);
8465 					pango_layout_get_pixel_size(layout_sign, &sign_w, &sign_h);
8466 					if(sign_h / 2 > dh) {
8467 						dh = sign_h / 2;
8468 					}
8469 					if(sign_h / 2 + sign_h % 2 > uh) {
8470 						uh = sign_h / 2 + sign_h % 2;
8471 					}
8472 					w += sign_w;
8473 
8474 					PangoLayout *layout_sign2 = gtk_widget_create_pango_layout(resultview, NULL);
8475 					str = "";
8476 					TTBP(str);
8477 					switch(m[1].comparisonType()) {
8478 						case COMPARISON_GREATER: {
8479 							str += "&gt;";
8480 							break;
8481 						}
8482 						case COMPARISON_LESS: {
8483 							str += "&lt;";
8484 							break;
8485 						}
8486 						case COMPARISON_EQUALS_GREATER: {
8487 							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))) {
8488 								str += SIGN_GREATER_OR_EQUAL;
8489 							} else {
8490 								str += "&gt;=";
8491 							}
8492 							break;
8493 						}
8494 						case COMPARISON_EQUALS_LESS: {
8495 							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))) {
8496 								str += SIGN_LESS_OR_EQUAL;
8497 							} else {
8498 								str += "&lt;=";
8499 							}
8500 							break;
8501 						}
8502 						default: {}
8503 					}
8504 					TTE(str);
8505 					pango_layout_set_markup(layout_sign2, str.c_str(), -1);
8506 					pango_layout_get_pixel_size(layout_sign2, &sign2_w, &sign2_h);
8507 					if(sign2_h / 2 > dh) {
8508 						dh = sign2_h / 2;
8509 					}
8510 					if(sign2_h / 2 + sign2_h % 2 > uh) {
8511 						uh = sign2_h / 2 + sign2_h % 2;
8512 					}
8513 					w += sign2_w;
8514 
8515 
8516 					w += space_w * (surface_terms.size() - 1) * 2;
8517 
8518 					central_point = dh;
8519 					h = dh + uh;
8520 					surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
8521 					cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
8522 					cr = cairo_create(surface);
8523 					w = 0;
8524 					for(size_t i = 0; i < surface_terms.size(); i++) {
8525 						gdk_cairo_set_source_rgba(cr, color);
8526 						if(i > 0) {
8527 							w += space_w;
8528 							if(i == 1) {
8529 								cairo_move_to(cr, w, uh - sign_h / 2 - sign_h % 2);
8530 								pango_cairo_show_layout(cr, layout_sign);
8531 								w += sign_w;
8532 							} else {
8533 								cairo_move_to(cr, w, uh - sign2_h / 2 - sign2_h % 2);
8534 								pango_cairo_show_layout(cr, layout_sign2);
8535 								w += sign2_w;
8536 							}
8537 							w += space_w;
8538 						}
8539 						w -= xpt[i];
8540 						cairo_set_source_surface(cr, surface_terms[i], w, uh - (hpt[i] - cpt[i]));
8541 						cairo_paint(cr);
8542 						w += wpt[i];
8543 						cairo_surface_destroy(surface_terms[i]);
8544 					}
8545 					g_object_unref(layout_sign);
8546 					g_object_unref(layout_sign2);
8547 					break;
8548 				}
8549 			}
8550 			case STRUCT_COMPARISON: {}
8551 			case STRUCT_LOGICAL_XOR: {}
8552 			case STRUCT_LOGICAL_OR: {}
8553 			case STRUCT_BITWISE_AND: {}
8554 			case STRUCT_BITWISE_XOR: {}
8555 			case STRUCT_BITWISE_OR: {
8556 
8557 				ips_n.depth++;
8558 
8559 				vector<cairo_surface_t*> surface_terms;
8560 				vector<gint> hpt, wpt, cpt, xpt;
8561 				gint sign_w, sign_h, wtmp, htmp, hetmp = 0, w = 0, h = 0, dh = 0, uh = 0, xtmp = 0, wotmp = 0;
8562 				CALCULATE_SPACE_W
8563 
8564 				for(size_t i = 0; i < m.size(); i++) {
8565 					hetmp = 0;
8566 					ips_n.wrap = m[i].needsParenthesis(po, ips_n, m, i + 1, ips.division_depth > 0 || ips.power_depth > 0, ips.power_depth > 0);
8567 					surface_terms.push_back(draw_structure(m[i], po, caf, ips_n, &hetmp, scaledown, color, &xtmp, &wotmp));
8568 					if(CALCULATOR->aborted()) {
8569 						for(size_t i = 0; i < surface_terms.size(); i++) {
8570 							if(surface_terms[i]) cairo_surface_destroy(surface_terms[i]);
8571 						}
8572 						return NULL;
8573 					}
8574 					if(i == 0) {
8575 						offset_x = xtmp;
8576 						xtmp = 0;
8577 					} else if(i == m.size() - 1) {
8578 						offset_w = wotmp;
8579 						wotmp = 0;
8580 					}
8581 					wtmp = cairo_image_surface_get_width(surface_terms[i]) / scalefactor;
8582 					htmp = cairo_image_surface_get_height(surface_terms[i]) / scalefactor;
8583 					hpt.push_back(htmp);
8584 					cpt.push_back(hetmp);
8585 					wpt.push_back(wtmp);
8586 					xpt.push_back(xtmp);
8587 					w -= xtmp;
8588 					w += wtmp;
8589 					if(htmp - hetmp > uh) {
8590 						uh = htmp - hetmp;
8591 					}
8592 					if(hetmp > dh) {
8593 						dh = hetmp;
8594 					}
8595 				}
8596 
8597 				PangoLayout *layout_sign = gtk_widget_create_pango_layout(resultview, NULL);
8598 				string str;
8599 				TTBP(str);
8600 				if(m.type() == STRUCT_COMPARISON) {
8601 					switch(m.comparisonType()) {
8602 						case COMPARISON_EQUALS: {
8603 							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))) {
8604 								str += SIGN_ALMOST_EQUAL;
8605 							} else {
8606 								str += "=";
8607 							}
8608 							break;
8609 						}
8610 						case COMPARISON_NOT_EQUALS: {
8611 							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))) {
8612 								str += SIGN_NOT_EQUAL;
8613 							} else {
8614 								str += "!=";
8615 							}
8616 							break;
8617 						}
8618 						case COMPARISON_GREATER: {
8619 							str += "&gt;";
8620 							break;
8621 						}
8622 						case COMPARISON_LESS: {
8623 							str += "&lt;";
8624 							break;
8625 						}
8626 						case COMPARISON_EQUALS_GREATER: {
8627 							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))) {
8628 								str += SIGN_GREATER_OR_EQUAL;
8629 							} else {
8630 								str += "&gt;=";
8631 							}
8632 							break;
8633 						}
8634 						case COMPARISON_EQUALS_LESS: {
8635 							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))) {
8636 								str += SIGN_LESS_OR_EQUAL;
8637 							} else {
8638 								str += "&lt;=";
8639 							}
8640 							break;
8641 						}
8642 					}
8643 				} else if(m.type() == STRUCT_LOGICAL_AND) {
8644 					if(po.spell_out_logical_operators) str += _("and");
8645 					else str += "&amp;&amp;";
8646 				} else if(m.type() == STRUCT_LOGICAL_OR) {
8647 					if(po.spell_out_logical_operators) str += _("or");
8648 					else str += "||";
8649 				} else if(m.type() == STRUCT_LOGICAL_XOR) {
8650 					str += "xor";
8651 				} else if(m.type() == STRUCT_BITWISE_AND) {
8652 					str += "&amp;";
8653 				} else if(m.type() == STRUCT_BITWISE_OR) {
8654 					str += "|";
8655 				} else if(m.type() == STRUCT_BITWISE_XOR) {
8656 					str += "xor";
8657 				}
8658 
8659 				TTE(str);
8660 				pango_layout_set_markup(layout_sign, str.c_str(), -1);
8661 				pango_layout_get_pixel_size(layout_sign, &sign_w, &sign_h);
8662 				if(sign_h / 2 > dh) {
8663 					dh = sign_h / 2;
8664 				}
8665 				if(sign_h / 2 + sign_h % 2 > uh) {
8666 					uh = sign_h / 2 + sign_h % 2;
8667 				}
8668 				w += sign_w * (m.size() - 1);
8669 
8670 				w += space_w * (surface_terms.size() - 1) * 2;
8671 
8672 				central_point = dh;
8673 				h = dh + uh;
8674 				surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
8675 				cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
8676 				cr = cairo_create(surface);
8677 				w = 0;
8678 				for(size_t i = 0; i < surface_terms.size(); i++) {
8679 					if(!CALCULATOR->aborted()) {
8680 						gdk_cairo_set_source_rgba(cr, color);
8681 						if(i > 0) {
8682 							w += space_w;
8683 							cairo_move_to(cr, w, uh - sign_h / 2 - sign_h % 2);
8684 							pango_cairo_show_layout(cr, layout_sign);
8685 							w += sign_w;
8686 							w += space_w;
8687 						}
8688 						w -= xpt[i];
8689 						cairo_set_source_surface(cr, surface_terms[i], w, uh - (hpt[i] - cpt[i]));
8690 						cairo_paint(cr);
8691 						w += wpt[i];
8692 					}
8693 					cairo_surface_destroy(surface_terms[i]);
8694 				}
8695 				g_object_unref(layout_sign);
8696 				break;
8697 			}
8698 			case STRUCT_LOGICAL_NOT: {}
8699 			case STRUCT_BITWISE_NOT: {
8700 
8701 				ips_n.depth++;
8702 
8703 				gint not_w, not_h, uh, dh, h, w, ctmp, htmp, wtmp, hpa, cpa, xtmp;
8704 				//gint wpa;
8705 
8706 				PangoLayout *layout_not = gtk_widget_create_pango_layout(resultview, NULL);
8707 
8708 				if(m.type() == STRUCT_LOGICAL_NOT) {
8709 					PANGO_TTP(layout_not, "!");
8710 				} else {
8711 					if(po.use_unicode_signs && (!po.can_display_unicode_string_function || (*po.can_display_unicode_string_function) ("¬", po.can_display_unicode_string_arg))) {
8712 						PANGO_TTP(layout_not, "¬");
8713 					} else {
8714 						PANGO_TTP(layout_not, "~");
8715 					}
8716 				}
8717 				pango_layout_get_pixel_size(layout_not, &not_w, &not_h);
8718 
8719 				w = not_w + 1;
8720 				uh = not_h / 2 + not_h % 2;
8721 				dh = not_h / 2;
8722 
8723 				ips_n.wrap = m[0].needsParenthesis(po, ips_n, m, 1, ips.division_depth > 0 || ips.power_depth > 0, ips.power_depth > 0);
8724 				cairo_surface_t *surface_arg = draw_structure(m[0], po, caf, ips_n, &ctmp, scaledown, color, &xtmp, &offset_w);
8725 				if(!surface_arg) {
8726 					g_object_unref(layout_not);
8727 					return NULL;
8728 				}
8729 				wtmp = cairo_image_surface_get_width(surface_arg) / scalefactor;
8730 				htmp = cairo_image_surface_get_height(surface_arg) / scalefactor;
8731 				hpa = htmp;
8732 				cpa = ctmp;
8733 				//wpa = wtmp;
8734 				w -= xtmp;
8735 				w += wtmp;
8736 				if(ctmp > dh) {
8737 					dh = ctmp;
8738 				}
8739 				if(htmp - ctmp > uh) {
8740 					uh = htmp - ctmp;
8741 				}
8742 
8743 				h = uh + dh;
8744 				central_point = dh;
8745 
8746 				surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
8747 				cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
8748 				cr = cairo_create(surface);
8749 
8750 				w = 0;
8751 				gdk_cairo_set_source_rgba(cr, color);
8752 				cairo_move_to(cr, w, uh - not_h / 2 - not_h % 2);
8753 				pango_cairo_show_layout(cr, layout_not);
8754 				w += not_w + 1 - xtmp;
8755 				cairo_set_source_surface(cr, surface_arg, w, uh - (hpa - cpa));
8756 				cairo_paint(cr);
8757 				cairo_surface_destroy(surface_arg);
8758 
8759 				g_object_unref(layout_not);
8760 				break;
8761 			}
8762 			case STRUCT_VECTOR: {
8763 
8764 				ips_n.depth++;
8765 
8766 				if(m.isMatrix()) {
8767 					if(m[0].size() == 0) {
8768 						PangoLayout *layout = gtk_widget_create_pango_layout(resultview, NULL);
8769 						string str;
8770 						TTBP(str)
8771 						str += "[ ]";
8772 						TTE(str)
8773 						pango_layout_set_markup(layout, str.c_str(), -1);
8774 						pango_layout_get_pixel_size(layout, &w, &h);
8775 						w += 1;
8776 						central_point = h / 2;
8777 						surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
8778 						cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
8779 						cr = cairo_create(surface);
8780 						gdk_cairo_set_source_rgba(cr, color);
8781 						cairo_move_to(cr, 1, 0);
8782 						pango_cairo_show_layout(cr, layout);
8783 						g_object_unref(layout);
8784 						break;
8785 					}
8786 					gint wtmp, htmp, ctmp = 0, w = 0, h = 0;
8787 					CALCULATE_SPACE_W
8788 					vector<gint> col_w;
8789 					vector<gint> row_h;
8790 					vector<gint> row_uh;
8791 					vector<gint> row_dh;
8792 					vector<vector<gint> > element_w;
8793 					vector<vector<gint> > element_h;
8794 					vector<vector<gint> > element_c;
8795 					vector<vector<cairo_surface_t*> > surface_elements;
8796 					element_w.resize(m.size());
8797 					element_h.resize(m.size());
8798 					element_c.resize(m.size());
8799 					surface_elements.resize(m.size());
8800 					PangoLayout *layout_comma = gtk_widget_create_pango_layout(resultview, NULL);
8801 					string str;
8802 					gint comma_w = 0, comma_h = 0;
8803 					TTP(str, po.comma())
8804 					pango_layout_set_markup(layout_comma, str.c_str(), -1);
8805 					pango_layout_get_pixel_size(layout_comma, &comma_w, &comma_h);
8806 					for(size_t index_r = 0; index_r < m.size(); index_r++) {
8807 						for(size_t index_c = 0; index_c < m[index_r].size(); index_c++) {
8808 							ctmp = 0;
8809 							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);
8810 							surface_elements[index_r].push_back(draw_structure(m[index_r][index_c], po, caf, ips_n, &ctmp, scaledown, color));
8811 							if(CALCULATOR->aborted()) {
8812 								break;
8813 							}
8814 							wtmp = cairo_image_surface_get_width(surface_elements[index_r][index_c]) / scalefactor;
8815 							htmp = cairo_image_surface_get_height(surface_elements[index_r][index_c]) / scalefactor;
8816 							element_w[index_r].push_back(wtmp);
8817 							element_h[index_r].push_back(htmp);
8818 							element_c[index_r].push_back(ctmp);
8819 							if(index_r == 0) {
8820 								col_w.push_back(wtmp);
8821 							} else if(wtmp > col_w[index_c]) {
8822 								col_w[index_c] = wtmp;
8823 							}
8824 							if(index_c == 0) {
8825 								row_uh.push_back(htmp - ctmp);
8826 								row_dh.push_back(ctmp);
8827 							} else {
8828 								if(ctmp > row_dh[index_r]) {
8829 									row_dh[index_r] = ctmp;
8830 								}
8831 								if(htmp - ctmp > row_uh[index_r]) {
8832 									row_uh[index_r] = htmp - ctmp;
8833 								}
8834 							}
8835 						}
8836 						if(CALCULATOR->aborted()) {
8837 							break;
8838 						}
8839 						row_h.push_back(row_uh[index_r] + row_dh[index_r]);
8840 						h += row_h[index_r];
8841 						if(index_r != 0) {
8842 							h += 4;
8843 						}
8844 					}
8845 					h += 4;
8846 					for(size_t i = 0; i < col_w.size(); i++) {
8847 						w += col_w[i];
8848 						if(i != 0) {
8849 							w += space_w * 2;
8850 						}
8851 					}
8852 
8853 					gint wlr, wll;
8854 					wll = 10;
8855 					wlr = 10;
8856 
8857 					w += wlr + 1;
8858 					w += wll + 3;
8859 					central_point = h / 2;
8860 					surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
8861 					cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
8862 					cr = cairo_create(surface);
8863 					gdk_cairo_set_source_rgba(cr, color);
8864 					w = 1;
8865 					cairo_move_to(cr, w, 1);
8866 					cairo_line_to(cr, w, h - 1);
8867 					cairo_move_to(cr, w, 1);
8868 					cairo_line_to(cr, w + 7, 1);
8869 					cairo_move_to(cr, w, h - 1);
8870 					cairo_line_to(cr, w + 7, h - 1);
8871 					cairo_set_line_width(cr, 2);
8872 					cairo_stroke(cr);
8873 					h = 2;
8874 					for(size_t index_r = 0; index_r < surface_elements.size(); index_r++) {
8875 						if(!CALCULATOR->aborted()) {
8876 							gdk_cairo_set_source_rgba(cr, color);
8877 							w = wll + 1;
8878 						}
8879 						for(size_t index_c = 0; index_c < surface_elements[index_r].size(); index_c++) {
8880 							if(!CALCULATOR->aborted()) {
8881 								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]));
8882 								cairo_paint(cr);
8883 								w += col_w[index_c];
8884 								if(index_c != m[index_r].size() - 1) {
8885 									w += space_w * 2;
8886 								}
8887 							}
8888 							if(surface_elements[index_r][index_c]) {
8889 								cairo_surface_destroy(surface_elements[index_r][index_c]);
8890 							}
8891 						}
8892 						if(!CALCULATOR->aborted()) {
8893 							h += row_h[index_r];
8894 							h += 4;
8895 						}
8896 					}
8897 					h -= 4;
8898 					h += 2;
8899 					w += wll - 7;
8900 					gdk_cairo_set_source_rgba(cr, color);
8901 					cairo_move_to(cr, w + 7, 1);
8902 					cairo_line_to(cr, w + 7, h - 1);
8903 					cairo_move_to(cr, w, 1);
8904 					cairo_line_to(cr, w + 7, 1);
8905 					cairo_move_to(cr, w, h - 1);
8906 					cairo_line_to(cr, w + 7, h - 1);
8907 					cairo_set_line_width(cr, 2);
8908 					cairo_stroke(cr);
8909 					g_object_unref(layout_comma);
8910 					break;
8911 				}
8912 
8913 				gint comma_w, comma_h, uh = 0, dh = 0, h = 0, w = 0, ctmp, htmp, wtmp, arc_w, arc_h, xtmp;
8914 				vector<cairo_surface_t*> surface_args;
8915 				vector<gint> hpa, cpa, wpa, xpa;
8916 
8917 				CALCULATE_SPACE_W
8918 				PangoLayout *layout_comma = gtk_widget_create_pango_layout(resultview, NULL);
8919 				string str, func_str;
8920 				TTP(str, CALCULATOR->getComma())
8921 				pango_layout_set_markup(layout_comma, str.c_str(), -1);
8922 				pango_layout_get_pixel_size(layout_comma, &comma_w, &comma_h);
8923 
8924 				if(m.size() == 0) {
8925 					PangoLayout *layout_one = gtk_widget_create_pango_layout(resultview, NULL);
8926 					TTP(str, "1")
8927 					pango_layout_set_markup(layout_one, str.c_str(), -1);
8928 					pango_layout_get_pixel_size(layout_one, &w, &h);
8929 					uh = h / 2 + h % 2;
8930 					dh = h / 2;
8931 					w = 2;
8932 					g_object_unref(layout_one);
8933 				}
8934 				for(size_t index = 0; index < m.size(); index++) {
8935 					ips_n.wrap = m[index].needsParenthesis(po, ips_n, m, index + 1, ips.division_depth > 0 || ips.power_depth > 0, ips.power_depth > 0);
8936 					surface_args.push_back(draw_structure(m[index], po, caf, ips_n, &ctmp, scaledown, color, &xtmp));
8937 					if(CALCULATOR->aborted()) {
8938 						for(size_t i = 0; i < surface_args.size(); i++) {
8939 							if(surface_args[i]) cairo_surface_destroy(surface_args[i]);
8940 						}
8941 						g_object_unref(layout_comma);
8942 						return NULL;
8943 					}
8944 					if(index == 0) xtmp = 0;
8945 					wtmp = cairo_image_surface_get_width(surface_args[index]) / scalefactor;
8946 					htmp = cairo_image_surface_get_height(surface_args[index]) / scalefactor;
8947 					hpa.push_back(htmp);
8948 					cpa.push_back(ctmp);
8949 					wpa.push_back(wtmp);
8950 					xpa.push_back(xtmp);
8951 					if(index > 0) {
8952 						w += comma_w;
8953 						w += space_w;
8954 					}
8955 					w += wtmp;
8956 					w -= xtmp;
8957 					if(ctmp > dh) {
8958 						dh = ctmp;
8959 					}
8960 					if(htmp - ctmp > uh) {
8961 						uh = htmp - ctmp;
8962 					}
8963 				}
8964 
8965 				if(dh > uh) uh = dh;
8966 				else if(uh > dh) dh = uh;
8967 				h = uh + dh;
8968 				central_point = dh;
8969 				arc_h = h;
8970 				arc_w = PAR_WIDTH;
8971 				w += arc_w * 2;
8972 				w += 1;
8973 				if(ips.depth > 0) w += ips.power_depth > 0 ? 2 : 3;
8974 
8975 				int x1 = 0, x2 = 0;
8976 				if(surface_args.size() == 1) {
8977 					get_image_blank_width(surface_args[0], &x1, &x2);
8978 					x1 /= scalefactor;
8979 					x1++;
8980 					x2 = ::ceil(x2 / scalefactor);
8981 					w -= wpa[0];
8982 					wpa[0] = x2 - x1;
8983 					w += wpa[0];
8984 				} else if(surface_args.size() > 1) {
8985 					get_image_blank_width(surface_args[0], &x1, NULL);
8986 					x1 /= scalefactor;
8987 					x1++;
8988 					w -= x1;
8989 					wpa[0] -= x1;
8990 					int i_last = surface_args.size() - 1;
8991 					get_image_blank_width(surface_args[i_last], NULL, &x2);
8992 					x2 = ::ceil(x2 / scalefactor);
8993 					w -= wpa[i_last] - x2;
8994 					wpa[i_last] -= wpa[i_last] - x2;
8995 				}
8996 
8997 				surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
8998 				cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
8999 				cr = cairo_create(surface);
9000 
9001 				if(ips.depth > 0) w = ips.power_depth > 0 ? 2 : 3;
9002 				else w = 0;
9003 				cairo_set_source_surface(cr, get_left_parenthesis(arc_w, arc_h, scaledown, color), w, (h - arc_h) / 2);
9004 				cairo_paint(cr);
9005 				w += arc_w;
9006 				if(m.size() == 0) w += 2;
9007 				for(size_t index = 0; index < surface_args.size(); index++) {
9008 					if(!CALCULATOR->aborted()) {
9009 						gdk_cairo_set_source_rgba(cr, color);
9010 						if(index > 0) {
9011 							cairo_move_to(cr, w, uh - comma_h / 2 - comma_h % 2);
9012 							pango_cairo_show_layout(cr, layout_comma);
9013 							w += comma_w;
9014 							w += space_w;
9015 						}
9016 						w -= xpa[index];
9017 						cairo_set_source_surface(cr, surface_args[index], index == 0 ? w - x1 : w, uh - (hpa[index] - cpa[index]));
9018 						cairo_paint(cr);
9019 						w += wpa[index];
9020 					}
9021 					cairo_surface_destroy(surface_args[index]);
9022 				}
9023 				cairo_set_source_surface(cr, get_right_parenthesis(arc_w, arc_h, scaledown, color), w, (h - arc_h) / 2);
9024 				cairo_paint(cr);
9025 
9026 				g_object_unref(layout_comma);
9027 
9028 				break;
9029 			}
9030 			case STRUCT_UNIT: {
9031 
9032 				string str, str2;
9033 				TTBP(str);
9034 
9035 				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);
9036 
9037 				if(m.prefix()) {
9038 					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);
9039 				}
9040 				if(ename->suffix && ename->name.length() > 1) {
9041 					size_t i = ename->name.rfind('_');
9042 					bool b = i == string::npos || i == ename->name.length() - 1 || i == 0;
9043 					size_t i2 = 1;
9044 					if(b) {
9045 						if(is_in(NUMBERS, ename->name[ename->name.length() - 1])) {
9046 							while(ename->name.length() > i2 + 1 && is_in(NUMBERS, ename->name[ename->name.length() - 1 - i2])) {
9047 								i2++;
9048 							}
9049 						}
9050 						str += ename->name.substr(0, ename->name.length() - i2);
9051 					} else {
9052 						str += ename->name.substr(0, i);
9053 					}
9054 					if(b || i + 5 != ename->name.length() || ename->name.substr(ename->name.length() - 4, 4) != "unit") {
9055 						TTBP_SMALL(str);
9056 						str += "<sub>";
9057 						if(b) str += ename->name.substr(ename->name.length() - i2, i2);
9058 						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);}
9059 						else str += ename->name.substr(i + 1, ename->name.length() - (i + 1));
9060 						str += "</sub>";
9061 						TTE(str);
9062 					}
9063 				} else {
9064 					str += ename->name;
9065 				}
9066 				gsub("_", " ", str);
9067 
9068 				TTE(str);
9069 				PangoLayout *layout = gtk_widget_create_pango_layout(resultview, NULL);
9070 				pango_layout_set_markup(layout, str.c_str(), -1);
9071 				PangoRectangle rect, lrect;
9072 				pango_layout_get_pixel_extents(layout, &rect, &lrect);
9073 				w = lrect.width;
9074 				h = lrect.height;
9075 				if(rect.x < 0) {
9076 					w -= rect.x;
9077 					if(rect.width > w) {
9078 						offset_w = rect.width - w;
9079 						w = rect.width;
9080 					}
9081 					offset_x = -rect.x;
9082 				} else {
9083 					if(rect.width + rect.x > w) {
9084 						offset_w = rect.width + rect.x - w;
9085 						w = rect.width + rect.x;
9086 					}
9087 				}
9088 				central_point = h / 2;
9089 				if(rect.y < 0) h -= rect.y;
9090 				surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
9091 				cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
9092 				cr = cairo_create(surface);
9093 				gdk_cairo_set_source_rgba(cr, color);
9094 				cairo_move_to(cr, offset_x, rect.y < 0 ? -rect.y : 0);
9095 				pango_cairo_show_layout(cr, layout);
9096 				g_object_unref(layout);
9097 				break;
9098 			}
9099 			case STRUCT_VARIABLE: {
9100 
9101 				PangoLayout *layout = gtk_widget_create_pango_layout(resultview, NULL);
9102 				string str;
9103 
9104 				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);
9105 
9106 				bool cursive = m.variable() != CALCULATOR->v_i && ename->name != "%" && ename->name != "‰" && ename->name != "‱" && m.variable()->referenceName() != "true" && m.variable()->referenceName() != "false";
9107 				if(cursive) str = "<i>";
9108 				TTBP(str);
9109 
9110 				if(ename->suffix && ename->name.length() > 1) {
9111 					size_t i = ename->name.rfind('_');
9112 					bool b = i == string::npos || i == ename->name.length() - 1 || i == 0;
9113 					size_t i2 = 1;
9114 					if(b) {
9115 						if(is_in(NUMBERS, ename->name[ename->name.length() - 1])) {
9116 							while(ename->name.length() > i2 + 1 && is_in(NUMBERS, ename->name[ename->name.length() - 1 - i2])) {
9117 								i2++;
9118 							}
9119 						}
9120 						str += ename->name.substr(0, ename->name.length() - i2);
9121 					} else {
9122 						str += ename->name.substr(0, i);
9123 					}
9124 					if(!b || i + 9 != ename->name.length() || ename->name.substr(ename->name.length() - 8, 8) != "constant") {
9125 						TTBP_SMALL(str);
9126 						str += "<sub>";
9127 						if(b) str += ename->name.substr(ename->name.length() - i2, i2);
9128 						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);
9129 						else str += ename->name.substr(i + 1, ename->name.length() - (i + 1));
9130 						str += "</sub>";
9131 						TTE(str);
9132 					}
9133 				} else {
9134 					str += ename->name;
9135 				}
9136 				gsub("_", " ", str);
9137 
9138 				TTE(str);
9139 				if(cursive) str += "</i>";
9140 
9141 				pango_layout_set_markup(layout, str.c_str(), -1);
9142 				PangoRectangle rect, lrect;
9143 				pango_layout_get_pixel_extents(layout, &rect, &lrect);
9144 				w = lrect.width;
9145 				h = lrect.height;
9146 				if(rect.x < 0) {
9147 					w -= rect.x;
9148 					if(rect.width > w) {
9149 						offset_w = rect.width - w;
9150 						w = rect.width;
9151 					}
9152 					offset_x = -rect.x;
9153 				} else {
9154 					if(rect.width + rect.x > w) {
9155 						offset_w = rect.width + rect.x - w;
9156 						w = rect.width + rect.x;
9157 					}
9158 				}
9159 				if(m.variable() == CALCULATOR->v_i) w += 1;
9160 				central_point = h / 2;
9161 				if(rect.y < 0) h -= rect.y;
9162 				surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
9163 				cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
9164 				cr = cairo_create(surface);
9165 				gdk_cairo_set_source_rgba(cr, color);
9166 				cairo_move_to(cr, offset_x, rect.y < 0 ? -rect.y : 0);
9167 				pango_cairo_show_layout(cr, layout);
9168 				g_object_unref(layout);
9169 				break;
9170 			}
9171 			case STRUCT_FUNCTION: {
9172 
9173 				if(m.function() == CALCULATOR->f_uncertainty && m.size() == 3 && m[2].isZero()) {
9174 					ips_n.depth++;
9175 					gint unc_uh, unc_w, unc_dh, mid_w, mid_dh, mid_uh, dh = 0, uh = 0, w = 0, h = 0;
9176 					cairo_surface_t *mid_surface = NULL, *unc_surface = NULL;
9177 					ips_n.wrap = !m[0].isNumber();
9178 					PrintOptions po2 = po;
9179 					po2.show_ending_zeroes = false;
9180 					po2.number_fraction_format = FRACTION_DECIMAL;
9181 					mid_surface = draw_structure(m[0], po2, caf, ips_n, &mid_dh, scaledown, color, &offset_x, NULL);
9182 					if(!mid_surface) {
9183 						return NULL;
9184 					}
9185 					mid_w = cairo_image_surface_get_width(mid_surface) / scalefactor;
9186 					h = cairo_image_surface_get_height(mid_surface) / scalefactor;
9187 					mid_uh = h - mid_dh;
9188 					ips_n.wrap = !m[1].isNumber();
9189 					unc_surface = draw_structure(m[1], po2, caf, ips_n, &unc_dh, scaledown, color, NULL, &offset_w);
9190 					unc_w = cairo_image_surface_get_width(unc_surface) / scalefactor;
9191 					h = cairo_image_surface_get_height(unc_surface) / scalefactor;
9192 					unc_uh = h - unc_dh;
9193 					h = 0;
9194 					gint pm_w, pm_h;
9195 					PangoLayout *layout_pm = gtk_widget_create_pango_layout(resultview, NULL);
9196 					PANGO_TTP(layout_pm, SIGN_PLUSMINUS);
9197 					pango_layout_get_pixel_size(layout_pm, &pm_w, &pm_h);
9198 					w = mid_w + unc_w + pm_w;
9199 					dh = mid_dh; uh = mid_uh;
9200 					if(unc_dh > dh) h = unc_dh;
9201 					if(unc_uh > uh) uh = unc_uh;
9202 					if(pm_h / 2 > dh) {
9203 						dh = pm_h / 2;
9204 					}
9205 					if(pm_h / 2 + pm_h % 2 > uh) {
9206 						uh = pm_h / 2 + pm_h % 2;
9207 					}
9208 					h = uh + dh;
9209 					central_point = dh;
9210 					surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
9211 					cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
9212 					cr = cairo_create(surface);
9213 					gdk_cairo_set_source_rgba(cr, color);
9214 					w = 0;
9215 					cairo_set_source_surface(cr, mid_surface, w, uh - mid_uh);
9216 					cairo_paint(cr);
9217 					w += mid_w;
9218 					gdk_cairo_set_source_rgba(cr, color);
9219 					cairo_move_to(cr, w, uh - pm_h / 2 - pm_h % 2);
9220 					pango_cairo_show_layout(cr, layout_pm);
9221 					w += pm_w;
9222 					cairo_set_source_surface(cr, unc_surface, w, uh - unc_uh);
9223 					cairo_paint(cr);
9224 					g_object_unref(layout_pm);
9225 					cairo_surface_destroy(mid_surface);
9226 					cairo_surface_destroy(unc_surface);
9227 					break;
9228 				} else if(SHOW_WITH_ROOT_SIGN(m)) {
9229 
9230 					ips_n.depth++;
9231 					gint arg_w, arg_h, root_w, root_h, sign_w, sign_h, h, w, ctmp;
9232 
9233 					int i_root = 2;
9234 					if(m.function() == CALCULATOR->f_root) i_root = m[1].number().intValue();
9235 					else if(m.function() == CALCULATOR->f_cbrt) i_root = 3;
9236 					string root_str;
9237 					TT_XSMALL(root_str, i2s(i_root));
9238 					PangoLayout *layout_root = gtk_widget_create_pango_layout(resultview, NULL);
9239 					pango_layout_set_markup(layout_root, root_str.c_str(), -1);
9240 					pango_layout_get_pixel_size(layout_root, &root_w, &root_h);
9241 					PangoRectangle rect;
9242 					pango_layout_get_pixel_extents(layout_root, &rect, NULL);
9243 					root_h = rect.y + rect.height;
9244 
9245 					ips_n.wrap = false;
9246 					cairo_surface_t *surface_arg = draw_structure(m[0], po, caf, ips_n, &ctmp, scaledown, color);
9247 					if(!surface_arg) return NULL;
9248 
9249 					arg_w = cairo_image_surface_get_width(surface_arg) / scalefactor;
9250 					arg_h = cairo_image_surface_get_height(surface_arg) / scalefactor;
9251 
9252 					int y;
9253 					get_image_blank_height(surface_arg, &y, NULL);
9254 					y /= scalefactor;
9255 					y -= 6;
9256 					arg_h -= y;
9257 
9258 					double divider = 1.0;
9259 					if(ips.power_depth >= 1) divider = 1.5;
9260 
9261 					gint extra_space = 5;
9262 					if(scaledown == 1) extra_space = 3;
9263 					else if(scaledown > 1) extra_space = 1;
9264 
9265 					central_point = ctmp + extra_space / divider;
9266 
9267 					root_w = root_w / divider;
9268 					root_h = root_h / divider;
9269 					sign_w = root_w * 2.6;
9270 
9271 					if(i_root == 2) {
9272 						sign_h = arg_h + extra_space / divider;
9273 					} else {
9274 						sign_h = root_h * 2.0;
9275 						if(sign_h < arg_h + extra_space / divider) sign_h = arg_h + extra_space / divider;
9276 					}
9277 
9278 					h = sign_h + extra_space * 2.0 / divider;
9279 					w = arg_w + sign_w * 1.25;
9280 
9281 					surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
9282 					cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
9283 					cr = cairo_create(surface);
9284 					gdk_cairo_set_source_rgba(cr, color);
9285 
9286 					cairo_move_to(cr, 0, h / 2.0 + h / 15.0);
9287 					cairo_line_to(cr, sign_w / 6.0, h / 2.0);
9288 					cairo_line_to(cr, sign_w / 2.2, h - extra_space / divider);
9289 					cairo_line_to(cr, sign_w,  extra_space / divider);
9290 					cairo_line_to(cr, w,  extra_space / divider);
9291 					cairo_set_line_width(cr, 2 / divider);
9292 					cairo_stroke(cr);
9293 
9294 					if(i_root != 2) {
9295 						cairo_move_to(cr, (sign_w - root_w) / 3.0, (h / 2.0) - root_h - extra_space / (divider * 2) - 1);
9296 						cairo_surface_set_device_scale(surface, scalefactor / divider, scalefactor / divider);
9297 						pango_cairo_show_layout(cr, layout_root);
9298 						cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
9299 					}
9300 
9301 					gdk_cairo_set_source_rgba(cr, color);
9302 					cairo_move_to(cr, 0, 0);
9303 					cairo_set_source_surface(cr, surface_arg, sign_w + 1, h - arg_h - extra_space / divider - y);
9304 					cairo_paint(cr);
9305 
9306 					cairo_surface_destroy(surface_arg);
9307 					g_object_unref(layout_root);
9308 
9309 					break;
9310 
9311 				} else if((m.function() == CALCULATOR->f_abs || m.function() == CALCULATOR->f_floor || m.function() == CALCULATOR->f_ceil) && m.size() == 1) {
9312 
9313 					ips_n.depth++;
9314 					gint arg_w, arg_h, h, w, ctmp;
9315 
9316 					ips_n.wrap = false;
9317 					cairo_surface_t *surface_arg = draw_structure(m[0], po, caf, ips_n, &ctmp, scaledown, color);
9318 					if(!surface_arg) return NULL;
9319 
9320 					arg_w = cairo_image_surface_get_width(surface_arg) / scalefactor;
9321 					arg_h = cairo_image_surface_get_height(surface_arg) / scalefactor;
9322 
9323 					double divider = 1.0;
9324 					if(ips.power_depth >= 1) divider = 1.5;
9325 
9326 					gint extra_space = m.function() == CALCULATOR->f_abs ? 5 : 3;
9327 					gint bracket_length = (m.function() == CALCULATOR->f_abs ? 0 : 7);
9328 
9329 					int y;
9330 					get_image_blank_height(surface_arg, &y, NULL);
9331 					y /= scalefactor;
9332 					y -= 6; if(y < 0) y = 0;
9333 					arg_h -= y;
9334 
9335 					gint line_space = extra_space / divider;
9336 					central_point = ctmp + line_space;
9337 					h = arg_h + line_space * 2;
9338 					w = arg_w + (m.function() != CALCULATOR->f_abs && extra_space > 2 ? 4 : extra_space * 2) + extra_space * 2 / divider + bracket_length * 2;
9339 					double linewidth = 2 / divider;
9340 
9341 					surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
9342 					cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
9343 					cr = cairo_create(surface);
9344 					gdk_cairo_set_source_rgba(cr, color);
9345 
9346 					cairo_move_to(cr, (extra_space / divider), line_space);
9347 					cairo_line_to(cr, (extra_space / divider), h - line_space);
9348 					cairo_move_to(cr, w - (extra_space / divider), line_space);
9349 					cairo_line_to(cr, w - (extra_space / divider), h - line_space);
9350 					if(m.function() == CALCULATOR->f_floor) {
9351 						cairo_move_to(cr, extra_space / divider, h - line_space - linewidth / 2);
9352 						cairo_line_to(cr, extra_space / divider + bracket_length, h - line_space - linewidth / 2);
9353 						cairo_move_to(cr, w - (extra_space / divider) - bracket_length, h - line_space - linewidth / 2);
9354 						cairo_line_to(cr, w - (extra_space / divider), h - line_space - linewidth / 2);
9355 					} else if(m.function() == CALCULATOR->f_ceil) {
9356 						cairo_move_to(cr, extra_space / divider, line_space + linewidth / 2);
9357 						cairo_line_to(cr, extra_space / divider + bracket_length, line_space + linewidth / 2);
9358 						cairo_move_to(cr, w - (extra_space / divider) - bracket_length, line_space + linewidth / 2);
9359 						cairo_line_to(cr, w - (extra_space / divider), line_space + linewidth / 2);
9360 					}
9361 					cairo_set_line_width(cr, linewidth);
9362 					cairo_stroke(cr);
9363 
9364 					gdk_cairo_set_source_rgba(cr, color);
9365 					cairo_move_to(cr, 0, 0);
9366 					cairo_set_source_surface(cr, surface_arg, (w - arg_w) / 2.0, line_space - y);
9367 					cairo_paint(cr);
9368 
9369 					cairo_surface_destroy(surface_arg);
9370 
9371 					break;
9372 				} 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()) {
9373 
9374 					MathStructure mdx("d");
9375 					if(!m[2].isOne()) mdx ^= m[2];
9376 					string s = "d";
9377 					if(m[1].isSymbolic()) s += m[1].symbol();
9378 					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;
9379 					mdx.transform(STRUCT_DIVISION, s);
9380 					if(!m[2].isOne()) mdx[1] ^= m[2];
9381 
9382 					ips_n.depth++;
9383 
9384 					gint hpt1, hpt2;
9385 					gint wpt1, wpt2;
9386 					gint cpt1, cpt2;
9387 					gint w = 0, h = 0, dh = 0, uh = 0;
9388 
9389 					CALCULATE_SPACE_W
9390 
9391 					ips_n.wrap = false;
9392 					cairo_surface_t *surface_term1 = draw_structure(mdx, po, caf, ips_n, &cpt1, scaledown, color);
9393 					wpt1 = cairo_image_surface_get_width(surface_term1) / scalefactor;
9394 					hpt1 = cairo_image_surface_get_height(surface_term1) / scalefactor;
9395 					ips_n.wrap = true;
9396 					cairo_surface_t *surface_term2 = draw_structure(m[0], po, caf, ips_n, &cpt2, scaledown, color);
9397 					wpt2 = cairo_image_surface_get_width(surface_term2) / scalefactor;
9398 					hpt2 = cairo_image_surface_get_height(surface_term2) / scalefactor;
9399 					w = wpt1 + wpt2 + space_w;
9400 					if(hpt1 - cpt1 > hpt2 - cpt2) uh = hpt1 - cpt1;
9401 					else uh = hpt2 - cpt2;
9402 					if(cpt1 > cpt2) dh = cpt1;
9403 					else dh = cpt2;
9404 					central_point = dh;
9405 					h = dh + uh;
9406 					surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
9407 					cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
9408 					cr = cairo_create(surface);
9409 					gdk_cairo_set_source_rgba(cr, color);
9410 					cairo_set_source_surface(cr, surface_term1, 0, uh - (hpt1 - cpt1));
9411 					cairo_paint(cr);
9412 					gdk_cairo_set_source_rgba(cr, color);
9413 					cairo_set_source_surface(cr, surface_term2, wpt1 + space_w, uh - (hpt2 - cpt2));
9414 					cairo_paint(cr);
9415 					cairo_surface_destroy(surface_term1);
9416 					cairo_surface_destroy(surface_term2);
9417 
9418 					break;
9419 				}
9420 
9421 				ips_n.depth++;
9422 
9423 				gint comma_w, comma_h, function_w, function_h, uh, dh, h, w, ctmp, htmp, wtmp, arc_w, arc_h, xtmp;
9424 				vector<cairo_surface_t*> surface_args;
9425 				vector<gint> hpa, cpa, wpa, xpa;
9426 
9427 				CALCULATE_SPACE_W
9428 				PangoLayout *layout_comma = gtk_widget_create_pango_layout(resultview, NULL);
9429 				string str;
9430 				TTP(str, po.comma())
9431 				pango_layout_set_markup(layout_comma, str.c_str(), -1);
9432 				pango_layout_get_pixel_size(layout_comma, &comma_w, &comma_h);
9433 				PangoLayout *layout_function = gtk_widget_create_pango_layout(resultview, NULL);
9434 
9435 				str = "";
9436 				TTBP(str);
9437 
9438 				size_t argcount = m.size();
9439 
9440 				if(m.function() == CALCULATOR->f_signum && argcount > 1) {
9441 					argcount = 1;
9442 				} else if(m.function() == CALCULATOR->f_integrate && argcount > 3) {
9443 					if(m[1].isUndefined() && m[2].isUndefined()) argcount = 1;
9444 					else argcount = 3;
9445 				} else if(m.function()->maxargs() > 0 && m.function()->minargs() < m.function()->maxargs() && m.size() > (size_t) m.function()->minargs()) {
9446 					while(true) {
9447 						string defstr = m.function()->getDefaultValue(argcount);
9448 						Argument *arg = m.function()->getArgumentDefinition(argcount);
9449 						remove_blank_ends(defstr);
9450 						if(defstr.empty()) break;
9451 						if(m[argcount - 1].isUndefined() && defstr == "undefined") {
9452 							argcount--;
9453 						} else if(argcount > 1 && arg && arg->type() == ARGUMENT_TYPE_SYMBOLIC && ((argcount > 1 && defstr == "undefined" && m[argcount - 1] == m[0].find_x_var()) || (defstr == "\"\"" && m[argcount - 1] == ""))) {
9454 							argcount--;
9455 						} else if(m[argcount - 1].isVariable() && (!arg || arg->type() != ARGUMENT_TYPE_TEXT) && defstr == m[argcount - 1].variable()->referenceName()) {
9456 							argcount--;
9457 						} 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)) {
9458 							argcount--;
9459 						} else if(m[argcount - 1].isSymbolic() && arg && arg->type() == ARGUMENT_TYPE_TEXT && (m[argcount - 1].symbol() == defstr || (defstr == "\"\"" && m[argcount - 1].symbol().empty()))) {
9460 							argcount--;
9461 						} else {
9462 							break;
9463 						}
9464 						if(argcount == 0 || argcount == (size_t) m.function()->minargs()) break;
9465 					}
9466 				}
9467 
9468 				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);
9469 				if(ename->suffix && ename->name.length() > 1) {
9470 
9471 					size_t i = ename->name.rfind('_');
9472 					bool b = i == string::npos || i == ename->name.length() - 1 || i == 0;
9473 					size_t i2 = 1;
9474 					if(b) {
9475 						if(is_in(NUMBERS, ename->name[ename->name.length() - 1])) {
9476 							while(ename->name.length() > i2 + 1 && is_in(NUMBERS, ename->name[ename->name.length() - 1 - i2])) {
9477 								i2++;
9478 							}
9479 						}
9480 						str += ename->name.substr(0, ename->name.length() - i2);
9481 					} else {
9482 						str += ename->name.substr(0, i);
9483 					}
9484 					TTBP_SMALL(str);
9485 					str += "<sub>";
9486 					if(b) str += ename->name.substr(ename->name.length() - i2, i2);
9487 					else str += ename->name.substr(i + 1, ename->name.length() - (i + 1));
9488 					str += "</sub>";
9489 					TTE(str);
9490 				} else {
9491 					str += ename->name;
9492 					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))))) {
9493 						argcount = 1;
9494 						TTBP_SMALL(str);
9495 						str += "<sub>";
9496 						str += m[1].print(po);
9497 						str += "</sub>";
9498 						TTE(str);
9499 					}
9500 				}
9501 				gsub("_", " ", str);
9502 
9503 				TTE(str);
9504 
9505 				pango_layout_set_markup(layout_function, str.c_str(), -1);
9506 				PangoRectangle rect, lrect;
9507 				pango_layout_get_pixel_extents(layout_function, &rect, &lrect);
9508 				function_w = lrect.width;
9509 				function_h = lrect.height;
9510 				if(rect.x < 0) {
9511 					function_w -= rect.x;
9512 					if(rect.width > function_w) {
9513 						function_w = rect.width;
9514 					}
9515 					offset_x = -rect.x;
9516 				} else {
9517 					if(rect.width + rect.x > function_w) {
9518 						function_w = rect.width + rect.x;
9519 					}
9520 				}
9521 				w = function_w + 1;
9522 				uh = function_h / 2 + function_h % 2;
9523 				dh = function_h / 2;
9524 				if(rect.y < 0) {
9525 					uh = -rect.y;
9526 					function_h -= rect.y;
9527 				}
9528 
9529 				for(size_t index = 0; index < argcount; index++) {
9530 
9531 					ips_n.wrap = m[index].needsParenthesis(po, ips_n, m, index + 1, ips.division_depth > 0 || ips.power_depth > 0, ips.power_depth > 0);
9532 					if(m.function() == CALCULATOR->f_interval) {
9533 						PrintOptions po2 = po;
9534 						po2.show_ending_zeroes = false;
9535 						if(m[index].isNumber()) {
9536 							if(index == 0) po2.interval_display = INTERVAL_DISPLAY_LOWER;
9537 							else if(index == 1) po2.interval_display = INTERVAL_DISPLAY_UPPER;
9538 						}
9539 						surface_args.push_back(draw_structure(m[index], po2, caf, ips_n, &ctmp, scaledown, color, &xtmp));
9540 					} else {
9541 						surface_args.push_back(draw_structure(m[index], po, caf, ips_n, &ctmp, scaledown, color, &xtmp));
9542 					}
9543 					if(CALCULATOR->aborted()) {
9544 						for(size_t i = 0; i < surface_args.size(); i++) {
9545 							if(surface_args[i]) cairo_surface_destroy(surface_args[i]);
9546 						}
9547 						g_object_unref(layout_function);
9548 						g_object_unref(layout_comma);
9549 						return NULL;
9550 					}
9551 					wtmp = cairo_image_surface_get_width(surface_args[index]) / scalefactor;
9552 					htmp = cairo_image_surface_get_height(surface_args[index]) / scalefactor;
9553 					if(index == 0) xtmp = 0;
9554 					hpa.push_back(htmp);
9555 					cpa.push_back(ctmp);
9556 					wpa.push_back(wtmp);
9557 					xpa.push_back(xtmp);
9558 					if(index > 0) {
9559 						w += comma_w;
9560 						w += space_w;
9561 					}
9562 					w -= xtmp;
9563 					w += wtmp;
9564 					if(ctmp > dh) {
9565 						dh = ctmp;
9566 					}
9567 					if(htmp - ctmp > uh) {
9568 						uh = htmp - ctmp;
9569 					}
9570 				}
9571 
9572 				if(dh > uh) uh = dh;
9573 				else if(uh > dh) dh = uh;
9574 				h = uh + dh;
9575 				central_point = dh;
9576 				arc_h = h;
9577 				arc_w = PAR_WIDTH;
9578 				w += arc_w * 2;
9579 				w += ips.power_depth > 0 ? 3 : 4;
9580 
9581 				int x1 = 0, x2 = 0;
9582 				if(surface_args.size() == 1) {
9583 					get_image_blank_width(surface_args[0], &x1, &x2);
9584 					x1 /= scalefactor;
9585 					x1++;
9586 					x2 = ::ceil(x2 / scalefactor);
9587 					w -= wpa[0];
9588 					wpa[0] = x2 - x1;
9589 					w += wpa[0];
9590 				} else if(surface_args.size() > 1) {
9591 					get_image_blank_width(surface_args[0], &x1, NULL);
9592 					x1 /= scalefactor;
9593 					x1++;
9594 					w -= x1;
9595 					wpa[0] -= x1;
9596 					int i_last = surface_args.size() - 1;
9597 					get_image_blank_width(surface_args[i_last], NULL, &x2);
9598 					x2 = ::ceil(x2 / scalefactor);
9599 					w -= wpa[i_last] - x2;
9600 					wpa[i_last] -= wpa[i_last] - x2;
9601 				}
9602 
9603 				surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
9604 				cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
9605 				cr = cairo_create(surface);
9606 
9607 				w = 0;
9608 				gdk_cairo_set_source_rgba(cr, color);
9609 				cairo_move_to(cr, w, uh - function_h / 2 - function_h % 2);
9610 				pango_cairo_show_layout(cr, layout_function);
9611 				w += function_w;
9612 				w += ips.power_depth > 0 ? 2 : 3;
9613 				cairo_set_source_surface(cr, get_left_parenthesis(arc_w, arc_h, scaledown, color), w, (h - arc_h) / 2);
9614 				cairo_paint(cr);
9615 				w += arc_w;
9616 				for(size_t index = 0; index < surface_args.size(); index++) {
9617 					if(!CALCULATOR->aborted()) {
9618 						gdk_cairo_set_source_rgba(cr, color);
9619 						if(index > 0) {
9620 							cairo_move_to(cr, w, uh - comma_h / 2 - comma_h % 2);
9621 							pango_cairo_show_layout(cr, layout_comma);
9622 							w += comma_w;
9623 							w += space_w;
9624 						}
9625 						w -= xpa[index];
9626 						cairo_set_source_surface(cr, surface_args[index], index == 0 ? w - x1 : w, uh - (hpa[index] - cpa[index]));
9627 						cairo_paint(cr);
9628 						w += wpa[index];
9629 					}
9630 					cairo_surface_destroy(surface_args[index]);
9631 				}
9632 				cairo_set_source_surface(cr, get_right_parenthesis(arc_w, arc_h, scaledown, color), w, (h - arc_h) / 2);
9633 				cairo_paint(cr);
9634 
9635 				g_object_unref(layout_comma);
9636 				g_object_unref(layout_function);
9637 
9638 				break;
9639 			}
9640 			case STRUCT_UNDEFINED: {
9641 				PangoLayout *layout = gtk_widget_create_pango_layout(resultview, NULL);
9642 				string str;
9643 				TTP(str, _("undefined"));
9644 				pango_layout_set_markup(layout, str.c_str(), -1);
9645 				PangoRectangle rect, lrect;
9646 				pango_layout_get_pixel_extents(layout, &rect, &lrect);
9647 				w = lrect.width;
9648 				h = lrect.height;
9649 				if(rect.x < 0) {
9650 					w -= rect.x;
9651 					if(rect.width > w) {
9652 						offset_w = rect.width - w;
9653 						w = rect.width;
9654 					}
9655 					offset_x = -rect.x;
9656 				} else {
9657 					if(rect.width + rect.x > w) {
9658 						offset_w = rect.width + rect.x - w;
9659 						w = rect.width + rect.x;
9660 					}
9661 				}
9662 				central_point = h / 2;
9663 				if(rect.y < 0) h -= rect.y;
9664 				surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
9665 				cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
9666 				cr = cairo_create(surface);
9667 				gdk_cairo_set_source_rgba(cr, color);
9668 				cairo_move_to(cr, offset_x, rect.y < 0 ? -rect.y : 0);
9669 				pango_cairo_show_layout(cr, layout);
9670 				g_object_unref(layout);
9671 				break;
9672 			}
9673 			default: {}
9674 		}
9675 	}
9676 	if(ips.wrap && surface) {
9677 		gint w, h, base_h, base_w;
9678 		offset_w = 0; offset_x = 0;
9679 		base_w = cairo_image_surface_get_width(surface) / scalefactor;
9680 		base_h = cairo_image_surface_get_height(surface) / scalefactor;
9681 		int x1 = 0, x2 = 0;
9682 		get_image_blank_width(surface, &x1, &x2);
9683 		x1 /= scalefactor;
9684 		x1++;
9685 		x2 = ::ceil(x2 / scalefactor);
9686 		base_w = x2 - x1;
9687 		h = base_h;
9688 		w = base_w;
9689 		gint base_dh = central_point;
9690 		if(h > central_point * 2) central_point = h - central_point;
9691 		gint arc_base_h = central_point * 2;
9692 		if(h < arc_base_h) h = arc_base_h;
9693 		gint arc_base_w = PAR_WIDTH;
9694 		w += arc_base_w * 2;
9695 		w += ips.power_depth > 0 ? 2 : 3;
9696 		cairo_surface_t *surface_old = surface;
9697 		cairo_destroy(cr);
9698 		surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
9699 		cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
9700 		cr = cairo_create(surface);
9701 		gdk_cairo_set_source_rgba(cr, color);
9702 		w = ips.power_depth > 0 ? 2 : 3;
9703 		cairo_set_source_surface(cr, get_left_parenthesis(arc_base_w, arc_base_h, scaledown, color), w, (h - arc_base_h) / 2);
9704 		cairo_paint(cr);
9705 		w += arc_base_w;
9706 		cairo_set_source_surface(cr, surface_old, w - x1, central_point - (base_h - base_dh));
9707 		cairo_paint(cr);
9708 		cairo_surface_destroy(surface_old);
9709 		w += base_w;
9710 		cairo_set_source_surface(cr, get_right_parenthesis(arc_base_w, arc_base_h, scaledown, color), w, (h - arc_base_h) / 2);
9711 		cairo_paint(cr);
9712 	}
9713 	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) {
9714 		gint w, h, wle, hle, w_new, h_new;
9715 		w = cairo_image_surface_get_width(surface) / scalefactor;
9716 		h = cairo_image_surface_get_height(surface) / scalefactor;
9717 		cairo_surface_t *surface_old = surface;
9718 		PangoLayout *layout_equals = gtk_widget_create_pango_layout(resultview, NULL);
9719 		if((po.is_approximate && *po.is_approximate) || m.isApproximate()) {
9720 			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))) {
9721 				PANGO_TT(layout_equals, SIGN_ALMOST_EQUAL);
9722 			} else {
9723 				string str;
9724 				TTB(str);
9725 				str += "= ";
9726 				str += _("approx.");
9727 				TTE(str);
9728 				pango_layout_set_markup(layout_equals, str.c_str(), -1);
9729 			}
9730 		} else {
9731 			PANGO_TT(layout_equals, "=");
9732 		}
9733 		CALCULATE_SPACE_W
9734 		PangoRectangle rect, lrect;
9735 		pango_layout_get_pixel_extents(layout_equals, &rect, &lrect);
9736 		wle = lrect.width - offset_x;
9737 		offset_x = 0;
9738 		if(rect.x < 0) {
9739 			wle -= rect.x;
9740 			offset_x = -rect.x;
9741 		}
9742 		hle = lrect.height;
9743 		w_new = w + wle + space_w;
9744 		h_new = h;
9745 		surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w_new * scalefactor, h_new * scalefactor);
9746 		cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
9747 		cr = cairo_create(surface);
9748 		gdk_cairo_set_source_rgba(cr, color);
9749 		cairo_move_to(cr, offset_x, h - central_point - hle / 2 - hle % 2);
9750 		pango_cairo_show_layout(cr, layout_equals);
9751 		cairo_set_source_surface(cr, surface_old, wle + space_w, 0);
9752 		cairo_paint(cr);
9753 		cairo_surface_destroy(surface_old);
9754 		g_object_unref(layout_equals);
9755 	}
9756 	if(!surface) {
9757 		surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1 * scalefactor, 1 * scalefactor);
9758 		cairo_surface_set_device_scale(surface, scalefactor, scalefactor);
9759 		cr = cairo_create(surface);
9760 	}
9761 	if(cr) cairo_destroy(cr);
9762 	if(point_central) *point_central = central_point;
9763 	if(x_offset) *x_offset = offset_x;
9764 	if(w_offset) *w_offset = offset_w;
9765 	return surface;
9766 }
9767 
set_status_bottom_border_visible(bool b)9768 void set_status_bottom_border_visible(bool b) {
9769 	gchar *gstr = gtk_css_provider_to_string(statusframe_provider);
9770 	string status_css = gstr;
9771 	g_free(gstr);
9772 	if(b) {
9773 		gsub("border-bottom-width: 0;", "", status_css);
9774 	} else {
9775 		gsub("}", "border-bottom-width: 0;}", status_css);
9776 	}
9777 	gtk_css_provider_load_from_data(statusframe_provider, status_css.c_str(), -1, NULL);
9778 }
9779 
clearresult()9780 void clearresult() {
9781 	if(minimal_mode && gtk_widget_is_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "resultoverlay")))) {
9782 		gint w, h;
9783 		gtk_window_get_size(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), &w, &h);
9784 		h -= gtk_widget_get_allocated_height(GTK_WIDGET(gtk_builder_get_object(main_builder, "resultoverlay")));
9785 		set_status_bottom_border_visible(false);
9786 		h -= 1;
9787 		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "resultoverlay")));
9788 		gtk_window_resize(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), w, h);
9789 	}
9790 	showing_first_time_message = false;
9791 	if(displayed_mstruct) {
9792 		displayed_mstruct->unref();
9793 		displayed_mstruct = NULL;
9794 		if(!surface_result) gtk_widget_queue_draw(resultview);
9795 	}
9796 	result_autocalculated = false;
9797 	date_map.clear();
9798 	number_map.clear();
9799 	number_base_map.clear();
9800 	number_exp_map.clear();
9801 	number_exp_minus_map.clear();
9802 	number_approx_map.clear();
9803 	if(gtk_revealer_get_child_revealed(GTK_REVEALER(gtk_builder_get_object(main_builder, "message_revealer")))) {
9804 		gtk_info_bar_response(GTK_INFO_BAR(gtk_builder_get_object(main_builder, "message_bar")), GTK_RESPONSE_CLOSE);
9805 	}
9806 	update_expression_icons();
9807 	if(surface_result) {
9808 		cairo_surface_destroy(surface_result);
9809 		surface_result = NULL;
9810 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "menu_item_save_image")), FALSE);
9811 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_save_image")), FALSE);
9812 		gtk_widget_queue_draw(resultview);
9813 	}
9814 	if(visible_keypad & PROGRAMMING_KEYPAD) {
9815 		result_bin = ""; result_oct = ""; result_dec = ""; result_hex = "";
9816 		update_result_bases();
9817 	}
9818 	gtk_widget_set_tooltip_text(resultview, "");
9819 }
9820 
on_abort_display(GtkDialog *,gint,gpointer)9821 void on_abort_display(GtkDialog*, gint, gpointer) {
9822 	CALCULATOR->abort();
9823 }
9824 
replace_interval_with_function(MathStructure & m)9825 void replace_interval_with_function(MathStructure &m) {
9826 	if(m.isNumber() && m.number().isInterval()) {
9827 		m.transform(STRUCT_FUNCTION);
9828 		m.setFunction(CALCULATOR->f_interval);
9829 		m.addChild(m[0]);
9830 	} else {
9831 		for(size_t i = 0; i < m.size(); i++) replace_interval_with_function(m[i]);
9832 	}
9833 }
9834 
run()9835 void ViewThread::run() {
9836 
9837 	while(true) {
9838 		int scale_tmp = 0;
9839 		if(!read(&scale_tmp)) break;
9840 		void *x = NULL;
9841 		if(!read(&x) || !x) break;
9842 		MathStructure m(*((MathStructure*) x));
9843 		bool b_stack = false;
9844 		if(!read(&b_stack)) break;
9845 		if(!read(&x)) break;
9846 		MathStructure *mm = (MathStructure*) x;
9847 		if(!read(&x)) break;
9848 		CALCULATOR->startControl();
9849 		printops.can_display_unicode_string_arg = (void*) historyview;
9850 		bool b_puup = printops.use_unit_prefixes;
9851 		if(x) {
9852 			PrintOptions po;
9853 			if(!read(&po.is_approximate)) break;
9854 			void *x_to = NULL;
9855 			if(!read(&x_to)) break;
9856 			po.show_ending_zeroes = evalops.parse_options.read_precision != DONT_READ_PRECISION && CALCULATOR->usesIntervalArithmetic() && evalops.parse_options.base > BASE_CUSTOM;
9857 			po.lower_case_e = printops.lower_case_e;
9858 			po.lower_case_numbers = printops.lower_case_numbers;
9859 			po.base_display = printops.base_display;
9860 			po.twos_complement = printops.twos_complement;
9861 			po.hexadecimal_twos_complement = printops.hexadecimal_twos_complement;
9862 			po.base = evalops.parse_options.base;
9863 			po.preserve_format = (x_to != NULL);
9864 			Number nr_base;
9865 			if(po.base == BASE_CUSTOM && (CALCULATOR->usesIntervalArithmetic() || CALCULATOR->customInputBase().isRational()) && (CALCULATOR->customInputBase().isInteger() || !CALCULATOR->customInputBase().isNegative()) && (CALCULATOR->customInputBase() > 1 || CALCULATOR->customInputBase() < -1)) {
9866 				nr_base = CALCULATOR->customOutputBase();
9867 				CALCULATOR->setCustomOutputBase(CALCULATOR->customInputBase());
9868 			} else if(po.base == BASE_CUSTOM || (po.base < BASE_CUSTOM && !CALCULATOR->usesIntervalArithmetic() && po.base != BASE_UNICODE && po.base != BASE_BIJECTIVE_26)) {
9869 				po.base = 10;
9870 				po.min_exp = 6;
9871 				po.use_max_decimals = true;
9872 				po.max_decimals = 5;
9873 				po.preserve_format = false;
9874 			}
9875 			po.abbreviate_names = false;
9876 			po.use_unicode_signs = printops.use_unicode_signs;
9877 			po.digit_grouping = printops.digit_grouping;
9878 			po.multiplication_sign = printops.multiplication_sign;
9879 			po.division_sign = printops.division_sign;
9880 			po.short_multiplication = false;
9881 			po.excessive_parenthesis = true;
9882 			po.improve_division_multipliers = false;
9883 			po.can_display_unicode_string_function = &can_display_unicode_string_function;
9884 			po.can_display_unicode_string_arg = (void*) statuslabel_l;
9885 			po.spell_out_logical_operators = printops.spell_out_logical_operators;
9886 			po.restrict_to_parent_precision = false;
9887 			po.interval_display = INTERVAL_DISPLAY_PLUSMINUS;
9888 			MathStructure mp(*((MathStructure*) x));
9889 			mp.format(po);
9890 			parsed_text = mp.print(po);
9891 			if(x_to && !((MathStructure*) x_to)->isUndefined()) {
9892 				mp.set(*((MathStructure*) x_to));
9893 				parsed_text += CALCULATOR->localToString();
9894 				mp.format(po);
9895 				parsed_text += mp.print(po);
9896 				printops.use_unit_prefixes = true;
9897 			}
9898 			if(po.base == BASE_CUSTOM) CALCULATOR->setCustomOutputBase(nr_base);
9899 		}
9900 		printops.allow_non_usable = false;
9901 
9902 		if(mm && m.isMatrix()) {
9903 			mm->set(m);
9904 			MathStructure mm2(m);
9905 			string mstr;
9906 			int c = mm->columns(), r = mm->rows();
9907 			for(int index_r = 0; index_r < r; index_r++) {
9908 				for(int index_c = 0; index_c < c; index_c++) {
9909 					mm->getElement(index_r + 1, index_c + 1)->setAborted();
9910 				}
9911 			}
9912 			for(int index_r = 0; index_r < r; index_r++) {
9913 				for(int index_c = 0; index_c < c; index_c++) {
9914 					mm2.getElement(index_r + 1, index_c + 1)->format(printops);
9915 					mstr = mm2.getElement(index_r + 1, index_c + 1)->print(printops);
9916 					mm->getElement(index_r + 1, index_c + 1)->set(mstr);
9917 				}
9918 			}
9919 		}
9920 
9921 		// convert time units to hours when using time format
9922 		if(printops.base == BASE_TIME && is_time(m)) {
9923 			Unit *u = CALCULATOR->getActiveUnit("h");
9924 			if(u) {
9925 				m.divide(u);
9926 				m.eval(evalops);
9927 			}
9928 		}
9929 
9930 		if(printops.spell_out_logical_operators && x && test_parsed_comparison_gtk(*((MathStructure*) x))) {
9931 			if(m.isZero()) {
9932 				Variable *v = CALCULATOR->getActiveVariable("false");
9933 				if(v) m.set(v);
9934 			} else if(m.isOne()) {
9935 				Variable *v = CALCULATOR->getActiveVariable("true");
9936 				if(v) m.set(v);
9937 			}
9938 		}
9939 
9940 		m.removeDefaultAngleUnit(evalops);
9941 		m.format(printops);
9942 		m.removeDefaultAngleUnit(evalops);
9943 		gint64 time1 = g_get_monotonic_time();
9944 		result_text = m.print(printops);
9945 		if(complex_angle_form) replace_result_cis_gtk(result_text);
9946 		result_text_approximate = *printops.is_approximate;
9947 
9948 		if(!b_stack && visible_keypad & PROGRAMMING_KEYPAD) {
9949 			set_result_bases(m);
9950 		}
9951 
9952 		if(!b_stack && g_get_monotonic_time() - time1 < 200000) {
9953 			PrintOptions printops_long = printops;
9954 			printops_long.abbreviate_names = false;
9955 			printops_long.short_multiplication = false;
9956 			printops_long.excessive_parenthesis = true;
9957 			printops_long.is_approximate = NULL;
9958 			result_text_long = m.print(printops_long);
9959 			if(complex_angle_form) replace_result_cis_gtk(result_text_long);
9960 		} else if(!b_stack) {
9961 			result_text_long = "";
9962 		}
9963 		printops.can_display_unicode_string_arg = NULL;
9964 
9965 		result_too_long = false;
9966 		if(!b_stack && result_text.length() > 900) {
9967 			PangoLayout *layout = gtk_widget_create_pango_layout(resultview, NULL);
9968 			result_too_long = true;
9969 			pango_layout_set_markup(layout, _("result is too long\nsee history"), -1);
9970 			gint w = 0, h = 0;
9971 			pango_layout_get_pixel_size(layout, &w, &h);
9972 			PangoRectangle rect;
9973 			pango_layout_get_pixel_extents(layout, &rect, NULL);
9974 			if(rect.x < 0) {w -= rect.x; if(rect.width > w) w = rect.width;}
9975 			else if(w < rect.x + rect.width) w = rect.x + rect.width;
9976 			gint scalefactor = gtk_widget_get_scale_factor(expressiontext);
9977 			tmp_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
9978 			cairo_surface_set_device_scale(tmp_surface, scalefactor, scalefactor);
9979 			cairo_t *cr = cairo_create(tmp_surface);
9980 			GdkRGBA rgba;
9981 			gtk_style_context_get_color(gtk_widget_get_style_context(resultview), gtk_widget_get_state_flags(resultview), &rgba);
9982 			gdk_cairo_set_source_rgba(cr, &rgba);
9983 			if(rect.x < 0) cairo_move_to(cr, -rect.x, 0);
9984 			pango_cairo_show_layout(cr, layout);
9985 			cairo_destroy(cr);
9986 			g_object_unref(layout);
9987 			*printops.is_approximate = false;
9988 			if(displayed_mstruct) {
9989 				displayed_mstruct->unref();
9990 				displayed_mstruct = NULL;
9991 			}
9992 		} else if(!b_stack && m.isAborted()) {
9993 			PangoLayout *layout = gtk_widget_create_pango_layout(resultview, NULL);
9994 			pango_layout_set_markup(layout, _("calculation was aborted"), -1);
9995 			gint w = 0, h = 0;
9996 			pango_layout_get_pixel_size(layout, &w, &h);
9997 			PangoRectangle rect;
9998 			pango_layout_get_pixel_extents(layout, &rect, NULL);
9999 			if(rect.x < 0) {w -= rect.x; if(rect.width > w) w = rect.width;}
10000 			else if(w < rect.x + rect.width) w = rect.x + rect.width;
10001 			gint scalefactor = gtk_widget_get_scale_factor(expressiontext);
10002 			tmp_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
10003 			cairo_t *cr = cairo_create(tmp_surface);
10004 			GdkRGBA rgba;
10005 			gtk_style_context_get_color(gtk_widget_get_style_context(resultview), gtk_widget_get_state_flags(resultview), &rgba);
10006 			gdk_cairo_set_source_rgba(cr, &rgba);
10007 			if(rect.x < 0) cairo_move_to(cr, -rect.x, 0);
10008 			pango_cairo_show_layout(cr, layout);
10009 			cairo_destroy(cr);
10010 			g_object_unref(layout);
10011 			*printops.is_approximate = false;
10012 			if(displayed_mstruct) displayed_mstruct->unref();
10013 			displayed_mstruct = new MathStructure(m);
10014 			displayed_printops = printops;
10015 			displayed_printops.allow_non_usable = true;
10016 			displayed_caf = complex_angle_form;
10017 		} else if(!b_stack) {
10018 			if(!CALCULATOR->aborted()) {
10019 				printops.allow_non_usable = true;
10020 				printops.can_display_unicode_string_arg = (void*) resultview;
10021 
10022 				MathStructure *displayed_mstruct_pre = new MathStructure(m);
10023 				if(printops.interval_display == INTERVAL_DISPLAY_INTERVAL) replace_interval_with_function(*displayed_mstruct_pre);
10024 				tmp_surface = draw_structure(*displayed_mstruct_pre, printops, complex_angle_form, top_ips, NULL, scale_tmp);
10025 				if(displayed_mstruct) displayed_mstruct->unref();
10026 				displayed_mstruct = displayed_mstruct_pre;
10027 				if(tmp_surface && CALCULATOR->aborted()) {
10028 					cairo_surface_destroy(tmp_surface);
10029 					tmp_surface = NULL;
10030 				}
10031 
10032 				printops.can_display_unicode_string_arg = NULL;
10033 				printops.allow_non_usable = false;
10034 			}
10035 			if(!tmp_surface && displayed_mstruct) {
10036 				displayed_mstruct->unref();
10037 				displayed_mstruct = NULL;
10038 			} else {
10039 				displayed_printops = printops;
10040 				displayed_printops.allow_non_usable = true;
10041 				displayed_caf = complex_angle_form;
10042 			}
10043 		}
10044 		result_autocalculated = false;
10045 		printops.use_unit_prefixes = b_puup;
10046 		b_busy = false;
10047 		CALCULATOR->stopControl();
10048 	}
10049 }
10050 
on_event(GtkWidget *,GdkEvent * e,gpointer)10051 gboolean on_event(GtkWidget*, GdkEvent *e, gpointer) {
10052 	if(e->type == GDK_EXPOSE || e->type == GDK_PROPERTY_NOTIFY || e->type == GDK_CONFIGURE || e->type == GDK_FOCUS_CHANGE || e->type == GDK_VISIBILITY_NOTIFY) {
10053 		return FALSE;
10054 	}
10055 	return TRUE;
10056 }
10057 
reload_history(gint from_index)10058 void reload_history(gint from_index) {
10059 	if(from_index < 0) gtk_list_store_clear(historystore);
10060 	string history_str;
10061 	GtkTreeIter history_iter;
10062 	size_t i = inhistory.size();
10063 	gint pos = 0;
10064 	while(i > 0 && (from_index < 0 || (i >= (size_t) from_index))) {
10065 		i--;
10066 		switch(inhistory_type[i]) {
10067 			case QALCULATE_HISTORY_RESULT_APPROXIMATE: {}
10068 			case QALCULATE_HISTORY_RESULT: {
10069 				history_str = "";
10070 				size_t trans_l = 0;
10071 				if(i + 1 < inhistory.size()  && inhistory_type[i + 1] == QALCULATE_HISTORY_TRANSFORMATION) {
10072 					history_str = inhistory[i + 1];
10073 					history_str += ":  ";
10074 					trans_l = history_str.length();
10075 				}
10076 				if(inhistory_type[i] == QALCULATE_HISTORY_RESULT_APPROXIMATE) {
10077 					if(printops.use_unicode_signs && can_display_unicode_string_function(SIGN_ALMOST_EQUAL, (void*) historyview)) {
10078 						history_str += SIGN_ALMOST_EQUAL;
10079 					} else {
10080 						history_str += "= ";
10081 						history_str += _("approx.");
10082 					}
10083 				} else {
10084 					history_str += "=";
10085 				}
10086 				history_str += " ";
10087 				size_t history_expr_i = history_str.length();
10088 				history_str += inhistory[i];
10089 				add_line_breaks(history_str, 2, history_expr_i);
10090 				fix_history_string2(history_str);
10091 				improve_result_text(history_str);
10092 				if(trans_l > 0) {
10093 					trans_l = history_str.find(":  ");
10094 					if(trans_l != string::npos) {
10095 						trans_l += 3;
10096 						history_str.insert(trans_l, "</span>");
10097 						history_str.insert(0, "<span font-style=\"italic\">");
10098 					}
10099 				}
10100 				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);
10101 				pos++;
10102 				break;
10103 			}
10104 			case QALCULATE_HISTORY_PARSE_APPROXIMATE: {}
10105 			case QALCULATE_HISTORY_PARSE: {
10106 				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)) {
10107 					if(i + 2 >= inhistory.size() || inhistory_type[i + 2] != QALCULATE_HISTORY_BOOKMARK) {
10108 						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++;}
10109 					}
10110 					if(!inhistory[i].empty()) {
10111 						string expr_str;
10112 						if(inhistory_type[i + 1] == QALCULATE_HISTORY_RPN_OPERATION) expr_str = ("RPN Operation");
10113 						else if(inhistory_type[i + 1] == QALCULATE_HISTORY_REGISTER_MOVED) expr_str = ("RPN Register Moved");
10114 						else expr_str = inhistory[i + 1];
10115 						history_str = fix_history_string(expr_str);
10116 						history_str += "<span font-style=\"italic\" foreground=\"";
10117 						history_str += history_parse_color;
10118 						history_str += "\">  ";
10119 						string str2;
10120 						if(inhistory_type[i] == QALCULATE_HISTORY_PARSE) {
10121 							str2 = "=";
10122 						} else {
10123 							if(printops.use_unicode_signs && can_display_unicode_string_function(SIGN_ALMOST_EQUAL, (void*) historyview)) {
10124 								str2 = SIGN_ALMOST_EQUAL;
10125 							} else {
10126 								str2 = _("approx.");
10127 							}
10128 						}
10129 						history_str += str2;
10130 						history_str += " ";
10131 						history_str += fix_history_string(inhistory[i]);
10132 						history_str += "</span>";
10133 						PangoLayout *layout = gtk_widget_create_pango_layout(historyview, "");
10134 						pango_layout_set_markup(layout, history_str.c_str(), -1);
10135 						gint w = 0;
10136 						pango_layout_get_pixel_size(layout, &w, NULL);
10137 						if(w > history_width_e) {
10138 							history_str = inhistory[i + 1];
10139 							add_line_breaks(history_str, 1, 0);
10140 							fix_history_string2(history_str);
10141 							str2 += " ";
10142 							size_t history_expr_i = str2.length();
10143 							str2 += inhistory[i];
10144 							add_line_breaks(str2, 3, history_expr_i);
10145 							fix_history_string2(str2);
10146 							history_str += '\n';
10147 							history_str += "<span font-style=\"italic\" foreground=\"";
10148 							history_str += history_parse_color;
10149 							history_str += "\">";
10150 							history_str += str2;
10151 							history_str += "</span>";
10152 						}
10153 						if(inhistory_protected[i + 1] || (i + 2 < inhistory.size() && inhistory_type[i + 2] == QALCULATE_HISTORY_BOOKMARK)) {
10154 							if(can_display_unicode_string_function_exact("��", historyview)) history_str += "<span size=\"small\"><sup> ��</sup></span>";
10155 							else history_str += "<span size=\"x-small\"><sup> P</sup></span>";
10156 						}
10157 						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);
10158 						pos++;
10159 						g_object_unref(layout);
10160 					}
10161 				}
10162 				break;
10163 			}
10164 			case QALCULATE_HISTORY_ERROR: {}
10165 			case QALCULATE_HISTORY_MESSAGE: {}
10166 			case QALCULATE_HISTORY_WARNING: {
10167 				string str = "- ";
10168 				str += inhistory[i];
10169 				add_line_breaks(str, false, 2);
10170 				fix_history_string2(str);
10171 				if(inhistory_type[i] == QALCULATE_HISTORY_MESSAGE) {
10172 					history_str = "<i>";
10173 				} else {
10174 					history_str = "<span foreground=\"";
10175 					if(inhistory_type[i] == QALCULATE_HISTORY_WARNING) history_str += history_warning_color;
10176 					else history_str += history_error_color;
10177 					history_str += "\">";
10178 				}
10179 				history_str += str;
10180 				if(inhistory_type[i] == QALCULATE_HISTORY_MESSAGE) history_str += "</i>";
10181 				else history_str += "</span>";
10182 				if(i + 2 < inhistory.size() && inhistory_type[i + 2] == QALCULATE_HISTORY_EXPRESSION && inhistory_protected[i + 2]) {
10183 					if(can_display_unicode_string_function_exact("��", historyview)) history_str += "<span size=\"small\"><sup> ��</sup></span>";
10184 					else history_str += "<span size=\"x-small\"><sup> P</sup></span>";
10185 				}
10186 				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);
10187 				pos++;
10188 				break;
10189 			}
10190 			case QALCULATE_HISTORY_BOOKMARK: {
10191 				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)) {
10192 					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++;}
10193 				}
10194 				string str = inhistory[i];
10195 				add_line_breaks(str, false);
10196 				fix_history_string2(str);
10197 				history_str = "<span foreground=\"";
10198 				history_str += history_bookmark_color;
10199 				history_str += "\">";
10200 				history_str += str;
10201 				history_str += ":";
10202 				history_str += "</span>";
10203 				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);
10204 				pos++;
10205 				break;
10206 			}
10207 			default: {}
10208 		}
10209 	}
10210 	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++;}
10211 }
10212 
add_line_breaks(string & str,int expr,size_t first_i)10213 void add_line_breaks(string &str, int expr, size_t first_i) {
10214 	PangoLayout *layout = gtk_widget_create_pango_layout(historyview, "");
10215 	PangoFontDescription *font_desc = NULL;
10216 	if(expr == 3) {
10217 		gtk_style_context_get(gtk_widget_get_style_context(historyview), GTK_STATE_FLAG_NORMAL, GTK_STYLE_PROPERTY_FONT, &font_desc, NULL);
10218 		pango_font_description_set_style(font_desc, PANGO_STYLE_ITALIC);
10219 		pango_layout_set_font_description(layout, font_desc);
10220 	}
10221 	int r = 1;
10222 	size_t i_row = 0;
10223 	size_t indent = 0;
10224 	size_t lb_point = string::npos;
10225 	size_t c = 0;
10226 	int b_or = 0;
10227 	int history_width = (expr == 2 ? history_width_a : history_width_e);
10228 	if(expr > 1 && str.find("||") != string::npos) b_or = 2;
10229 	else if(expr > 1 && str.find(_("or")) != string::npos) b_or = 1;
10230 	for(size_t i = first_i; i < str.length(); i++) {
10231 		if(r != 1 && i - i_row <= indent) {
10232 			if(str[i] == ' ') {
10233 				str.erase(i, 1);
10234 				if(i >= str.length()) i = str.length() - 1;
10235 			} else if(str[i] == -30 && i + 2 < str.length() && str[i + 1] == -128 && str[i + 2] == -119) {
10236 				str.erase(i, 3);
10237 				if(i >= str.length()) i = str.length() - 1;
10238 			}
10239 		}
10240 		if(str[i] > 0 || (unsigned char) str[i] >= 0xC0 || i == str.length() - 1) {
10241 			if(str[i] == '\n') {
10242 				r++;
10243 				i_row = i + 1;
10244 				lb_point = string::npos;
10245 			} else {
10246 				if(i - i_row > indent) {
10247 					if(is_in(" \t", str[i]) && i + 1 < str.length() && (is_not_in("0123456789", str[i + 1]) || is_not_in("0123456789", str[i - 1]))) {
10248 						if(b_or == 1 && str.length() > i + strlen("or") + 2 && str.substr(i + 1, strlen(_("or"))) == _("or") && str[i + strlen(_("or")) + 1] == ' ') {
10249 							i = i + strlen(_("or")) + 1;
10250 							str[i] = '\n';
10251 							i_row = i + 1;
10252 							lb_point = string::npos;
10253 							c = 0;
10254 						} else if(b_or == 2 && str.length() > i + 2 + 2 && str.substr(i + 1, 2) == "||" && str[i + 2 + 1] == ' ') {
10255 							i = i + 2 + 1;
10256 							str[i] = '\n';
10257 							i_row = i + 1;
10258 							lb_point = string::npos;
10259 							c = 0;
10260 						} else if(c > 10) {
10261 							string teststr = str.substr(i_row, i - i_row);
10262 							pango_layout_set_text(layout, teststr.c_str(), -1);
10263 							gint w = 0;
10264 							pango_layout_get_pixel_size(layout, &w, NULL);
10265 							if(w > history_width) {
10266 								bool cbreak = lb_point == string::npos;
10267 								if(!cbreak && expr) {
10268 									teststr = str.substr(i_row, lb_point - i_row);
10269 									pango_layout_set_text(layout, teststr.c_str(), -1);
10270 									pango_layout_get_pixel_size(layout, &w, NULL);
10271 									cbreak = (w > history_width || w < history_width / 3);
10272 									if(w <= history_width) teststr = str.substr(i_row, i - i_row);
10273 								}
10274 								if(cbreak) {
10275 									while(true) {
10276 										while(teststr[teststr.length() - 1] <= 0 && (unsigned char) teststr[teststr.length() - 1] < 0xC0) {
10277 											i--;
10278 											teststr.erase(teststr.length() - 1, 1);
10279 											if(i == i_row) return;
10280 										}
10281 										i--;
10282 										teststr.erase(teststr.length() - 1, 1);
10283 										if(i == i_row) return;
10284 										pango_layout_set_text(layout, teststr.c_str(), -1);
10285 										pango_layout_get_pixel_size(layout, &w, NULL);
10286 										if(w <= history_width) {
10287 											i++;
10288 											if(str[i - 1] == ' ') {
10289 												i--;
10290 											} else if(str[i - 1] == -30 && i + 1 < str.length() && str[i] == -128 && str[i + 1] == -119) {
10291 												i--;
10292 											} else if(i > 3 && str[i - 1] == -119 && str[i - 2] == -128 && str[i - 3] == -30) {
10293 												i -= 3;
10294 											} else if(i > 3 && str[i] <= '9' && str[i] >= '0' && str[i - 1] <= '9' && str[i - 1] >= '0') {
10295 												if(str[i - 2] == ' ' && str[i - 3] <= '9' && str[i - 3] >= '0') i -= 2;
10296 												else if(str[i - 3] == ' ' && str[i - 4] <= '9' && str[i - 4] >= '0') i -= 3;
10297 												else if((str[i - 2] == '.' || str[i - 2] == ',') && str[i - 3] <= '9' && str[i - 3] >= '0') i--;
10298 												else if((str[i - 3] == '.' || str[i - 3] == ',') && str[i - 4] <= '9' && str[i - 4] >= '0') i -= 2;
10299 												else if(teststr.length() > 6) {
10300 													size_t i2 = teststr.find(THIN_SPACE, teststr.length() - 6);
10301 													if(i2 != string::npos && i2 > 0 && teststr[i2 - 1] <= '9' && teststr[i2 - 1] >= '0') {
10302 														i = i2 + i_row;
10303 													}
10304 												}
10305 											} 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') {
10306 												i -= 3;
10307 											}
10308 											str.insert(i, "\n");
10309 											i_row = i + 1;
10310 											r++;
10311 											lb_point = string::npos;
10312 											break;
10313 										}
10314 									}
10315 								} else {
10316 									str[lb_point] = '\n';
10317 									i = lb_point;
10318 									i_row = i + 1;
10319 									r++;
10320 									lb_point = string::npos;
10321 								}
10322 								c = 0;
10323 							} else {
10324 								lb_point = i;
10325 								c++;
10326 							}
10327 						}
10328 					} else if(i + 1 == str.length() || (c >= 50 && c % 50 == 0)) {
10329 						string teststr;
10330 						if(str[i] <= 0) {
10331 							while(i + 1 < str.length() && str[i + 1] <= 0 && (unsigned char) str[i + 1] < 0xC0) i++;
10332 						}
10333 						if(i + 1 == str.length()) teststr = str.substr(i_row);
10334 						else teststr = str.substr(i_row, i - i_row + 1);
10335 						pango_layout_set_text(layout, teststr.c_str(), -1);
10336 						gint w = 0;
10337 						pango_layout_get_pixel_size(layout, &w, NULL);
10338 						if(w > history_width) {
10339 							bool cbreak = lb_point == string::npos;
10340 							if(!cbreak && expr) {
10341 								teststr = str.substr(i_row, lb_point - i_row);
10342 								pango_layout_set_text(layout, teststr.c_str(), -1);
10343 								pango_layout_get_pixel_size(layout, &w, NULL);
10344 								cbreak = (w > history_width || w < history_width / 3);
10345 								if(w <= history_width) {
10346 									if(i + 1 == str.length()) teststr = str.substr(i_row);
10347 									else teststr = str.substr(i_row, i - i_row + 1);
10348 								}
10349 							}
10350 							if(cbreak) {
10351 								while(true) {
10352 									while(teststr[teststr.length() - 1] <= 0 && (unsigned char) teststr[teststr.length() - 1] < 0xC0) {
10353 										i--;
10354 										teststr.erase(teststr.length() - 1, 1);
10355 										if(i == i_row) return;
10356 									}
10357 									i--;
10358 									teststr.erase(teststr.length() - 1, 1);
10359 									if(i == i_row) return;
10360 									pango_layout_set_text(layout, teststr.c_str(), -1);
10361 									pango_layout_get_pixel_size(layout, &w, NULL);
10362 									if(w <= history_width) {
10363 										i++;
10364 										if(str[i - 1] == ' ') {
10365 											i--;
10366 										} else if(str[i - 1] == -30 && i + 1 < str.length() && str[i] == -128 && str[i + 1] == -119) {
10367 											i--;
10368 										} else if(i > 3 && str[i - 1] == -119 && str[i - 2] == -128 && str[i - 3] == -30) {
10369 											i -= 3;
10370 										} else if(i > 3 && str[i] <= '9' && str[i] >= '0' && str[i - 1] <= '9' && str[i - 1] >= '0') {
10371 											if(str[i - 2] == ' ' && str[i - 3] <= '9' && str[i - 3] >= '0') i -= 2;
10372 											else if(str[i - 3] == ' ' && str[i - 4] <= '9' && str[i - 4] >= '0') i -= 3;
10373 											else if((str[i - 2] == '.' || str[i - 2] == ',') && str[i - 3] <= '9' && str[i - 3] >= '0') i--;
10374 											else if((str[i - 3] == '.' || str[i - 3] == ',') && str[i - 4] <= '9' && str[i - 4] >= '0') i -= 2;
10375 											else if(teststr.length() > 6) {
10376 												size_t i2 = teststr.find(THIN_SPACE, teststr.length() - 6);
10377 												if(i2 != string::npos && i2 > 0 && teststr[i2 - 1] <= '9' && teststr[i2 - 1] >= '0') {
10378 													i = i2 + i_row;
10379 												}
10380 											}
10381 										} 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') {
10382 											i -= 3;
10383 										}
10384 										str.insert(i, "\n");
10385 										i_row = i + 1;
10386 										r++;
10387 										lb_point = string::npos;
10388 										break;
10389 									}
10390 								}
10391 							} else {
10392 								str[lb_point] = '\n';
10393 								i = lb_point;
10394 								i_row = i + 1;
10395 								r++;
10396 								lb_point = string::npos;
10397 							}
10398 							c = 0;
10399 						} else {
10400 							c++;
10401 						}
10402 					} else {
10403 						c++;
10404 					}
10405 				}
10406 			}
10407 		}
10408 	}
10409 	g_object_unref(layout);
10410 	if(font_desc) pango_font_description_free(font_desc);
10411 }
10412 
create_base_string(string & str1,int b_almost_equal,bool b_small)10413 void create_base_string(string &str1, int b_almost_equal, bool b_small) {
10414 	if(b_small) str1 = "<small>";
10415 	else str1 = "";
10416 	if(b_almost_equal == 0) {
10417 		str1 += "=";
10418 	} else if(b_almost_equal == 1) {
10419 		str1 += SIGN_ALMOST_EQUAL;
10420 		b_almost_equal = true;
10421 	} else {
10422 		str1 += "= ";
10423 		str1 += _("approx.");
10424 	}
10425 	str1 += " ";
10426 	PangoFontDescription *font_desc;
10427 	gtk_style_context_get(gtk_widget_get_style_context(result_bases), GTK_STATE_FLAG_NORMAL, GTK_STYLE_PROPERTY_FONT, &font_desc, NULL);
10428 #define SUB_STRING2(X) b_small ? string("<span size=\"xx-small\" rise=\"" + i2s((int) (-pango_font_description_get_size(font_desc) / 5)) + "\">") + string(X) + "</span>" : string("<span size=\"x-small\" rise=\"" + i2s((int) (-pango_font_description_get_size(font_desc) / 2.5)) + "\">") + string(X) + "</span>"
10429 	if(printops.base != 16) {
10430 		str1 += result_hex;
10431 		if(printops.hexadecimal_twos_complement && (mstruct->isNegate() || mstruct->number().isNegative())) str1 += SUB_STRING2("16-");
10432 		else str1 += SUB_STRING2("16");
10433 	}
10434 	if(printops.base != 10) {
10435 		if(printops.base != 16) {
10436 			if(b_almost_equal) str1 += " " SIGN_ALMOST_EQUAL " ";
10437 			else str1 += " = ";
10438 		}
10439 		str1 += result_dec;
10440 		str1 += SUB_STRING2("10");
10441 	}
10442 	if(printops.base != 8) {
10443 		if(b_almost_equal) str1 += " " SIGN_ALMOST_EQUAL " ";
10444 		else str1 += " = ";
10445 		str1 += result_oct;
10446 		str1 += SUB_STRING2("8");
10447 	}
10448 	if(printops.base != 2) {
10449 		if(b_almost_equal) str1 += " " SIGN_ALMOST_EQUAL " ";
10450 		else str1 += " = ";
10451 		str1 += result_bin;
10452 		if(printops.twos_complement && (mstruct->isNegate() || mstruct->number().isNegative())) str1 += SUB_STRING2("2-");
10453 		else str1 += SUB_STRING2("2");
10454 	}
10455 	if(b_small) str1 += "</small>";
10456 	pango_font_description_free(font_desc);
10457 }
10458 
update_result_bases()10459 void update_result_bases() {
10460 	if(!result_hex.empty() || !result_dec.empty() || !result_oct.empty() || !result_bin.empty()) {
10461 		string str1, str2;
10462 		int b_almost_equal = -1;
10463 		if(mstruct->isInteger() || (mstruct->isNegate() && mstruct->getChild(1)->isInteger())) {
10464 			b_almost_equal = 0;
10465 		} else if(printops.use_unicode_signs && can_display_unicode_string_function(SIGN_ALMOST_EQUAL, (void*) historyview)) {
10466 			b_almost_equal = 1;
10467 		}
10468 		create_base_string(str1, b_almost_equal, false);
10469 		bool use_str2 = false;
10470 		if(two_result_bases_rows != 0) {
10471 			PangoLayout *layout = gtk_widget_create_pango_layout(result_bases, "");
10472 			pango_layout_set_markup(layout, str1.c_str(), -1);
10473 			gint w = 0;
10474 			pango_layout_get_pixel_size(layout, &w, NULL);
10475 			g_object_unref(layout);
10476 			if(w + 12 > gtk_widget_get_allocated_width(GTK_WIDGET(gtk_builder_get_object(main_builder, "stack_keypad_top")))) {
10477 				size_t i;
10478 				if(two_result_bases_rows == 2) {
10479 					create_base_string(str2, b_almost_equal, true);
10480 					if(b_almost_equal == 1) i = str2.rfind(" " SIGN_ALMOST_EQUAL " ");
10481 					else i = str2.rfind(" = ");
10482 					if(i != string::npos) str2[i] = '\n';
10483 					use_str2 = true;
10484 				} else {
10485 					if(b_almost_equal == 1) i = str1.rfind(" " SIGN_ALMOST_EQUAL " ");
10486 					else i = str1.rfind(" = ");
10487 					if(i != string::npos) str1[i] = '\n';
10488 				}
10489 #if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 16
10490 				gtk_label_set_yalign(GTK_LABEL(result_bases), 0.0);
10491 #else
10492 				gtk_misc_set_alignment(GTK_MISC(result_bases), 1.0, 0.0);
10493 #endif
10494 				if(two_result_bases_rows < 0) {
10495 					layout = gtk_widget_create_pango_layout(result_bases, "");
10496 					pango_layout_set_markup(layout, str1.c_str(), -1);
10497 					gint h = 0;
10498 					pango_layout_get_pixel_size(layout, NULL, &h);
10499 					if(h + 3 > gtk_widget_get_allocated_height(GTK_WIDGET(gtk_builder_get_object(main_builder, "stack_keypad_top")))) {
10500 						create_base_string(str2, b_almost_equal, true);
10501 						size_t i2;
10502 						if(b_almost_equal == 1) i2 = str2.rfind(" " SIGN_ALMOST_EQUAL " ");
10503 						else i2 = str2.rfind(" = ");
10504 						if(i2 != string::npos) str2[i2] = '\n';
10505 						pango_layout_set_markup(layout, str2.c_str(), -1);
10506 						pango_layout_get_pixel_size(layout, NULL, &h);
10507 						if(h + 3 > gtk_widget_get_allocated_height(GTK_WIDGET(gtk_builder_get_object(main_builder, "stack_keypad_top")))) {
10508 							two_result_bases_rows = 0;
10509 							if(i != string::npos) str1[i] = ' ';
10510 #if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 16
10511 							gtk_label_set_yalign(GTK_LABEL(result_bases), 0.5);
10512 #else
10513 							gtk_misc_set_alignment(GTK_MISC(result_bases), 1.0, 0.5);
10514 #endif
10515 						} else {
10516 							use_str2 = true;
10517 							two_result_bases_rows = 2;
10518 						}
10519 					} else {
10520 						two_result_bases_rows = 1;
10521 					}
10522 					g_object_unref(layout);
10523 				}
10524 			} else {
10525 #if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 16
10526 				gtk_label_set_yalign(GTK_LABEL(result_bases), 0.5);
10527 #else
10528 				gtk_misc_set_alignment(GTK_MISC(result_bases), 1.0, 0.5);
10529 #endif
10530 			}
10531 		}
10532 		gtk_label_set_markup(GTK_LABEL(result_bases), use_str2 ? str2.c_str() : str1.c_str());
10533 		if(b_almost_equal) gsub(" " SIGN_ALMOST_EQUAL " ", "\n" SIGN_ALMOST_EQUAL " ", str1);
10534 		else gsub(" = ", "\n= ", str1);
10535 		gtk_widget_set_tooltip_markup(result_bases, str1.c_str());
10536 	} else {
10537 		gtk_label_set_text(GTK_LABEL(result_bases), "");
10538 		gtk_widget_set_tooltip_markup(result_bases, "");
10539 	}
10540 }
10541 
update_window_title(const char * str,bool is_result)10542 bool update_window_title(const char *str, bool is_result) {
10543 	if(title_modified || !main_builder) return false;
10544 	switch(title_type) {
10545 		case TITLE_MODE: {
10546 			if(is_result) return false;
10547 			if(str && !current_mode.empty()) gtk_window_set_title(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), (current_mode + string(": ") + str).c_str());
10548 			else if(!current_mode.empty()) gtk_window_set_title(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), current_mode.c_str());
10549 			else if(str) gtk_window_set_title(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), (string("Qalculate! ") + str).c_str());
10550 			else gtk_window_set_title(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), _("Qalculate!"));
10551 			break;
10552 		}
10553 		case TITLE_APP_MODE: {
10554 			if(is_result || (!current_mode.empty() && str)) return false;
10555 			if(!current_mode.empty()) gtk_window_set_title(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), (string("Qalculate! ") + current_mode).c_str());
10556 			else if(str) gtk_window_set_title(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), (string("Qalculate! ") + str).c_str());
10557 			else gtk_window_set_title(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), _("Qalculate!"));
10558 			break;
10559 		}
10560 		case TITLE_RESULT: {
10561 			if(!str) return false;
10562 			if(str) gtk_window_set_title(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), str);
10563 			break;
10564 		}
10565 		case TITLE_APP_RESULT: {
10566 			if(str) gtk_window_set_title(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), (string("Qalculate! (") + string(str) + ")").c_str());
10567 			break;
10568 		}
10569 		default: {
10570 			if(is_result) return false;
10571 			if(str) gtk_window_set_title(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), (string("Qalculate! ") + str).c_str());
10572 			else gtk_window_set_title(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), _("Qalculate!"));
10573 		}
10574 	}
10575 	return true;
10576 }
10577 
10578 /*
10579 	set result in result widget and add to history widget
10580 */
setResult(Prefix * prefix,bool update_history,bool update_parse,bool force,string transformation,size_t stack_index,bool register_moved,bool supress_dialog)10581 void setResult(Prefix *prefix, bool update_history, bool update_parse, bool force, string transformation, size_t stack_index, bool register_moved, bool supress_dialog) {
10582 
10583 	if(block_result_update || exit_in_progress) return;
10584 
10585 	if(expression_has_changed && (!rpn_mode || CALCULATOR->RPNStackSize() == 0)) {
10586 		if(!force) return;
10587 		execute_expression();
10588 		if(!prefix) return;
10589 	}
10590 
10591 	if(rpn_mode && CALCULATOR->RPNStackSize() == 0) return;
10592 
10593 	if(nr_of_new_expressions == 0 && !register_moved && !update_parse && update_history) {
10594 		update_history = false;
10595 	}
10596 
10597 	if(b_busy || b_busy_result || b_busy_expression || b_busy_command) return;
10598 
10599 	if(!rpn_mode) stack_index = 0;
10600 
10601 	if(stack_index != 0) {
10602 		update_history = true;
10603 		update_parse = false;
10604 	}
10605 	if(register_moved) {
10606 		update_history = true;
10607 		update_parse = false;
10608 	}
10609 
10610 	bool error_icon = false;
10611 
10612 	int inhistory_index = 0;
10613 
10614 	if(update_parse && parsed_mstruct && parsed_mstruct->isFunction() && (parsed_mstruct->function() == CALCULATOR->f_error || parsed_mstruct->function() == CALCULATOR->f_warning || parsed_mstruct->function() == CALCULATOR->f_message)) {
10615 		history_index = -1;
10616 		inhistory_type.push_back(QALCULATE_HISTORY_PARSE);
10617 		inhistory_protected.push_back(false);
10618 		inhistory.push_back("");
10619 		inhistory_value.push_back(-1);
10620 		inhistory_type.push_back(QALCULATE_HISTORY_EXPRESSION);
10621 		inhistory_protected.push_back(false);
10622 		inhistory.push_back("");
10623 		inhistory_value.push_back(-1);
10624 		int inhistory_index = inhistory.size() - 2;
10625 		if(history_index >= 0) gtk_list_store_insert_with_values(historystore, NULL, history_index + 1, 1, -1, 5, history_scroll_width, 6, 1.0, 7, PANGO_ALIGN_RIGHT, -1);
10626 		block_update_expression_icons++;
10627 		clearresult();
10628 		block_update_expression_icons--;
10629 		while(gtk_events_pending()) gtk_main_iteration();
10630 		if(gtk_widget_get_realized(historyview)) {
10631 			GtkTreePath *path = gtk_tree_path_new_from_indices(0, -1);
10632 			gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(historyview), path, history_index_column, FALSE, 0, 0);
10633 			gtk_tree_view_scroll_to_point(GTK_TREE_VIEW(historyview), 0, 0);
10634 			gtk_tree_path_free(path);
10635 		}
10636 		clear_expression_text();
10637 		display_errors(&history_index, NULL, &inhistory_index, 1);
10638 		current_inhistory_index = inhistory_index;
10639 		return;
10640 	}
10641 
10642 	do_timeout = false;
10643 	b_busy = true;
10644 	b_busy_result = true;
10645 	display_aborted = false;
10646 
10647 	if(!view_thread->running && !view_thread->start()) {
10648 		b_busy = false;
10649 		b_busy_result = false;
10650 		do_timeout = true;
10651 		return;
10652 	}
10653 
10654 	GtkTreeIter history_iter;
10655 
10656 	bool b_rpn_operation = false;
10657 
10658 	if(update_history) {
10659 		if(update_parse || register_moved || current_inhistory_index < 0) {
10660 			if(register_moved) {
10661 				result_text = _("RPN Register Moved");
10662 				inhistory_type.push_back(QALCULATE_HISTORY_REGISTER_MOVED);
10663 				inhistory_protected.push_back(false);
10664 				inhistory.push_back("");
10665 				inhistory_value.push_back(nr_of_new_expressions);
10666 			} else {
10667 				remove_blank_ends(result_text);
10668 				gsub("\n", " ", result_text);
10669 				if(result_text == _("RPN Operation")) {
10670 					b_rpn_operation = true;
10671 					inhistory_type.push_back(QALCULATE_HISTORY_RPN_OPERATION);
10672 					inhistory_protected.push_back(false);
10673 					inhistory.push_back("");
10674 					inhistory_value.push_back(nr_of_new_expressions);
10675 				} else {
10676 					inhistory_type.push_back(QALCULATE_HISTORY_EXPRESSION);
10677 					inhistory_protected.push_back(false);
10678 					inhistory.push_back(result_text);
10679 					inhistory_value.push_back(nr_of_new_expressions);
10680 					if(adaptive_interval_display) {
10681 						string expression_str = get_expression_text();
10682 						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;
10683 						else if(parsed_mstruct && parsed_mstruct->containsFunction(CALCULATOR->f_interval)) printops.interval_display = INTERVAL_DISPLAY_INTERVAL;
10684 						else printops.interval_display = INTERVAL_DISPLAY_SIGNIFICANT_DIGITS;
10685 					}
10686 				}
10687 			}
10688 			nr_of_new_expressions++;
10689 			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);
10690 			gtk_list_store_insert_with_values(historystore, NULL, 1, 1, -1, 5, history_scroll_width, 6, 1.0, 7, PANGO_ALIGN_RIGHT, -1);
10691 			history_index = 0;
10692 			inhistory_index = inhistory.size() - 1;
10693 			history_parsed.push_back(NULL);
10694 			history_answer.push_back(NULL);
10695 		} else if(current_inhistory_index >= 0) {
10696 			inhistory_index = current_inhistory_index;
10697 			if(!transformation.empty()) {
10698 				string history_str = transformation;
10699 				history_str += ":";
10700 				add_line_breaks(history_str, 3, 0);
10701 				fix_history_string2(history_str);
10702 				improve_result_text(history_str);
10703 				history_str.insert(0, "<span font-style=\"italic\">");
10704 				history_str += "</span>";
10705 				history_index++;
10706 				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);
10707 				GtkTreeIter index_iter = history_iter;
10708 				gint index_hi = -1;
10709 				while(gtk_tree_model_iter_previous(GTK_TREE_MODEL(historystore), &index_iter)) {
10710 					gtk_tree_model_get(GTK_TREE_MODEL(historystore), &index_iter, 1, &index_hi, -1);
10711 					if(index_hi >= 0) {
10712 						gtk_list_store_set(historystore, &index_iter, 1, index_hi + 1, -1);
10713 					}
10714 				}
10715 				inhistory.insert(inhistory.begin() + inhistory_index, transformation);
10716 				inhistory_type.insert(inhistory_type.begin() + inhistory_index, QALCULATE_HISTORY_TRANSFORMATION);
10717 				inhistory_protected.insert(inhistory_protected.begin() + inhistory_index, false);
10718 				inhistory_value.insert(inhistory_value.begin() + inhistory_index, nr_of_new_expressions);
10719 			}
10720 		} else {
10721 			b_busy = false;
10722 			b_busy_result = false;
10723 			do_timeout = true;
10724 			return;
10725 		}
10726 		result_text = "?";
10727 	}
10728 
10729 	if(update_parse) {
10730 		parsed_text = "aborted";
10731 	}
10732 
10733 	if(stack_index == 0) {
10734 		block_update_expression_icons++;
10735 		clearresult();
10736 		block_update_expression_icons--;
10737 	}
10738 
10739 	scale_n = 0;
10740 
10741 	gint w = 0, h = 0;
10742 	bool parsed_approx = false;
10743 	bool title_set = false, was_busy = false;
10744 
10745 	Number save_nbase;
10746 	bool custom_base_set = false;
10747 	int save_base = printops.base;
10748 	bool caf_bak = complex_angle_form;
10749 	unsigned int save_bits = printops.binary_bits;
10750 	bool save_pre = printops.use_unit_prefixes;
10751 	bool save_cur = printops.use_prefixes_for_currencies;
10752 	bool save_allu = printops.use_prefixes_for_all_units;
10753 	bool save_all = printops.use_all_prefixes;
10754 	bool save_den = printops.use_denominator_prefix;
10755 	int save_bin = CALCULATOR->usesBinaryPrefixes();
10756 	NumberFractionFormat save_format = printops.number_fraction_format;
10757 	bool save_restrict_fraction_length = printops.restrict_fraction_length;
10758 	bool do_to = false;
10759 	bool result_cleared = false;
10760 
10761 	if(stack_index == 0) {
10762 		if(to_base != 0 || to_fraction || to_prefix != 0 || (to_caf >= 0 && to_caf != complex_angle_form)) {
10763 			if(to_base != 0 && (to_base != printops.base || to_bits != printops.binary_bits || (to_base == BASE_CUSTOM && to_nbase != CALCULATOR->customOutputBase()))) {
10764 				printops.base = to_base;
10765 				printops.binary_bits = to_bits;
10766 				if(to_base == BASE_CUSTOM) {
10767 					custom_base_set = true;
10768 					save_nbase = CALCULATOR->customOutputBase();
10769 					CALCULATOR->setCustomOutputBase(to_nbase);
10770 				}
10771 				do_to = true;
10772 			}
10773 			if(to_fraction && (printops.restrict_fraction_length || printops.number_fraction_format != FRACTION_COMBINED)) {
10774 				printops.restrict_fraction_length = false;
10775 				printops.number_fraction_format = FRACTION_COMBINED;
10776 				do_to = true;
10777 			}
10778 			if(to_caf >= 0 && to_caf != complex_angle_form) {
10779 				complex_angle_form = to_caf;
10780 				do_to = true;
10781 			}
10782 			if(to_prefix != 0 && !prefix) {
10783 				bool new_pre = printops.use_unit_prefixes;
10784 				bool new_cur = printops.use_prefixes_for_currencies;
10785 				bool new_allu = printops.use_prefixes_for_all_units;
10786 				bool new_all = printops.use_all_prefixes;
10787 				bool new_den = printops.use_denominator_prefix;
10788 				int new_bin = CALCULATOR->usesBinaryPrefixes();
10789 				new_pre = true;
10790 				if(to_prefix == 'b') {
10791 					int i = has_information_unit_gtk(*mstruct);
10792 					new_bin = (i > 0 ? 1 : 2);
10793 					if(i == 1) {
10794 						new_den = false;
10795 					} else if(i > 1) {
10796 						new_den = true;
10797 					} else {
10798 						new_cur = true;
10799 						new_allu = true;
10800 					}
10801 				} else {
10802 					new_cur = true;
10803 					new_allu = true;
10804 					if(to_prefix == 'a') new_all = true;
10805 					else if(to_prefix == 'd') new_bin = 0;
10806 				}
10807 				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) {
10808 					printops.use_unit_prefixes = new_pre;
10809 					printops.use_all_prefixes = new_all;
10810 					printops.use_prefixes_for_currencies = new_cur;
10811 					printops.use_prefixes_for_all_units = new_allu;
10812 					printops.use_denominator_prefix = new_den;
10813 					CALCULATOR->useBinaryPrefixes(new_bin);
10814 					do_to = true;
10815 				}
10816 			}
10817 		}
10818 		if(surface_result) {
10819 			cairo_surface_destroy(surface_result);
10820 			surface_result = NULL;
10821 			result_cleared = true;
10822 		}
10823 		date_map.clear();
10824 		number_map.clear();
10825 		number_base_map.clear();
10826 		number_exp_map.clear();
10827 		number_exp_minus_map.clear();
10828 		number_approx_map.clear();
10829 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "menu_item_save_image")), FALSE);
10830 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_save_image")), FALSE);
10831 	}
10832 
10833 	printops.prefix = prefix;
10834 	tmp_surface = NULL;
10835 
10836 	if(!view_thread->write(scale_n)) {b_busy = false; b_busy_result = false; do_timeout = true; return;}
10837 	if(stack_index == 0) {
10838 		if(!view_thread->write((void *) mstruct)) {b_busy = false; b_busy_result = false; do_timeout = true; return;}
10839 	} else {
10840 		MathStructure *mreg = CALCULATOR->getRPNRegister(stack_index + 1);
10841 		if(!view_thread->write((void *) mreg)) {b_busy = false; b_busy_result = false; do_timeout = true; return;}
10842 	}
10843 	bool b_stack = stack_index != 0;
10844 	if(!view_thread->write(b_stack)) {b_busy = false; b_busy_result = false; do_timeout = true; return;}
10845 	if(b_stack) {
10846 		if(!view_thread->write(NULL)) {b_busy = false; b_busy_result = false; do_timeout = true; return;}
10847 	} else {
10848 		matrix_mstruct->clear();
10849 		if(!view_thread->write((void *) matrix_mstruct)) {b_busy = false; b_busy_result = false; do_timeout = true; return;}
10850 	}
10851 	if(update_parse) {
10852 		if(!view_thread->write((void *) parsed_mstruct)) {b_busy = false; b_busy_result = false; do_timeout = true; return;}
10853 		bool *parsed_approx_p = &parsed_approx;
10854 		if(!view_thread->write((void *) parsed_approx_p)) {b_busy = false; b_busy_result = false; do_timeout = true; return;}
10855 		if(!view_thread->write((void *) (b_rpn_operation ? NULL : parsed_tostruct))) {b_busy = false; b_busy_result = false; do_timeout = true; return;}
10856 	} else {
10857 		if(!view_thread->write(NULL)) {b_busy = false; b_busy_result = false; do_timeout = true; return;}
10858 	}
10859 
10860 	int i = 0;
10861 	while(b_busy && view_thread->running && i < 50) {
10862 		sleep_ms(10);
10863 		i++;
10864 	}
10865 	i = 0;
10866 
10867 	if(b_busy && view_thread->running) {
10868 		if(result_cleared) gtk_widget_queue_draw(resultview);
10869 		g_application_mark_busy(g_application_get_default());
10870 		update_expression_icons(stack_index == 0 ? (!minimal_mode ? RESULT_SPINNER : EXPRESSION_SPINNER) : EXPRESSION_STOP);
10871 		if(minimal_mode) gtk_spinner_start(GTK_SPINNER(gtk_builder_get_object(main_builder, "resultspinner")));
10872 		else gtk_spinner_start(GTK_SPINNER(gtk_builder_get_object(main_builder, "expressionspinner")));
10873 		if(update_window_title(_("Processing…"))) title_set = true;
10874 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "menubar")), FALSE);
10875 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "buttons")), FALSE);
10876 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "convert")), FALSE);
10877 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "historyview")), FALSE);
10878 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "historyactions")), FALSE);
10879 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "rpntab")), FALSE);
10880 		was_busy = true;
10881 	}
10882 	while(b_busy && view_thread->running) {
10883 		while(gtk_events_pending()) gtk_main_iteration();
10884 		sleep_ms(100);
10885 	}
10886 	b_busy = true;
10887 	b_busy_result = true;
10888 
10889 	if(stack_index == 0) {
10890 		display_aborted = !tmp_surface;
10891 		if(display_aborted) {
10892 			PangoLayout *layout = gtk_widget_create_pango_layout(resultview, NULL);
10893 			pango_layout_set_markup(layout, _("result processing was aborted"), -1);
10894 			pango_layout_get_pixel_size(layout, &w, &h);
10895 			gint scalefactor = gtk_widget_get_scale_factor(expressiontext);
10896 			tmp_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
10897 			cairo_surface_set_device_scale(tmp_surface, scalefactor, scalefactor);
10898 			cairo_t *cr = cairo_create(tmp_surface);
10899 			GdkRGBA rgba;
10900 			gtk_style_context_get_color(gtk_widget_get_style_context(resultview), gtk_widget_get_state_flags(resultview), &rgba);
10901 			gdk_cairo_set_source_rgba(cr, &rgba);
10902 			pango_cairo_show_layout(cr, layout);
10903 			cairo_destroy(cr);
10904 			g_object_unref(layout);
10905 			*printops.is_approximate = false;
10906 		}
10907 	}
10908 
10909 	if(was_busy) {
10910 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "menubar")), TRUE);
10911 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "buttons")), TRUE);
10912 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "convert")), TRUE);
10913 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "historyview")), TRUE);
10914 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "historyactions")), TRUE);
10915 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "rpntab")), TRUE);
10916 		if(!update_parse && stack_index == 0) hide_expression_spinner();
10917 		if(title_set && stack_index != 0) update_window_title();
10918 		if(minimal_mode) gtk_spinner_stop(GTK_SPINNER(gtk_builder_get_object(main_builder, "resultspinner")));
10919 		else gtk_spinner_stop(GTK_SPINNER(gtk_builder_get_object(main_builder, "expressionspinner")));
10920 		g_application_unmark_busy(g_application_get_default());
10921 	}
10922 
10923 	if(stack_index == 0) {
10924 		if(visible_keypad & PROGRAMMING_KEYPAD) update_result_bases();
10925 		surface_result = NULL;
10926 		if(tmp_surface) {
10927 			showing_first_time_message = FALSE;
10928 			first_draw_of_result = TRUE;
10929 			surface_result = tmp_surface;
10930 			if(minimal_mode && !gtk_widget_is_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "resultoverlay")))) {
10931 				gint h = -1;
10932 				gtk_widget_get_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "expressionscrolled")), NULL, &h);
10933 				gtk_widget_set_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "expressionscrolled")), -1, gtk_widget_get_allocated_height(GTK_WIDGET(gtk_builder_get_object(main_builder, "expressionscrolled"))));
10934 				set_status_bottom_border_visible(true);
10935 				gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(main_builder, "resultoverlay")));
10936 				while(gtk_events_pending()) gtk_main_iteration();
10937 				gtk_widget_set_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "expressionscrolled")), -1, h);
10938 			}
10939 			gtk_widget_queue_draw(resultview);
10940 			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "menu_item_save_image")), displayed_mstruct && !display_aborted);
10941 			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_save_image")), displayed_mstruct && !display_aborted);
10942 		}
10943 		if(!update_window_title(result_text.c_str(), true) && title_set) update_window_title();
10944 	}
10945 	if(register_moved) {
10946 		update_parse = true;
10947 		parsed_text = result_text;
10948 	}
10949 	if(current_inhistory_index < 0) {
10950 		update_parse = true;
10951 		current_inhistory_index = 0;
10952 	}
10953 	bool do_scroll = false;
10954 	if(stack_index != 0) {
10955 		if(result_text.length() > 500000) {
10956 			result_text = "(…)";
10957 		}
10958 		RPNRegisterChanged(result_text, stack_index);
10959 		error_icon = display_errors(NULL, supress_dialog ? NULL : GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")), NULL, supress_dialog ? 2 : 0);
10960 	} else if(update_history) {
10961 		if(result_text.length() > 500000) {
10962 			result_text = "(…)";
10963 		}
10964 		if(parsed_text.length() > 500000) {
10965 			parsed_text = "(…)";
10966 		}
10967 		if(update_parse) {
10968 			gchar *expr_str = NULL;
10969 			gtk_tree_model_get(GTK_TREE_MODEL(historystore), &history_iter, 0, &expr_str, -1);
10970 			string str = expr_str;
10971 			str += "<span font-style=\"italic\" foreground=\"";
10972 			str += history_parse_color;
10973 			str += "\">  ";
10974 			string str2;
10975 			if(!parsed_approx) {
10976 				str2 = "=";
10977 				inhistory_type.insert(inhistory_type.begin() + inhistory_index, QALCULATE_HISTORY_PARSE);
10978 				inhistory_protected.insert(inhistory_protected.begin() + inhistory_index, false);
10979 				inhistory_value.insert(inhistory_value.begin() + inhistory_index, nr_of_new_expressions);
10980 			} else {
10981 				if(printops.use_unicode_signs && can_display_unicode_string_function(SIGN_ALMOST_EQUAL, (void*) historyview)) {
10982 					str2 = SIGN_ALMOST_EQUAL;
10983 				} else {
10984 					str2 = _("approx.");
10985 				}
10986 				inhistory_type.insert(inhistory_type.begin() + inhistory_index, QALCULATE_HISTORY_PARSE_APPROXIMATE);
10987 				inhistory_protected.insert(inhistory_protected.begin() + inhistory_index, false);
10988 				inhistory_value.insert(inhistory_value.begin() + inhistory_index, nr_of_new_expressions);
10989 			}
10990 			str += str2;
10991 			str += " ";
10992 			str += fix_history_string(parsed_text);
10993 			str += "</span>";
10994 			inhistory.insert(inhistory.begin() + inhistory_index, parsed_text);
10995 			if(nr_of_new_expressions > 0 && parsed_mstruct && !history_parsed[nr_of_new_expressions - 1]) {
10996 				history_parsed[nr_of_new_expressions - 1] = new MathStructure(*parsed_mstruct);
10997 			}
10998 			PangoLayout *layout = gtk_widget_create_pango_layout(historyview, "");
10999 			pango_layout_set_markup(layout, str.c_str(), -1);
11000 			gint w = 0;
11001 			pango_layout_get_pixel_size(layout, &w, NULL);
11002 			if(w > history_width_e) {
11003 				str = expr_str;
11004 				unfix_history_string(str);
11005 				add_line_breaks(str, 1, 0);
11006 				fix_history_string2(str);
11007 				str2 += " ";
11008 				size_t history_expr_i = str2.length();
11009 				str2 += parsed_text;
11010 				add_line_breaks(str2, 3, history_expr_i);
11011 				fix_history_string2(str2);
11012 				str += '\n';
11013 				str += "<span font-style=\"italic\" foreground=\"";
11014 				str += history_parse_color;
11015 				str += "\">";
11016 				str += str2;
11017 				str += "</span>";
11018 			}
11019 			gtk_list_store_set(historystore, &history_iter, 0, str.c_str(), -1);
11020 			g_object_unref(layout);
11021 			g_free(expr_str);
11022 		}
11023 		int history_index_bak = history_index;
11024 		error_icon = display_errors(&history_index, supress_dialog ? NULL : GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")), &inhistory_index, 1);
11025 		if(rpn_mode && !register_moved) {
11026 			RPNRegisterChanged(result_text, stack_index);
11027 		}
11028 
11029 		string str;
11030 
11031 		bool b_approx = result_text_approximate || mstruct->isApproximate();
11032 		if(!b_approx) {
11033 			str = "=";
11034 		} else {
11035 			if(printops.use_unicode_signs && can_display_unicode_string_function(SIGN_ALMOST_EQUAL, (void*) historyview)) {
11036 				str = SIGN_ALMOST_EQUAL;
11037 			} else {
11038 				str = "= ";
11039 				str += _("approx.");
11040 			}
11041 		}
11042 		string history_str;
11043 		size_t trans_l = 0;
11044 		if(!update_parse && current_inhistory_index >= 0 && !transformation.empty() && history_index == history_index_bak) {
11045 			history_str = transformation;
11046 			history_str += ":  ";
11047 			trans_l = history_str.length();
11048 		}
11049 		history_str += str;
11050 		history_str += " ";
11051 		size_t history_expr_i = history_str.length();
11052 		history_str += result_text;
11053 		add_line_breaks(history_str, 2, history_expr_i);
11054 		fix_history_string2(history_str);
11055 		improve_result_text(history_str);
11056 		if(trans_l > 0) {
11057 			trans_l = history_str.find(":  ");
11058 			if(trans_l != string::npos) {
11059 				trans_l += 3;
11060 				history_str.insert(trans_l, "</span>");
11061 				history_str.insert(0, "<span font-style=\"italic\">");
11062 			}
11063 		}
11064 		if(!update_parse && current_inhistory_index >= 0 && !transformation.empty() && history_index_bak == history_index) {
11065 			gtk_list_store_set(historystore, &history_iter, 0, history_str.c_str(), 1, inhistory_index + 1, -1);
11066 		} else {
11067 			history_index++;
11068 			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);
11069 		}
11070 		inhistory.insert(inhistory.begin() + inhistory_index, result_text);
11071 		current_inhistory_index = inhistory_index;
11072 		if(b_approx) {
11073 			inhistory_type.insert(inhistory_type.begin() + inhistory_index, QALCULATE_HISTORY_RESULT_APPROXIMATE);
11074 		} else {
11075 			inhistory_type.insert(inhistory_type.begin() + inhistory_index, QALCULATE_HISTORY_RESULT);
11076 		}
11077 		inhistory_protected.insert(inhistory_protected.begin() + inhistory_index, false);
11078 		inhistory_value.insert(inhistory_value.begin() + inhistory_index, nr_of_new_expressions);
11079 		if(nr_of_new_expressions > 0 && mstruct && nr_of_new_expressions <= (int) history_answer.size()) {
11080 			if(!history_answer[nr_of_new_expressions - 1]) history_answer[nr_of_new_expressions - 1] = new MathStructure(*mstruct);
11081 			else history_answer[nr_of_new_expressions - 1]->set(*mstruct);
11082 		}
11083 
11084 		GtkTreeIter index_iter = history_iter;
11085 		gint index_hi = -1;
11086 		while(gtk_tree_model_iter_previous(GTK_TREE_MODEL(historystore), &index_iter)) {
11087 			gtk_tree_model_get(GTK_TREE_MODEL(historystore), &index_iter, 1, &index_hi, -1);
11088 			if(index_hi >= 0) {
11089 				gtk_list_store_set(historystore, &index_iter, 1, index_hi + 1, -1);
11090 			}
11091 		}
11092 
11093 		if(result_text.length() < 1000) {
11094 			str += " ";
11095 			if(result_text_long.empty()) {
11096 				str += result_text;
11097 			} else {
11098 				str += result_text_long;
11099 			}
11100 			gtk_widget_set_tooltip_text(resultview, str.length() < 1000 ? str.c_str() : "");
11101 		}
11102 		do_scroll = true;
11103 	} else {
11104 		int history_index_bak = history_index;
11105 		error_icon = display_errors(&history_index, supress_dialog ? NULL : GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")), &inhistory_index, 1);
11106 		do_scroll = (history_index != history_index_bak);
11107 	}
11108 	if(do_to) {
11109 		complex_angle_form = caf_bak;
11110 		printops.base = save_base;
11111 		printops.binary_bits = save_bits;
11112 		if(custom_base_set) CALCULATOR->setCustomOutputBase(save_nbase);
11113 		printops.use_unit_prefixes = save_pre;
11114 		printops.use_all_prefixes = save_all;
11115 		printops.use_prefixes_for_currencies = save_cur;
11116 		printops.use_prefixes_for_all_units = save_allu;
11117 		printops.use_denominator_prefix = save_den;
11118 		CALCULATOR->useBinaryPrefixes(save_bin);
11119 		printops.number_fraction_format = save_format;
11120 		printops.restrict_fraction_length = save_restrict_fraction_length;
11121 	}
11122 	printops.prefix = NULL;
11123 	b_busy = false;
11124 	b_busy_result = false;
11125 
11126 	while(gtk_events_pending()) gtk_main_iteration();
11127 	if(do_scroll && gtk_widget_get_realized(historyview)) {
11128 		GtkTreePath *path = gtk_tree_path_new_from_indices(0, -1);
11129 		gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(historyview), path, history_index_column, FALSE, 0, 0);
11130 		gtk_tree_view_scroll_to_point(GTK_TREE_VIEW(historyview), 0, 0);
11131 		gtk_tree_path_free(path);
11132 	}
11133 
11134 	if(!register_moved && stack_index == 0 && mstruct->isMatrix() && mstruct->rows() > 3 && matrix_mstruct->isMatrix() && matrix_mstruct->columns() < 200) {
11135 		while(gtk_events_pending()) gtk_main_iteration();
11136 		gtk_widget_grab_focus(expressiontext);
11137 		if(update_history && update_parse && force) {
11138 			GtkTextIter istart, iend;
11139 			gtk_text_buffer_get_start_iter(expressionbuffer, &istart);
11140 			gtk_text_buffer_get_end_iter(expressionbuffer, &iend);
11141 			gtk_text_buffer_select_range(expressionbuffer, &istart, &iend);
11142 			gtk_text_buffer_remove_tag(expressionbuffer, expression_par_tag, &istart, &iend);
11143 		}
11144 		if(!supress_dialog) insert_matrix(matrix_mstruct, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")), false, true, true);
11145 	}
11146 
11147 	if(!error_icon && (update_parse || stack_index != 0)) update_expression_icons(rpn_mode ? 0 : EXPRESSION_CLEAR);
11148 
11149 	do_timeout = true;
11150 
11151 }
11152 
on_abort_command(GtkDialog *,gint,gpointer)11153 void on_abort_command(GtkDialog*, gint, gpointer) {
11154 	CALCULATOR->abort();
11155 	int msecs = 5000;
11156 	while(b_busy && msecs > 0) {
11157 		sleep_ms(10);
11158 		msecs -= 10;
11159 	}
11160 	if(b_busy) {
11161 		command_thread->cancel();
11162 		b_busy = false;
11163 		CALCULATOR->stopControl();
11164 		command_aborted = true;
11165 	}
11166 }
11167 
run()11168 void CommandThread::run() {
11169 
11170 	enableAsynchronousCancel();
11171 
11172 	while(true) {
11173 		int command_type = 0;
11174 		if(!read(&command_type)) break;
11175 		void *x = NULL;
11176 		if(!read(&x)) break;
11177 		CALCULATOR->startControl();
11178 		switch(command_type) {
11179 			case COMMAND_FACTORIZE: {
11180 				if(!((MathStructure*) x)->integerFactorize()) {
11181 					((MathStructure*) x)->structure(STRUCTURING_FACTORIZE, evalops, true);
11182 				}
11183 				break;
11184 			}
11185 			case COMMAND_EXPAND_PARTIAL_FRACTIONS: {
11186 				((MathStructure*) x)->expandPartialFractions(evalops);
11187 				break;
11188 			}
11189 			case COMMAND_EXPAND: {
11190 				((MathStructure*) x)->expand(evalops);
11191 				break;
11192 			}
11193 			case COMMAND_TRANSFORM: {
11194 				string ceu_str;
11195 				if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "convert_button_continuous_conversion"))) && gtk_expander_get_expanded(GTK_EXPANDER(expander_convert)) && !minimal_mode) {
11196 					ParseOptions pa = evalops.parse_options; pa.base = 10;
11197 					ceu_str = CALCULATOR->unlocalizeExpression(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(main_builder, "convert_entry_unit"))), pa);
11198 					remove_blank_ends(ceu_str);
11199 					if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "convert_button_set_missing_prefixes"))) && !ceu_str.empty()) {
11200 						if(ceu_str[0] != '0' && ceu_str[0] != '?' && ceu_str[0] != '+' && ceu_str[0] != '-' && (ceu_str.length() == 1 || ceu_str[1] != '?')) {
11201 							ceu_str = "?" + ceu_str;
11202 						}
11203 					}
11204 					if(!ceu_str.empty() && ceu_str[0] == '?') {
11205 						to_prefix = 1;
11206 					} else if(ceu_str.length() > 1 && ceu_str[1] == '?' && (ceu_str[0] == 'b' || ceu_str[0] == 'a' || ceu_str[0] == 'd')) {
11207 						to_prefix = ceu_str[0];
11208 					}
11209 				}
11210 				((MathStructure*) x)->set(CALCULATOR->calculate(*((MathStructure*) x), evalops, ceu_str));
11211 				break;
11212 			}
11213 			case COMMAND_CONVERT_STRING: {
11214 				((MathStructure*) x)->set(CALCULATOR->convert(*((MathStructure*) x), command_convert_units_string, evalops));
11215 				break;
11216 			}
11217 			case COMMAND_CONVERT_UNIT: {
11218 				((MathStructure*) x)->set(CALCULATOR->convert(*((MathStructure*) x), command_convert_unit, evalops, false));
11219 				break;
11220 			}
11221 			case COMMAND_CONVERT_OPTIMAL: {
11222 				((MathStructure*) x)->set(CALCULATOR->convertToOptimalUnit(*((MathStructure*) x), evalops, true));
11223 				break;
11224 			}
11225 			case COMMAND_CONVERT_BASE: {
11226 				((MathStructure*) x)->set(CALCULATOR->convertToBaseUnits(*((MathStructure*) x), evalops));
11227 				break;
11228 			}
11229 			case COMMAND_CALCULATE: {
11230 				EvaluationOptions eo2 = evalops;
11231 				eo2.calculate_functions = false;
11232 				eo2.sync_units = false;
11233 				((MathStructure*) x)->calculatesub(eo2, eo2, true);
11234 				break;
11235 			}
11236 			case COMMAND_EVAL: {
11237 				((MathStructure*) x)->eval(evalops);
11238 				break;
11239 			}
11240 		}
11241 		b_busy = false;
11242 		CALCULATOR->stopControl();
11243 	}
11244 }
11245 
executeCommand(int command_type,bool show_result,string ceu_str,Unit * u,int run)11246 void executeCommand(int command_type, bool show_result, string ceu_str, Unit *u, int run) {
11247 
11248 	if(exit_in_progress) return;
11249 
11250 	if(run == 1) {
11251 
11252 		if(expression_has_changed && !rpn_mode && command_type != COMMAND_TRANSFORM) {
11253 			execute_expression();
11254 		}
11255 
11256 		if(b_busy || b_busy_result || b_busy_expression || b_busy_command) return;
11257 
11258 		if(command_type == COMMAND_CONVERT_UNIT || command_type == COMMAND_CONVERT_STRING) {
11259 			if(mbak_convert.isUndefined()) mbak_convert.set(*mstruct);
11260 			else mstruct->set(mbak_convert);
11261 		} else {
11262 			if(!mbak_convert.isUndefined()) mbak_convert.setUndefined();
11263 		}
11264 
11265 		do_timeout = false;
11266 		b_busy = true;
11267 		b_busy_command = true;
11268 		command_aborted = false;
11269 
11270 		if(command_type >= COMMAND_CONVERT_UNIT) {
11271 			CALCULATOR->resetExchangeRatesUsed();
11272 			command_convert_units_string = ceu_str;
11273 			command_convert_unit = u;
11274 		}
11275 		if(command_type == COMMAND_CONVERT_UNIT || command_type == COMMAND_CONVERT_STRING || command_type == COMMAND_CONVERT_BASE || command_type == COMMAND_CONVERT_OPTIMAL) {
11276 			to_prefix = 0;
11277 		}
11278 	}
11279 
11280 	bool title_set = false, was_busy = false;
11281 
11282 	int i = 0;
11283 
11284 	MathStructure *mfactor = new MathStructure(*mstruct);
11285 
11286 	rerun_command:
11287 
11288 	if(!command_thread->running && !command_thread->start()) {do_timeout = true; b_busy = false; b_busy_command = false; return;}
11289 
11290 	if(!command_thread->write(command_type)) {do_timeout = true; b_busy = false; b_busy_command = false; return;}
11291 	if(!command_thread->write((void *) mfactor)) {do_timeout = true; b_busy = false; b_busy_command = false; return;}
11292 
11293 	while(b_busy && command_thread->running && i < 50) {
11294 		sleep_ms(10);
11295 		i++;
11296 	}
11297 	i = 0;
11298 
11299 	cairo_surface_t *surface_result_bak = surface_result;
11300 
11301 	if(b_busy && command_thread->running) {
11302 		string progress_str;
11303 		switch(command_type) {
11304 			case COMMAND_FACTORIZE: {
11305 				progress_str = _("Factorizing…");
11306 				break;
11307 			}
11308 			case COMMAND_EXPAND_PARTIAL_FRACTIONS: {
11309 				progress_str = _("Expanding partial fractions…");
11310 				break;
11311 			}
11312 			case COMMAND_EXPAND: {
11313 				progress_str = _("Expanding…");
11314 				break;
11315 			}
11316 			case COMMAND_EVAL: {}
11317 			case COMMAND_TRANSFORM: {
11318 				progress_str = _("Calculating…");
11319 				break;
11320 			}
11321 			default: {
11322 				progress_str = _("Converting…");
11323 				break;
11324 			}
11325 		}
11326 		if(update_window_title(progress_str.c_str())) title_set = true;
11327 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "menubar")), FALSE);
11328 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "buttons")), FALSE);
11329 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "convert")), FALSE);
11330 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "historyview")), FALSE);
11331 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "historyactions")), FALSE);
11332 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "rpntab")), FALSE);
11333 		update_expression_icons(!minimal_mode ? RESULT_SPINNER : EXPRESSION_SPINNER);
11334 		if(!minimal_mode && surface_result) {
11335 			surface_result = NULL;
11336 			gtk_widget_queue_draw(resultview);
11337 		}
11338 		if(!minimal_mode) gtk_spinner_start(GTK_SPINNER(gtk_builder_get_object(main_builder, "resultspinner")));
11339 		else gtk_spinner_start(GTK_SPINNER(gtk_builder_get_object(main_builder, "expressionspinner")));
11340 		g_application_mark_busy(g_application_get_default());
11341 		was_busy = true;
11342 	}
11343 	while(b_busy && command_thread->running) {
11344 		while(gtk_events_pending()) gtk_main_iteration();
11345 		sleep_ms(100);
11346 	}
11347 	if(!command_thread->running) command_aborted = true;
11348 
11349 	if(!command_aborted && run == 1 && command_type >= COMMAND_CONVERT_UNIT && check_exchange_rates(NULL, show_result)) {
11350 		b_busy = true;
11351 		mfactor->set(*mstruct);
11352 		run = 2;
11353 		goto rerun_command;
11354 	}
11355 
11356 	b_busy = false;
11357 	b_busy_command = false;
11358 
11359 	if(was_busy) {
11360 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "menubar")), TRUE);
11361 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "buttons")), TRUE);
11362 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "convert")), TRUE);
11363 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "historyview")), TRUE);
11364 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "historyactions")), TRUE);
11365 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "rpntab")), TRUE);
11366 		if(title_set) update_window_title();
11367 		hide_expression_spinner();
11368 		if(!minimal_mode) gtk_spinner_stop(GTK_SPINNER(gtk_builder_get_object(main_builder, "resultspinner")));
11369 		else gtk_spinner_stop(GTK_SPINNER(gtk_builder_get_object(main_builder, "expressionspinner")));
11370 		g_application_unmark_busy(g_application_get_default());
11371 	}
11372 
11373 	if(command_type == COMMAND_CONVERT_STRING && !ceu_str.empty()) {
11374 		if(ceu_str[0] == '?') {
11375 			to_prefix = 1;
11376 		} else if(ceu_str.length() > 1 && ceu_str[1] == '?' && (ceu_str[0] == 'b' || ceu_str[0] == 'a' || ceu_str[0] == 'd')) {
11377 			to_prefix = ceu_str[0];
11378 		}
11379 	}
11380 
11381 	if(!command_aborted) {
11382 		mstruct->set(*mfactor);
11383 		mfactor->unref();
11384 		switch(command_type) {
11385 			case COMMAND_FACTORIZE: {
11386 				printops.allow_factorization = true;
11387 				break;
11388 			}
11389 			case COMMAND_EXPAND: {
11390 				printops.allow_factorization = false;
11391 				break;
11392 			}
11393 			default: {
11394 				printops.allow_factorization = (evalops.structuring == STRUCTURING_FACTORIZE);
11395 			}
11396 		}
11397 		if(show_result) {
11398 			setResult(NULL, true, false, true, command_type == COMMAND_TRANSFORM ? ceu_str : "");
11399 			surface_result_bak = NULL;
11400 		}
11401 	}
11402 
11403 	if(!surface_result && surface_result_bak) {
11404 		surface_result = surface_result_bak;
11405 		gtk_widget_queue_draw(resultview);
11406 	}
11407 
11408 	do_timeout = true;
11409 
11410 }
11411 
fetch_exchange_rates(int timeout,int n)11412 void fetch_exchange_rates(int timeout, int n) {
11413 	bool b_busy_bak = b_busy;
11414 	bool do_timeout_bak = do_timeout;
11415 	b_busy = true;
11416 	do_timeout = false;
11417 	FetchExchangeRatesThread fetch_thread;
11418 	if(fetch_thread.start() && fetch_thread.write(timeout) && fetch_thread.write(n)) {
11419 		int i = 0;
11420 		while(fetch_thread.running && i < 50) {
11421 			while(gtk_events_pending()) gtk_main_iteration();
11422 			sleep_ms(10);
11423 			i++;
11424 		}
11425 		if(fetch_thread.running) {
11426 			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."));
11427 			gtk_widget_show(dialog);
11428 			while(fetch_thread.running) {
11429 				while(gtk_events_pending()) gtk_main_iteration();
11430 				sleep_ms(10);
11431 			}
11432 			gtk_widget_destroy(dialog);
11433 		}
11434 	}
11435 	b_busy = b_busy_bak;
11436 	do_timeout = do_timeout_bak;
11437 }
11438 
run()11439 void FetchExchangeRatesThread::run() {
11440 	int timeout = 15;
11441 	int n = -1;
11442 	if(!read(&timeout)) return;
11443 	if(!read(&n)) return;
11444 	CALCULATOR->fetchExchangeRates(timeout, n);
11445 }
11446 
update_message_print_options()11447 void update_message_print_options() {
11448 	PrintOptions message_printoptions = printops;
11449 	message_printoptions.interval_display = INTERVAL_DISPLAY_PLUSMINUS;
11450 	message_printoptions.show_ending_zeroes = false;
11451 	message_printoptions.base = 10;
11452 	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;
11453 	else if(printops.min_exp == EXP_NONE) message_printoptions.min_exp = EXP_PRECISION;
11454 	if(PRECISION > 10) {
11455 		message_printoptions.use_max_decimals = true;
11456 		message_printoptions.max_decimals = 10;
11457 	}
11458 	CALCULATOR->setMessagePrintOptions(message_printoptions);
11459 }
11460 
result_display_updated()11461 void result_display_updated() {
11462 	if(block_result_update) return;
11463 	displayed_printops.use_unicode_signs = printops.use_unicode_signs;
11464 	displayed_printops.spell_out_logical_operators = printops.spell_out_logical_operators;
11465 	displayed_printops.multiplication_sign = printops.multiplication_sign;
11466 	displayed_printops.division_sign = printops.division_sign;
11467 	date_map.clear();
11468 	number_map.clear();
11469 	number_base_map.clear();
11470 	number_exp_map.clear();
11471 	number_exp_minus_map.clear();
11472 	number_approx_map.clear();
11473 	gtk_widget_queue_draw(resultview);
11474 	update_message_print_options();
11475 	update_status_text();
11476 	expression_has_changed2 = true;
11477 	display_parse_status();
11478 }
result_format_updated()11479 void result_format_updated() {
11480 	if(block_result_update) return;
11481 	update_message_print_options();
11482 	if(result_autocalculated) print_auto_calc();
11483 	else setResult(NULL, true, false, false);
11484 	update_status_text();
11485 	expression_has_changed2 = true;
11486 	display_parse_status();
11487 }
result_action_executed()11488 void result_action_executed() {
11489 	printops.allow_factorization = (evalops.structuring == STRUCTURING_FACTORIZE);
11490 	setResult(NULL, true, false, true);
11491 }
contains_prefix(const MathStructure & m)11492 bool contains_prefix(const MathStructure &m) {
11493 	if(m.isUnit() && (m.prefix() || m.unit()->subtype() == SUBTYPE_COMPOSITE_UNIT)) return true;
11494 	for(size_t i = 0; i < m.size(); i++) {
11495 		if(contains_prefix(m[i])) return true;
11496 	}
11497 	return false;
11498 }
result_prefix_changed(Prefix * prefix)11499 void result_prefix_changed(Prefix *prefix) {
11500 	to_prefix = 0;
11501 	bool b_use_unit_prefixes = printops.use_unit_prefixes;
11502 	bool b_use_prefixes_for_all_units = printops.use_prefixes_for_all_units;
11503 	if(contains_prefix(*mstruct)) {
11504 		mstruct->unformat(evalops);
11505 		executeCommand(COMMAND_CALCULATE, false);
11506 	}
11507 	if(!prefix) {
11508 		//mstruct->unformat(evalops);
11509 		printops.use_unit_prefixes = true;
11510 		printops.use_prefixes_for_all_units = true;
11511 	}
11512 	if(result_autocalculated) print_auto_calc();
11513 	else setResult(prefix, true, false, true);
11514 	printops.use_unit_prefixes = b_use_unit_prefixes;
11515 	printops.use_prefixes_for_all_units = b_use_prefixes_for_all_units;
11516 
11517 }
expression_calculation_updated()11518 void expression_calculation_updated() {
11519 	expression_has_changed2 = true;
11520 	display_parse_status();
11521 	update_message_print_options();
11522 	if(!rpn_mode) {
11523 		if(parsed_mstruct) {
11524 			for(size_t i = 0; i < 5; i++) {
11525 				if(parsed_mstruct->contains(vans[i])) {update_status_text(); return;}
11526 			}
11527 		}
11528 		if(auto_calculate) do_auto_calc();
11529 		else execute_expression(false);
11530 	}
11531 	update_status_text();
11532 }
expression_format_updated(bool recalculate)11533 void expression_format_updated(bool recalculate) {
11534 	expression_has_changed2 = true;
11535 	if(rpn_mode) recalculate = false;
11536 	display_parse_status();
11537 	update_message_print_options();
11538 	if(!expression_has_changed && !recalculate && !rpn_mode && !auto_calculate) {
11539 		clearresult();
11540 	} else if(!rpn_mode && parsed_mstruct) {
11541 		for(size_t i = 0; i < 5; i++) {
11542 			if(parsed_mstruct->contains(vans[i])) clearresult();
11543 		}
11544 	}
11545 	if(!rpn_mode) {
11546 		if(auto_calculate) do_auto_calc();
11547 		else if(recalculate) execute_expression(false);
11548 	}
11549 	update_status_text();
11550 }
11551 
11552 
on_abort_calculation(GtkDialog *,gint,gpointer)11553 void on_abort_calculation(GtkDialog*, gint, gpointer) {
11554 	CALCULATOR->abort();
11555 }
11556 
11557 int block_expression_history = 0;
add_to_expression_history(string str)11558 void add_to_expression_history(string str) {
11559 	if(block_expression_history) return;
11560 	for(size_t i = 0; i < expression_history.size(); i++) {
11561 		if(expression_history[i] == str) {
11562 			expression_history.erase(expression_history.begin() + i);
11563 			break;
11564 		}
11565 	}
11566 	if(expression_history.size() >= 100) {
11567 		expression_history.pop_back();
11568 	}
11569 	expression_history.insert(expression_history.begin(), str);
11570 	expression_history_index = 0;
11571 }
11572 
set_previous_expression()11573 void set_previous_expression() {
11574 	block_update_expression_icons++;
11575 	if(rpn_mode) {
11576 		clear_expression_text();
11577 	} else {
11578 		rpn_mode = true;
11579 		gtk_text_buffer_set_text(expressionbuffer, previous_expression.c_str(), -1);
11580 		rpn_mode = false;
11581 		gtk_widget_grab_focus(expressiontext);
11582 		GtkTextIter istart, iend;
11583 		gtk_text_buffer_get_start_iter(expressionbuffer, &istart);
11584 		gtk_text_buffer_get_end_iter(expressionbuffer, &iend);
11585 		gtk_text_buffer_select_range(expressionbuffer, &istart, &iend);
11586 		gtk_text_buffer_remove_tag(expressionbuffer, expression_par_tag, &istart, &iend);
11587 	}
11588 	cursor_has_moved = false;
11589 	block_update_expression_icons--;
11590 	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, "message_tooltip_icon"))) {
11591 		if(rpn_mode) update_expression_icons();
11592 		else update_expression_icons(EXPRESSION_CLEAR);
11593 	}
11594 }
11595 
fix_to_struct_gtk(MathStructure & m)11596 void fix_to_struct_gtk(MathStructure &m) {
11597 	if(m.isPower() && m[0].isUnit()) {
11598 		if(m[0].prefix() == NULL && m[0].unit()->referenceName() == "g") {
11599 			m[0].setPrefix(CALCULATOR->getOptimalDecimalPrefix(3));
11600 		} else if(m[0].unit() == CALCULATOR->u_euro) {
11601 			Unit *u = CALCULATOR->getLocalCurrency();
11602 			if(u) m[0].setUnit(u);
11603 		}
11604 	} else if(m.isUnit()) {
11605 		if(m.prefix() == NULL && m.unit()->referenceName() == "g") {
11606 			m.setPrefix(CALCULATOR->getOptimalDecimalPrefix(3));
11607 		} else if(m.unit() == CALCULATOR->u_euro) {
11608 			Unit *u = CALCULATOR->getLocalCurrency();
11609 			if(u) m.setUnit(u);
11610 		}
11611 	} else {
11612 		for(size_t i = 0; i < m.size();) {
11613 			if(m[i].isUnit()) {
11614 				if(m[i].prefix() == NULL && m[i].unit()->referenceName() == "g") {
11615 					m[i].setPrefix(CALCULATOR->getOptimalDecimalPrefix(3));
11616 				} else if(m[i].unit() == CALCULATOR->u_euro) {
11617 					Unit *u = CALCULATOR->getLocalCurrency();
11618 					if(u) m[i].setUnit(u);
11619 				}
11620 				i++;
11621 			} else if(m[i].isPower() && m[i][0].isUnit()) {
11622 				if(m[i][0].prefix() == NULL && m[i][0].unit()->referenceName() == "g") {
11623 					m[i][0].setPrefix(CALCULATOR->getOptimalDecimalPrefix(3));
11624 				} else if(m[i][0].unit() == CALCULATOR->u_euro) {
11625 					Unit *u = CALCULATOR->getLocalCurrency();
11626 					if(u) m[i][0].setUnit(u);
11627 				}
11628 				i++;
11629 			} else {
11630 				m.delChild(i + 1);
11631 			}
11632 		}
11633 		if(m.size() == 0) m.clear();
11634 		if(m.size() == 1) m.setToChild(1);
11635 	}
11636 }
11637 
s2b(const string & str)11638 int s2b(const string &str) {
11639 	if(str.empty()) return -1;
11640 	if(equalsIgnoreCase(str, "yes")) return 1;
11641 	if(equalsIgnoreCase(str, "no")) return 0;
11642 	if(equalsIgnoreCase(str, "true")) return 1;
11643 	if(equalsIgnoreCase(str, "false")) return 0;
11644 	if(equalsIgnoreCase(str, "on")) return 1;
11645 	if(equalsIgnoreCase(str, "off")) return 0;
11646 	if(str.find_first_not_of(SPACES NUMBERS) != string::npos) return -1;
11647 	int i = s2i(str);
11648 	if(i > 0) return 1;
11649 	return 0;
11650 }
11651 
11652 #define SET_BOOL_MENU(x)	{int v = s2b(svalue); if(v < 0) {CALCULATOR->error(true, "Illegal value: %s.", svalue.c_str(), NULL);} else gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, x)), v);}
11653 #define SET_BOOL_D(x)		{int v = s2b(svalue); if(v < 0) {CALCULATOR->error(true, "Illegal value: %s.", svalue.c_str(), NULL);} else if(x != v) {x = v; result_display_updated();}}
11654 #define SET_BOOL_PREF(x)	{int v = s2b(svalue); if(v < 0) {CALCULATOR->error(true, "Illegal value: %s.", svalue.c_str(), NULL);} else {if(!preferences_builder) {get_preferences_dialog();} gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(preferences_builder, x)), v);}}
11655 #define SET_BOOL_E(x)		{int v = s2b(svalue); if(v < 0) {CALCULATOR->error(true, "Illegal value: %s.", svalue.c_str(), NULL);} else if(x != v) {x = v; expression_calculation_updated();}}
11656 #define SET_BOOL(x)		{int v = s2b(svalue); if(v < 0) {CALCULATOR->error(true, "Illegal value: %s.", svalue.c_str(), NULL);} else if(x != v) {x = v;}}
11657 
set_assumption(const string & str,AssumptionType & at,AssumptionSign & as,bool last_of_two=false)11658 void set_assumption(const string &str, AssumptionType &at, AssumptionSign &as, bool last_of_two = false) {
11659 	if(equalsIgnoreCase(str, "unknown") || str == "0") {
11660 		if(!last_of_two) as = ASSUMPTION_SIGN_UNKNOWN;
11661 		else at = ASSUMPTION_TYPE_NUMBER;
11662 	} else if(equalsIgnoreCase(str, "real")) {
11663 		at = ASSUMPTION_TYPE_REAL;
11664 	} else if(equalsIgnoreCase(str, "number") || str == "num") {
11665 		at = ASSUMPTION_TYPE_NUMBER;
11666 	} else if(equalsIgnoreCase(str, "rational") || str == "rat") {
11667 		at = ASSUMPTION_TYPE_RATIONAL;
11668 	} else if(equalsIgnoreCase(str, "integer") || str == "int") {
11669 		at = ASSUMPTION_TYPE_INTEGER;
11670 	} else if(equalsIgnoreCase(str, "non-zero") || str == "nz") {
11671 		as = ASSUMPTION_SIGN_NONZERO;
11672 	} else if(equalsIgnoreCase(str, "positive") || str == "pos") {
11673 		as = ASSUMPTION_SIGN_POSITIVE;
11674 	} else if(equalsIgnoreCase(str, "non-negative") || str == "nneg") {
11675 		as = ASSUMPTION_SIGN_NONNEGATIVE;
11676 	} else if(equalsIgnoreCase(str, "negative") || str == "neg") {
11677 		as = ASSUMPTION_SIGN_NEGATIVE;
11678 	} else if(equalsIgnoreCase(str, "non-positive") || str == "npos") {
11679 		as = ASSUMPTION_SIGN_NONPOSITIVE;
11680 	} else {
11681 		CALCULATOR->error(true, "Unrecognized assumption: %s.", str.c_str(), NULL);
11682 	}
11683 }
11684 
set_option(string str)11685 void set_option(string str) {
11686 	remove_blank_ends(str);
11687 	gsub(SIGN_MINUS, "-", str);
11688 	string svalue, svar;
11689 	bool empty_value = false;
11690 	size_t i_underscore = str.find("_");
11691 	size_t index;
11692 	if(i_underscore != string::npos) {
11693 		index = str.find_first_of(SPACES);
11694 		if(index != string::npos && i_underscore > index) i_underscore = string::npos;
11695 	}
11696 	if(i_underscore == string::npos) index = str.find_last_of(SPACES);
11697 	if(index != string::npos) {
11698 		svar = str.substr(0, index);
11699 		remove_blank_ends(svar);
11700 		svalue = str.substr(index + 1);
11701 		remove_blank_ends(svalue);
11702 	} else {
11703 		svar = str;
11704 	}
11705 	if(i_underscore != string::npos) gsub("_", " ", svar);
11706 	if(svalue.empty()) {
11707 		empty_value = true;
11708 		svalue = "1";
11709 	}
11710 
11711 	set_option_place:
11712 	if(equalsIgnoreCase(svar, "base") || equalsIgnoreCase(svar, "input base") || svar == "inbase" || equalsIgnoreCase(svar, "output base") || svar == "outbase") {
11713 		int v = 0;
11714 		bool b_in = equalsIgnoreCase(svar, "input base") || svar == "inbase";
11715 		bool b_out = equalsIgnoreCase(svar, "output base") || svar == "outbase";
11716 		if(equalsIgnoreCase(svalue, "roman")) v = BASE_ROMAN_NUMERALS;
11717 		else if(equalsIgnoreCase(svalue, "bijective") || str == "b26" || str == "B26") v = BASE_BIJECTIVE_26;
11718 		else if(equalsIgnoreCase(svalue, "fp32") || equalsIgnoreCase(svalue, "binary32") || equalsIgnoreCase(svalue, "float")) {if(b_in) v = 0; else v = BASE_FP32;}
11719 		else if(equalsIgnoreCase(svalue, "fp64") || equalsIgnoreCase(svalue, "binary64") || equalsIgnoreCase(svalue, "double")) {if(b_in) v = 0; else v = BASE_FP64;}
11720 		else if(equalsIgnoreCase(svalue, "fp16") || equalsIgnoreCase(svalue, "binary16")) {if(b_in) v = 0; else v = BASE_FP16;}
11721 		else if(equalsIgnoreCase(svalue, "fp80")) {if(b_in) v = 0; else v = BASE_FP80;}
11722 		else if(equalsIgnoreCase(svalue, "fp128") || equalsIgnoreCase(svalue, "binary128")) {if(b_in) v = 0; else v = BASE_FP128;}
11723 		else if(equalsIgnoreCase(svalue, "time")) {if(b_in) v = 0; else v = BASE_TIME;}
11724 		else if(equalsIgnoreCase(svalue, "hex") || equalsIgnoreCase(svalue, "hexadecimal")) v = BASE_HEXADECIMAL;
11725 		else if(equalsIgnoreCase(svalue, "golden") || equalsIgnoreCase(svalue, "golden ratio") || svalue == "φ") v = BASE_GOLDEN_RATIO;
11726 		else if(equalsIgnoreCase(svalue, "supergolden") || equalsIgnoreCase(svalue, "supergolden ratio") || svalue == "ψ") v = BASE_SUPER_GOLDEN_RATIO;
11727 		else if(equalsIgnoreCase(svalue, "pi") || svalue == "π") v = BASE_PI;
11728 		else if(svalue == "e") v = BASE_E;
11729 		else if(svalue == "sqrt(2)" || svalue == "sqrt 2" || svalue == "sqrt2" || svalue == "√2") v = BASE_SQRT2;
11730 		else if(equalsIgnoreCase(svalue, "unicode")) v = BASE_UNICODE;
11731 		else if(equalsIgnoreCase(svalue, "duo") || equalsIgnoreCase(svalue, "duodecimal")) v = 12;
11732 		else if(equalsIgnoreCase(svalue, "bin") || equalsIgnoreCase(svalue, "binary")) v = BASE_BINARY;
11733 		else if(equalsIgnoreCase(svalue, "oct") || equalsIgnoreCase(svalue, "octal")) v = BASE_OCTAL;
11734 		else if(equalsIgnoreCase(svalue, "dec") || equalsIgnoreCase(svalue, "decimal")) v = BASE_DECIMAL;
11735 		else if(equalsIgnoreCase(svalue, "sexa") || equalsIgnoreCase(svalue, "sexagesimal")) {if(b_in) v = 0; else v = BASE_SEXAGESIMAL;}
11736 		else if(!b_in && !b_out && (index = svalue.find_first_of(SPACES)) != string::npos) {
11737 			str = svalue;
11738 			svalue = str.substr(index + 1, str.length() - (index + 1));
11739 			remove_blank_ends(svalue);
11740 			svar += " ";
11741 			str = str.substr(0, index);
11742 			remove_blank_ends(str);
11743 			svar += str;
11744 			gsub("_", " ", svar);
11745 			if(equalsIgnoreCase(svar, "base display")) {
11746 				goto set_option_place;
11747 			}
11748 			set_option(string("inbase ") + svalue);
11749 			set_option(string("outbase ") + str);
11750 			return;
11751 		} else if(!empty_value) {
11752 			MathStructure m;
11753 			EvaluationOptions eo = evalops;
11754 			eo.parse_options.base = 10;
11755 			eo.approximation = APPROXIMATION_TRY_EXACT;
11756 			CALCULATOR->beginTemporaryStopMessages();
11757 			CALCULATOR->calculate(&m, CALCULATOR->unlocalizeExpression(svalue, eo.parse_options), 500, eo);
11758 			if(CALCULATOR->endTemporaryStopMessages()) {
11759 				v = 0;
11760 			} else if(m.isInteger() && m.number() >= 2 && m.number() <= 36) {
11761 				v = m.number().intValue();
11762 			} else if(m.isNumber() && (b_in || ((!m.number().isNegative() || m.number().isInteger()) && (m.number() > 1 || m.number() < -1)))) {
11763 				v = BASE_CUSTOM;
11764 				if(b_in) CALCULATOR->setCustomInputBase(m.number());
11765 				else CALCULATOR->setCustomOutputBase(m.number());
11766 			}
11767 		}
11768 		if(v == 0) {
11769 			CALCULATOR->error(true, "Illegal base: %s.", svalue.c_str(), NULL);
11770 		} else if(b_in) {
11771 			if(v == BASE_CUSTOM || v != evalops.parse_options.base) {
11772 				evalops.parse_options.base = v;
11773 				input_base_updated_from_menu();
11774 				update_keypad_bases();
11775 				expression_format_updated(false);
11776 			}
11777 		} else {
11778 			if(v == BASE_CUSTOM || v != printops.base) {
11779 				printops.base = v;
11780 				to_base = 0;
11781 				to_bits = 0;
11782 				update_menu_base();
11783 				output_base_updated_from_menu();
11784 				update_keypad_bases();
11785 				result_format_updated();
11786 			}
11787 		}
11788 	} else if(equalsIgnoreCase(svar, "assumptions") || svar == "ass") {
11789 		size_t i = svalue.find_first_of(SPACES);
11790 		AssumptionType at = CALCULATOR->defaultAssumptions()->type();
11791 		AssumptionSign as = CALCULATOR->defaultAssumptions()->sign();
11792 		if(i != string::npos) {
11793 			set_assumption(svalue.substr(0, i), at, as, false);
11794 			set_assumption(svalue.substr(i + 1, svalue.length() - (i + 1)), at, as, true);
11795 		} else {
11796 			set_assumption(svalue, at, as, false);
11797 		}
11798 		set_assumptions_items(at, as);
11799 	} else if(equalsIgnoreCase(svar, "all prefixes") || svar == "allpref") SET_BOOL_MENU("menu_item_all_prefixes")
11800 	else if(equalsIgnoreCase(svar, "complex numbers") || svar == "cplx") SET_BOOL_MENU("menu_item_allow_complex")
11801 	else if(equalsIgnoreCase(svar, "excessive parentheses") || svar == "expar") SET_BOOL_D(printops.excessive_parenthesis)
11802 	else if(equalsIgnoreCase(svar, "functions") || svar == "func") SET_BOOL_MENU("menu_item_enable_functions")
11803 	else if(equalsIgnoreCase(svar, "infinite numbers") || svar == "inf") SET_BOOL_MENU("menu_item_allow_infinite")
11804 	else if(equalsIgnoreCase(svar, "show negative exponents") || svar == "negexp") SET_BOOL_MENU("menu_item_negative_exponents")
11805 	else if(equalsIgnoreCase(svar, "minus last") || svar == "minlast") SET_BOOL_MENU("menu_item_sort_minus_last")
11806 	else if(equalsIgnoreCase(svar, "assume nonzero denominators") || svar == "nzd") SET_BOOL_MENU("menu_item_assume_nonzero_denominators")
11807 	else if(equalsIgnoreCase(svar, "warn nonzero denominators") || svar == "warnnzd") SET_BOOL_MENU("menu_item_warn_about_denominators_assumed_nonzero")
11808 	else if(equalsIgnoreCase(svar, "prefixes") || svar == "pref") SET_BOOL_MENU("menu_item_prefixes_for_selected_units")
11809 	else if(equalsIgnoreCase(svar, "binary prefixes") || svar == "binpref") SET_BOOL_PREF("preferences_checkbutton_binary_prefixes")
11810 	else if(equalsIgnoreCase(svar, "denominator prefixes") || svar == "denpref") SET_BOOL_MENU("menu_item_denominator_prefixes")
11811 	else if(equalsIgnoreCase(svar, "place units separately") || svar == "unitsep") SET_BOOL_MENU("menu_item_place_units_separately")
11812 	else if(equalsIgnoreCase(svar, "calculate variables") || svar == "calcvar") SET_BOOL_MENU("menu_item_calculate_variables")
11813 	else if(equalsIgnoreCase(svar, "calculate functions") || svar == "calcfunc") SET_BOOL_E(evalops.calculate_functions)
11814 	else if(equalsIgnoreCase(svar, "sync units") || svar == "sync") SET_BOOL_E(evalops.sync_units)
11815 	else if(equalsIgnoreCase(svar, "temperature calculation") || svar == "temp")  {
11816 		int v = -1;
11817 		if(equalsIgnoreCase(svalue, "relative")) v = TEMPERATURE_CALCULATION_RELATIVE;
11818 		else if(equalsIgnoreCase(svalue, "hybrid")) v = TEMPERATURE_CALCULATION_HYBRID;
11819 		else if(equalsIgnoreCase(svalue, "absolute")) v = TEMPERATURE_CALCULATION_ABSOLUTE;
11820 		else if(svalue.find_first_not_of(SPACES NUMBERS) == string::npos) {
11821 			v = s2i(svalue);
11822 		}
11823 		if(v < 0 || v > 2) {
11824 			CALCULATOR->error(true, "Illegal value: %s.", svalue.c_str(), NULL);
11825 		} else {
11826 			if(!preferences_builder) get_preferences_dialog();
11827 			switch(v) {
11828 				case TEMPERATURE_CALCULATION_RELATIVE: {
11829 					gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(preferences_builder, "preferences_radiobutton_temp_rel")), TRUE);
11830 					break;
11831 				}
11832 				case TEMPERATURE_CALCULATION_ABSOLUTE: {
11833 					gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(preferences_builder, "preferences_radiobutton_temp_abs")), TRUE);
11834 					break;
11835 				}
11836 				case TEMPERATURE_CALCULATION_HYBRID: {
11837 					gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(preferences_builder, "preferences_radiobutton_temp_hybrid")), TRUE);
11838 					break;
11839 				}
11840 			}
11841 		}
11842 	} else if(equalsIgnoreCase(svar, "round to even") || svar == "rndeven") SET_BOOL_MENU("menu_item_round_halfway_to_even")
11843 	else if(equalsIgnoreCase(svar, "rpn syntax") || svar == "rpnsyn") {
11844 		bool b = (evalops.parse_options.parsing_mode == PARSING_MODE_RPN);
11845 		SET_BOOL(b)
11846 		if(b != (evalops.parse_options.parsing_mode == PARSING_MODE_RPN)) {
11847 			if(b) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_rpn_syntax")), TRUE);
11848 			else gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_adaptive_parsing")), TRUE);
11849 		}
11850 	} else if(equalsIgnoreCase(svar, "rpn") && svalue.find(" ") == string::npos) SET_BOOL_MENU("menu_item_rpn_mode")
11851 	else if(equalsIgnoreCase(svar, "short multiplication") || svar == "shortmul") SET_BOOL_D(printops.short_multiplication)
11852 	else if(equalsIgnoreCase(svar, "lowercase e") || svar == "lowe") SET_BOOL_PREF("preferences_checkbutton_lower_case_e")
11853 	else if(equalsIgnoreCase(svar, "lowercase numbers") || svar == "lownum") SET_BOOL_PREF("preferences_checkbutton_lower_case_numbers")
11854 	else if(equalsIgnoreCase(svar, "imaginary j") || svar == "imgj") SET_BOOL_PREF("preferences_checkbutton_imaginary_j")
11855 	else if(equalsIgnoreCase(svar, "base display") || svar == "basedisp") {
11856 		int v = -1;
11857 		if(equalsIgnoreCase(svalue, "none")) v = BASE_DISPLAY_NONE;
11858 		else if(empty_value || equalsIgnoreCase(svalue, "normal")) v = BASE_DISPLAY_NORMAL;
11859 		else if(equalsIgnoreCase(svalue, "alternative")) v = BASE_DISPLAY_ALTERNATIVE;
11860 		else if(svalue.find_first_not_of(SPACES NUMBERS) == string::npos) {
11861 			v = s2i(svalue);
11862 		}
11863 		if(v < 0 || v > 2) {
11864 			CALCULATOR->error(true, "Illegal value: %s.", svalue.c_str(), NULL);
11865 		} else {
11866 			if(!preferences_builder) get_preferences_dialog();
11867 			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(preferences_builder, "preferences_checkbutton_alternative_base_prefixes")), v == BASE_DISPLAY_ALTERNATIVE);
11868 		}
11869 	} else if(equalsIgnoreCase(svar, "two's complement") || svar == "twos") SET_BOOL_PREF("preferences_checkbutton_twos_complement")
11870 	else if(equalsIgnoreCase(svar, "hexadecimal two's") || svar == "hextwos") SET_BOOL_PREF("preferences_checkbutton_hexadecimal_twos_complement")
11871 	else if(equalsIgnoreCase(svar, "digit grouping") || svar =="group") {
11872 		int v = -1;
11873 		if(equalsIgnoreCase(svalue, "off")) v = DIGIT_GROUPING_NONE;
11874 		else if(equalsIgnoreCase(svalue, "none")) v = DIGIT_GROUPING_NONE;
11875 		else if(empty_value || equalsIgnoreCase(svalue, "standard") || equalsIgnoreCase(svalue, "on")) v = DIGIT_GROUPING_STANDARD;
11876 		else if(equalsIgnoreCase(svalue, "locale")) v = DIGIT_GROUPING_LOCALE;
11877 		else if(svalue.find_first_not_of(SPACES NUMBERS) == string::npos) {
11878 			v = s2i(svalue);
11879 		}
11880 		if(v < DIGIT_GROUPING_NONE || v > DIGIT_GROUPING_LOCALE) {
11881 			CALCULATOR->error(true, "Illegal value: %s.", svalue.c_str(), NULL);
11882 		} else {
11883 			if(!preferences_builder) get_preferences_dialog();
11884 			if(v == DIGIT_GROUPING_NONE) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(preferences_builder, "preferences_radiobutton_digit_grouping_none")), TRUE);
11885 			else if(v == DIGIT_GROUPING_STANDARD) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(preferences_builder, "preferences_radiobutton_digit_grouping_standard")), TRUE);
11886 			else if(v == DIGIT_GROUPING_LOCALE) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(preferences_builder, "preferences_radiobutton_digit_grouping_locale")), TRUE);
11887 		}
11888 	} else if(equalsIgnoreCase(svar, "spell out logical") || svar == "spellout") SET_BOOL_PREF("preferences_checkbutton_spell_out_logical_operators")
11889 	else if((equalsIgnoreCase(svar, "ignore dot") || svar == "nodot") && CALCULATOR->getDecimalPoint() != DOT) SET_BOOL_PREF("preferences_checkbutton_dot_as_separator")
11890 	else if((equalsIgnoreCase(svar, "ignore comma") || svar == "nocomma") && CALCULATOR->getDecimalPoint() != COMMA) SET_BOOL_PREF("preferences_checkbutton_comma_as_separator")
11891 	else if(equalsIgnoreCase(svar, "decimal comma")) {
11892 		int v = -2;
11893 		if(equalsIgnoreCase(svalue, "off")) v = 0;
11894 		else if(empty_value || equalsIgnoreCase(svalue, "on")) v = 1;
11895 		else if(equalsIgnoreCase(svalue, "locale")) v = -1;
11896 		else if(svalue.find_first_not_of(SPACES MINUS NUMBERS) == string::npos) {
11897 			v = s2i(svalue);
11898 		}
11899 		if(v < -1 || v > 1) {
11900 			CALCULATOR->error(true, "Illegal value: %s.", svalue.c_str(), NULL);
11901 		} else {
11902 			if(!preferences_builder) get_preferences_dialog();
11903 			if(v >= 0) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(preferences_builder, "preferences_checkbutton_decimal_comma")), v);
11904 			else b_decimal_comma = v;
11905 		}
11906 	} else if(equalsIgnoreCase(svar, "limit implicit multiplication") || svar == "limimpl") SET_BOOL_MENU("menu_item_limit_implicit_multiplication")
11907 	else if(equalsIgnoreCase(svar, "spacious") || svar == "space") SET_BOOL_D(printops.spacious)
11908 	else if(equalsIgnoreCase(svar, "unicode") || svar == "uni") SET_BOOL_PREF("preferences_checkbutton_unicode_signs")
11909 	else if(equalsIgnoreCase(svar, "units") || svar == "unit") SET_BOOL_MENU("menu_item_enable_units")
11910 	else if(equalsIgnoreCase(svar, "unknowns") || svar == "unknown") SET_BOOL_MENU("menu_item_enable_unknown_variables")
11911 	else if(equalsIgnoreCase(svar, "variables") || svar == "var") SET_BOOL_MENU("menu_item_enable_variables")
11912 	else if(equalsIgnoreCase(svar, "abbreviations") || svar == "abbr" || svar == "abbrev") SET_BOOL_MENU("menu_item_abbreviate_names")
11913 	else if(equalsIgnoreCase(svar, "show ending zeroes") || svar == "zeroes") SET_BOOL_MENU("menu_item_show_ending_zeroes")
11914 	else if(equalsIgnoreCase(svar, "repeating decimals") || svar == "repdeci") SET_BOOL_MENU("menu_item_indicate_infinite_series")
11915 	else if(equalsIgnoreCase(svar, "angle unit") || svar == "angle") {
11916 		int v = -1;
11917 		if(equalsIgnoreCase(svalue, "rad") || equalsIgnoreCase(svalue, "radians")) v = ANGLE_UNIT_RADIANS;
11918 		else if(equalsIgnoreCase(svalue, "deg") || equalsIgnoreCase(svalue, "degrees")) v = ANGLE_UNIT_DEGREES;
11919 		else if(equalsIgnoreCase(svalue, "gra") || equalsIgnoreCase(svalue, "gradians")) v = ANGLE_UNIT_GRADIANS;
11920 		else if(equalsIgnoreCase(svalue, "none")) v = ANGLE_UNIT_NONE;
11921 		else if(!empty_value && svalue.find_first_not_of(SPACES NUMBERS) == string::npos) {
11922 			v = s2i(svalue);
11923 		}
11924 		if(v < 0 || v > 3) {
11925 			CALCULATOR->error(true, "Illegal value: %s.", svalue.c_str(), NULL);
11926 		} else {
11927 			if(v == ANGLE_UNIT_DEGREES) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_degrees")), TRUE);
11928 			else if(v == ANGLE_UNIT_RADIANS) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_radians")), TRUE);
11929 			else if(v == ANGLE_UNIT_GRADIANS) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_gradians")), TRUE);
11930 			else if(v == ANGLE_UNIT_NONE) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_no_default_angle_unit")), TRUE);
11931 		}
11932 	} else if(equalsIgnoreCase(svar, "caret as xor") || equalsIgnoreCase(svar, "xor^")) SET_BOOL_PREF("preferences_checkbutton_caret_as_xor")
11933 	else if(equalsIgnoreCase(svar, "parsing mode") || svar == "parse" || svar == "syntax") {
11934 		int v = -1;
11935 		if(equalsIgnoreCase(svalue, "adaptive")) v = PARSING_MODE_ADAPTIVE;
11936 		else if(equalsIgnoreCase(svalue, "implicit first")) v = PARSING_MODE_IMPLICIT_MULTIPLICATION_FIRST;
11937 		else if(equalsIgnoreCase(svalue, "conventional")) v = PARSING_MODE_CONVENTIONAL;
11938 		else if(equalsIgnoreCase(svalue, "chain")) v = PARSING_MODE_CHAIN;
11939 		else if(equalsIgnoreCase(svalue, "rpn")) v = PARSING_MODE_RPN;
11940 		else if(!empty_value && svalue.find_first_not_of(SPACES NUMBERS) == string::npos) {
11941 			v = s2i(svalue);
11942 		}
11943 		if(v < PARSING_MODE_ADAPTIVE || v > PARSING_MODE_RPN) {
11944 			CALCULATOR->error(true, "Illegal value: %s.", svalue.c_str(), NULL);
11945 		} else {
11946 			if(v == PARSING_MODE_ADAPTIVE) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_adaptive_parsing")), TRUE);
11947 			else if(v == PARSING_MODE_IMPLICIT_MULTIPLICATION_FIRST) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_ignore_whitespace")), TRUE);
11948 			else if(v == PARSING_MODE_CONVENTIONAL) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_no_special_implicit_multiplication")), TRUE);
11949 			else if(v == PARSING_MODE_CHAIN) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_chain_syntax")), TRUE);
11950 			else if(v == PARSING_MODE_RPN) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_rpn_syntax")), TRUE);
11951 		}
11952 	} else if(equalsIgnoreCase(svar, "update exchange rates") || svar == "upxrates") {
11953 		int v = -2;
11954 		if(equalsIgnoreCase(svalue, "never")) {
11955 			v = 0;
11956 		} else if(equalsIgnoreCase(svalue, "ask")) {
11957 			v = -1;
11958 		} else {
11959 			v = s2i(svalue);
11960 		}
11961 		if(v < -1) v = -1;
11962 		if(!preferences_builder) get_preferences_dialog();
11963 		gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(preferences_builder, "preferences_update_exchange_rates_spin_button")), v);
11964 	} else if(equalsIgnoreCase(svar, "multiplication sign") || svar == "mulsign") {
11965 		int v = -1;
11966 		if(svalue == SIGN_MULTIDOT || svalue == ".") v = MULTIPLICATION_SIGN_DOT;
11967 		else if(svalue == SIGN_MIDDLEDOT) v = MULTIPLICATION_SIGN_ALTDOT;
11968 		else if(svalue == SIGN_MULTIPLICATION || svalue == "x") v = MULTIPLICATION_SIGN_X;
11969 		else if(svalue == "*") v = MULTIPLICATION_SIGN_ASTERISK;
11970 		else if(!empty_value && svalue.find_first_not_of(SPACES NUMBERS) == string::npos) {
11971 			v = s2i(svalue);
11972 		}
11973 		if(v < MULTIPLICATION_SIGN_ASTERISK || v > MULTIPLICATION_SIGN_ALTDOT) {
11974 			CALCULATOR->error(true, "Illegal value: %s.", svalue.c_str(), NULL);
11975 		} else {
11976 			if(!preferences_builder) get_preferences_dialog();
11977 			switch(v) {
11978 				case MULTIPLICATION_SIGN_DOT: {
11979 					gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(preferences_builder, "preferences_radiobutton_dot")), TRUE);
11980 					break;
11981 				}
11982 				case MULTIPLICATION_SIGN_ALTDOT: {
11983 					gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(preferences_builder, "preferences_radiobutton_altdot")), TRUE);
11984 					break;
11985 				}
11986 				case MULTIPLICATION_SIGN_X: {
11987 					gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(preferences_builder, "preferences_radiobutton_ex")), TRUE);
11988 					break;
11989 				}
11990 				default: {
11991 					gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(preferences_builder, "preferences_radiobutton_asterisk")), TRUE);
11992 					break;
11993 				}
11994 			}
11995 		}
11996 	} else if(equalsIgnoreCase(svar, "division sign") || svar == "divsign") {
11997 		int v = -1;
11998 		if(svalue == SIGN_DIVISION_SLASH) v = DIVISION_SIGN_DIVISION_SLASH;
11999 		else if(svalue == SIGN_DIVISION) v = DIVISION_SIGN_DIVISION;
12000 		else if(svalue == "/") v = DIVISION_SIGN_SLASH;
12001 		else if(!empty_value && svalue.find_first_not_of(SPACES NUMBERS) == string::npos) {
12002 			v = s2i(svalue);
12003 		}
12004 		if(v < 0 || v > 2) {
12005 			CALCULATOR->error(true, "Illegal value: %s.", svalue.c_str(), NULL);
12006 		} else {
12007 			if(!preferences_builder) get_preferences_dialog();
12008 			switch(v) {
12009 				case DIVISION_SIGN_DIVISION_SLASH: {
12010 					gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(preferences_builder, "preferences_radiobutton_division_slash")), TRUE);
12011 					break;
12012 				}
12013 				case DIVISION_SIGN_DIVISION: {
12014 					gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(preferences_builder, "preferences_radiobutton_division")), TRUE);
12015 					break;
12016 				}
12017 				default: {
12018 					gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(preferences_builder, "preferences_radiobutton_slash")), TRUE);
12019 					break;
12020 				}
12021 			}
12022 		}
12023 	} else if(equalsIgnoreCase(svar, "approximation") || svar == "appr" || svar == "approx") {
12024 		int v = -1;
12025 		if(equalsIgnoreCase(svalue, "exact")) v = APPROXIMATION_EXACT;
12026 		else if(equalsIgnoreCase(svalue, "auto")) v = -1;
12027 		else if(equalsIgnoreCase(svalue, "dual")) v = APPROXIMATION_APPROXIMATE + 1;
12028 		else if(empty_value || equalsIgnoreCase(svalue, "try exact") || svalue == "try") v = APPROXIMATION_TRY_EXACT;
12029 		else if(equalsIgnoreCase(svalue, "approximate") || svalue == "approx") v = APPROXIMATION_APPROXIMATE;
12030 		else if(svalue.find_first_not_of(SPACES NUMBERS) == string::npos) {
12031 			v = s2i(svalue);
12032 		}
12033 		if(v > APPROXIMATION_APPROXIMATE + 1) {
12034 			CALCULATOR->error(true, "Illegal value: %s.", svalue.c_str(), NULL);
12035 		} else if(v < APPROXIMATION_EXACT || v > APPROXIMATION_APPROXIMATE) {
12036 			CALCULATOR->error(true, "Unsupported value: %s.", svalue.c_str(), NULL);
12037 		} else {
12038 			if(v == APPROXIMATION_EXACT) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_always_exact")), TRUE);
12039 			else if(v == APPROXIMATION_TRY_EXACT) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_try_exact")), TRUE);
12040 			else if(v == APPROXIMATION_APPROXIMATE) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_approximate")), TRUE);
12041 		}
12042 	} else if(equalsIgnoreCase(svar, "interval calculation") || svar == "ic" || equalsIgnoreCase(svar, "uncertainty propagation") || svar == "up") {
12043 		int v = -1;
12044 		if(equalsIgnoreCase(svalue, "variance formula") || equalsIgnoreCase(svalue, "variance")) v = INTERVAL_CALCULATION_VARIANCE_FORMULA;
12045 		else if(equalsIgnoreCase(svalue, "interval arithmetic") || svalue == "iv") v = INTERVAL_CALCULATION_INTERVAL_ARITHMETIC;
12046 		else if(!empty_value && svalue.find_first_not_of(SPACES NUMBERS) == string::npos) {
12047 			v = s2i(svalue);
12048 		}
12049 		if(v < INTERVAL_CALCULATION_NONE || v > INTERVAL_CALCULATION_SIMPLE_INTERVAL_ARITHMETIC) {
12050 			CALCULATOR->error(true, "Illegal value: %s.", svalue.c_str(), NULL);
12051 		} else {
12052 			switch(v) {
12053 				case INTERVAL_CALCULATION_VARIANCE_FORMULA: {
12054 					gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_ic_variance")), TRUE);
12055 					break;
12056 				}
12057 				case INTERVAL_CALCULATION_INTERVAL_ARITHMETIC: {
12058 					gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_ic_interval_arithmetic")), TRUE);
12059 					break;
12060 				}
12061 				case INTERVAL_CALCULATION_SIMPLE_INTERVAL_ARITHMETIC: {
12062 					gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_ic_simple")), TRUE);
12063 					break;
12064 				}
12065 				case INTERVAL_CALCULATION_NONE: {
12066 					gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_ic_none")), TRUE);
12067 					break;
12068 				}
12069 			}
12070 		}
12071 	} else if(equalsIgnoreCase(svar, "autoconversion") || svar == "conv") {
12072 		int v = -1;
12073 		MixedUnitsConversion muc = MIXED_UNITS_CONVERSION_DEFAULT;
12074 		if(equalsIgnoreCase(svalue, "none")) {v = POST_CONVERSION_NONE;  muc = MIXED_UNITS_CONVERSION_NONE;}
12075 		else if(equalsIgnoreCase(svalue, "best")) v = POST_CONVERSION_OPTIMAL_SI;
12076 		else if(equalsIgnoreCase(svalue, "optimalsi") || svalue == "si") v = POST_CONVERSION_OPTIMAL_SI;
12077 		else if(empty_value || equalsIgnoreCase(svalue, "optimal")) v = POST_CONVERSION_OPTIMAL;
12078 		else if(equalsIgnoreCase(svalue, "base")) v = POST_CONVERSION_BASE;
12079 		else if(equalsIgnoreCase(svalue, "mixed")) v = POST_CONVERSION_OPTIMAL + 1;
12080 		else if(svalue.find_first_not_of(SPACES NUMBERS) == string::npos) {
12081 			v = s2i(svalue);
12082 			if(v == 1) v = 3;
12083 			else if(v == 3) v = 1;
12084 		}
12085 		if(v == POST_CONVERSION_OPTIMAL + 1) {
12086 			v = POST_CONVERSION_NONE;
12087 			muc = MIXED_UNITS_CONVERSION_DEFAULT;
12088 		} else if(v == 0) {
12089 			v = POST_CONVERSION_NONE;
12090 			muc = MIXED_UNITS_CONVERSION_NONE;
12091 		}
12092 		if(v < 0 || v > POST_CONVERSION_OPTIMAL) {
12093 			CALCULATOR->error(true, "Illegal value: %s.", svalue.c_str(), NULL);
12094 		} else {
12095 			switch(v) {
12096 				case POST_CONVERSION_OPTIMAL: {
12097 					gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_post_conversion_optimal")), TRUE);
12098 					break;
12099 				}
12100 				case POST_CONVERSION_OPTIMAL_SI: {
12101 					gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_post_conversion_optimal_si")), TRUE);
12102 					break;
12103 				}
12104 				case POST_CONVERSION_BASE: {
12105 					gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_post_conversion_base")), TRUE);
12106 					break;
12107 				}
12108 				default: {
12109 					gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_post_conversion_none")), TRUE);
12110 					break;
12111 				}
12112 			}
12113 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_mixed_units_conversion")), muc != MIXED_UNITS_CONVERSION_NONE);
12114 		}
12115 	} else if(equalsIgnoreCase(svar, "currency conversion") || svar == "curconv") SET_BOOL_PREF("preferences_checkbutton_local_currency_conversion")
12116 	else if(equalsIgnoreCase(svar, "algebra mode") || svar == "alg") {
12117 		int v = -1;
12118 		if(equalsIgnoreCase(svalue, "none")) v = STRUCTURING_NONE;
12119 		else if(equalsIgnoreCase(svalue, "simplify") || equalsIgnoreCase(svalue, "expand")) v = STRUCTURING_SIMPLIFY;
12120 		else if(equalsIgnoreCase(svalue, "factorize") || svalue == "factor") v = STRUCTURING_FACTORIZE;
12121 		else if(!empty_value && svalue.find_first_not_of(SPACES NUMBERS) == string::npos) {
12122 			v = s2i(svalue);
12123 		}
12124 		if(v < 0 || v > STRUCTURING_FACTORIZE) {
12125 			CALCULATOR->error(true, "Illegal value: %s.", svalue.c_str(), NULL);
12126 		} else {
12127 			if(v == STRUCTURING_FACTORIZE) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_algebraic_mode_factorize")), TRUE);
12128 			else if(v == STRUCTURING_SIMPLIFY) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_algebraic_mode_simplify")), TRUE);
12129 			else  {
12130 				evalops.structuring = (StructuringMode) v;
12131 				printops.allow_factorization = false;
12132 				expression_calculation_updated();
12133 			}
12134 		}
12135 	} else if(equalsIgnoreCase(svar, "exact")) {
12136 		int v = s2b(svalue);
12137 		if(v < 0) {
12138 			CALCULATOR->error(true, "Illegal value: %s.", svalue.c_str(), NULL);
12139 		} else {
12140 			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "button_exact")), v > 0);
12141 		}
12142 	} else if(equalsIgnoreCase(svar, "ignore locale")) SET_BOOL_PREF("preferences_checkbutton_ignore_locale")
12143 	else if(equalsIgnoreCase(svar, "save mode")) SET_BOOL_PREF("preferences_checkbutton_mode")
12144 	else if(equalsIgnoreCase(svar, "save definitions") || svar == "save defs") SET_BOOL_PREF("preferences_checkbutton_save_defs")
12145 	else if(equalsIgnoreCase(svar, "scientific notation") || svar == "exp mode" || svar == "exp") {
12146 		int v = -1;
12147 		bool valid = true;
12148 		if(equalsIgnoreCase(svalue, "off")) v = EXP_NONE;
12149 		else if(equalsIgnoreCase(svalue, "auto")) v = EXP_PRECISION;
12150 		else if(equalsIgnoreCase(svalue, "pure")) v = EXP_PURE;
12151 		else if(empty_value || equalsIgnoreCase(svalue, "scientific")) v = EXP_SCIENTIFIC;
12152 		else if(equalsIgnoreCase(svalue, "engineering")) v = EXP_BASE_3;
12153 		else if(svalue.find_first_not_of(SPACES NUMBERS MINUS) == string::npos) v = s2i(svalue);
12154 		else valid = false;
12155 		if(valid) {
12156 			switch(v) {
12157 				case EXP_PRECISION: {
12158 					gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_display_normal")), TRUE);
12159 					break;
12160 				}
12161 				case EXP_BASE_3: {
12162 					gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_display_engineering")), TRUE);
12163 					break;
12164 				}
12165 				case EXP_SCIENTIFIC: {
12166 					gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_display_scientific")), TRUE);
12167 					break;
12168 				}
12169 				case EXP_PURE: {
12170 					gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_display_purely_scientific")), TRUE);
12171 					break;
12172 				}
12173 				case EXP_NONE: {
12174 					gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_display_non_scientific")), TRUE);
12175 					break;
12176 				}
12177 				default: {
12178 					printops.min_exp = v;
12179 					result_format_updated();
12180 				}
12181 			}
12182 		} else {
12183 			CALCULATOR->error(true, "Illegal value: %s.", svalue.c_str(), NULL);
12184 		}
12185 	} else if(equalsIgnoreCase(svar, "precision") || svar == "prec") {
12186 		int v = 0;
12187 		if(!empty_value && svalue.find_first_not_of(SPACES NUMBERS) == string::npos) v = s2i(svalue);
12188 		if(v < 1) {
12189 			CALCULATOR->error(true, "Illegal value: %s.", svalue.c_str(), NULL);
12190 		} else {
12191 			if(precision_builder) {
12192 				gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(precision_builder, "precision_dialog_spinbutton_precision")), v);
12193 			} else {
12194 				CALCULATOR->setPrecision(v);
12195 				expression_calculation_updated();
12196 			}
12197 		}
12198 	} else if(equalsIgnoreCase(svar, "interval display") || svar == "ivdisp") {
12199 		int v = -1;
12200 		if(equalsIgnoreCase(svalue, "adaptive")) v = 0;
12201 		else if(equalsIgnoreCase(svalue, "significant")) v = INTERVAL_DISPLAY_SIGNIFICANT_DIGITS + 1;
12202 		else if(equalsIgnoreCase(svalue, "interval")) v = INTERVAL_DISPLAY_INTERVAL + 1;
12203 		else if(empty_value || equalsIgnoreCase(svalue, "plusminus")) v = INTERVAL_DISPLAY_PLUSMINUS + 1;
12204 		else if(equalsIgnoreCase(svalue, "midpoint")) v = INTERVAL_DISPLAY_MIDPOINT + 1;
12205 		else if(equalsIgnoreCase(svalue, "upper")) v = INTERVAL_DISPLAY_UPPER + 1;
12206 		else if(equalsIgnoreCase(svalue, "lower")) v = INTERVAL_DISPLAY_LOWER + 1;
12207 		else if(svalue.find_first_not_of(SPACES NUMBERS) == string::npos) {
12208 			v = s2i(svalue);
12209 		}
12210 		if(v == 0) {
12211 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_interval_adaptive")), TRUE);
12212 		} else {
12213 			v--;
12214 			if(v < INTERVAL_DISPLAY_SIGNIFICANT_DIGITS || v > INTERVAL_DISPLAY_UPPER) {
12215 				CALCULATOR->error(true, "Illegal value: %s.", svalue.c_str(), NULL);
12216 			} else {
12217 				switch(v) {
12218 					case INTERVAL_DISPLAY_INTERVAL: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_interval_interval")), TRUE); break;}
12219 					case INTERVAL_DISPLAY_PLUSMINUS: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_interval_plusminus")), TRUE); break;}
12220 					case INTERVAL_DISPLAY_MIDPOINT: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_interval_midpoint")), TRUE); break;}
12221 					default: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_interval_significant")), TRUE); break;}
12222 				}
12223 			}
12224 		}
12225 	} else if(equalsIgnoreCase(svar, "interval arithmetic") || svar == "ia" || svar == "interval") SET_BOOL_MENU("menu_item_interval_arithmetic")
12226 	else if(equalsIgnoreCase(svar, "variable units") || svar == "varunits") SET_BOOL_MENU("menu_item_enable_variable_units")
12227 	else if(equalsIgnoreCase(svar, "color")) CALCULATOR->error(true, "Unsupported option: %s.", svar.c_str(), NULL);
12228 	else if(equalsIgnoreCase(svar, "max decimals") || svar == "maxdeci") {
12229 		int v = -1;
12230 		if(equalsIgnoreCase(svalue, "off")) v = -1;
12231 		else if(!empty_value && svalue.find_first_not_of(SPACES NUMBERS) == string::npos) v = s2i(svalue);
12232 		if(decimals_builder) {
12233 			gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (gtk_builder_get_object(decimals_builder, "decimals_dialog_checkbutton_max")), v >= 0);
12234 			if(v >= 0) gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(decimals_builder, "decimals_dialog_spinbutton_max")), v);
12235 		} else {
12236 			if(v >= 0) printops.max_decimals = v;
12237 			printops.use_max_decimals = v >= 0;
12238 			result_format_updated();
12239 		}
12240 	} else if(equalsIgnoreCase(svar, "min decimals") || svar == "mindeci") {
12241 		int v = -1;
12242 		if(equalsIgnoreCase(svalue, "off")) v = -1;
12243 		else if(!empty_value && svalue.find_first_not_of(SPACES NUMBERS) == string::npos) v = s2i(svalue);
12244 		if(decimals_builder) {
12245 			gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (gtk_builder_get_object(decimals_builder, "decimals_dialog_checkbutton_min")), v >= 0);
12246 			if(v >= 0) gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(decimals_builder, "decimals_dialog_spinbutton_min")), v);
12247 		} else {
12248 			if(v >= 0) printops.min_decimals = v;
12249 			printops.use_min_decimals = v >= 0;
12250 			result_format_updated();
12251 		}
12252 	} else if(equalsIgnoreCase(svar, "fractions") || svar == "fr") {
12253 		int v = -1;
12254 		if(equalsIgnoreCase(svalue, "off")) v = FRACTION_DECIMAL;
12255 		else if(equalsIgnoreCase(svalue, "exact")) v = FRACTION_DECIMAL_EXACT;
12256 		else if(empty_value || equalsIgnoreCase(svalue, "on")) v = FRACTION_FRACTIONAL;
12257 		else if(equalsIgnoreCase(svalue, "combined") || equalsIgnoreCase(svalue, "mixed")) v = FRACTION_COMBINED;
12258 		else if(equalsIgnoreCase(svalue, "long")) v = FRACTION_COMBINED + 1;
12259 		else if(equalsIgnoreCase(svalue, "dual")) v = FRACTION_COMBINED + 2;
12260 		else if(equalsIgnoreCase(svalue, "auto")) v = -1;
12261 		else if(svalue.find_first_not_of(SPACES NUMBERS) == string::npos) {
12262 			v = s2i(svalue);
12263 		}
12264 		if(v > FRACTION_COMBINED + 2) {
12265 			CALCULATOR->error(true, "Illegal value: %s.", svalue.c_str(), NULL);
12266 		} else if(v < 0 || v > FRACTION_COMBINED + 1) {
12267 			CALCULATOR->error(true, "Unsupported value: %s.", svalue.c_str(), NULL);
12268 		} else {
12269 			int dff = default_fraction_fraction;
12270 			switch(v > FRACTION_COMBINED ? FRACTION_FRACTIONAL : v) {
12271 				case FRACTION_DECIMAL: {
12272 					gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_fraction_decimal")), TRUE);
12273 					break;
12274 				}
12275 				case FRACTION_DECIMAL_EXACT: {
12276 					gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_fraction_decimal_exact")), TRUE);
12277 					break;
12278 				}
12279 				case FRACTION_COMBINED: {
12280 					gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_fraction_combined")), TRUE);
12281 					break;
12282 				}
12283 				case FRACTION_FRACTIONAL: {
12284 					gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_fraction_fraction")), TRUE);
12285 					if(v > FRACTION_COMBINED) {
12286 						printops.restrict_fraction_length = false;
12287 						result_format_updated();
12288 					}
12289 					break;
12290 				}
12291 			}
12292 			default_fraction_fraction = dff;
12293 		}
12294 	} else if(equalsIgnoreCase(svar, "complex form") || svar == "cplxform") {
12295 		int v = -1;
12296 		if(equalsIgnoreCase(svalue, "rectangular") || equalsIgnoreCase(svalue, "cartesian") || svalue == "rect") v = COMPLEX_NUMBER_FORM_RECTANGULAR;
12297 		else if(equalsIgnoreCase(svalue, "exponential") || svalue == "exp") v = COMPLEX_NUMBER_FORM_EXPONENTIAL;
12298 		else if(equalsIgnoreCase(svalue, "polar")) v = COMPLEX_NUMBER_FORM_POLAR;
12299 		else if(equalsIgnoreCase(svalue, "angle") || equalsIgnoreCase(svalue, "phasor")) v = COMPLEX_NUMBER_FORM_CIS + 1;
12300 		else if(svar == "cis") v = COMPLEX_NUMBER_FORM_CIS;
12301 		else if(!empty_value && svalue.find_first_not_of(SPACES NUMBERS) == string::npos) {
12302 			v = s2i(svalue);
12303 		}
12304 		if(v < 0 || v > 4) {
12305 			CALCULATOR->error(true, "Illegal value: %s.", svalue.c_str(), NULL);
12306 		} else {
12307 			switch(v) {
12308 				case COMPLEX_NUMBER_FORM_RECTANGULAR: {
12309 					gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_complex_rectangular")), TRUE);
12310 					break;
12311 				}
12312 				case COMPLEX_NUMBER_FORM_EXPONENTIAL: {
12313 					gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_complex_exponential")), TRUE);
12314 					break;
12315 				}
12316 				case COMPLEX_NUMBER_FORM_POLAR: {
12317 					gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_complex_polar")), TRUE);
12318 					break;
12319 				}
12320 				case COMPLEX_NUMBER_FORM_CIS: {
12321 					gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_complex_polar")), TRUE);
12322 					break;
12323 				}
12324 				default: {
12325 					gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_complex_angle")), TRUE);
12326 				}
12327 			}
12328 		}
12329 	} else if(equalsIgnoreCase(svar, "read precision") || svar == "readprec") {
12330 		int v = -1;
12331 		if(equalsIgnoreCase(svalue, "off")) v = DONT_READ_PRECISION;
12332 		else if(equalsIgnoreCase(svalue, "always")) v = ALWAYS_READ_PRECISION;
12333 		else if(empty_value || equalsIgnoreCase(svalue, "when decimals") || equalsIgnoreCase(svalue, "on")) v = READ_PRECISION_WHEN_DECIMALS;
12334 		else if(svalue.find_first_not_of(SPACES NUMBERS) == string::npos) {
12335 			v = s2i(svalue);
12336 		}
12337 		if(v < 0 || v > 2) {
12338 			CALCULATOR->error(true, "Illegal value: %s.", svalue.c_str(), NULL);
12339 		} else {
12340 			if(v == ALWAYS_READ_PRECISION) {
12341 				evalops.parse_options.read_precision = (ReadPrecisionMode) v;
12342 				expression_format_updated(true);
12343 			} else {
12344 				gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_read_precision")), v != DONT_READ_PRECISION);
12345 			}
12346 		}
12347 	} else {
12348 		if(i_underscore == string::npos) {
12349 			if(index != string::npos) {
12350 				if((index = svar.find_last_of(SPACES)) != string::npos) {
12351 					svar = svar.substr(0, index);
12352 					remove_blank_ends(svar);
12353 					str = str.substr(index + 1);
12354 					remove_blank_ends(str);
12355 					svalue = str;
12356 					gsub("_", " ", svar);
12357 					goto set_option_place;
12358 				}
12359 			}
12360 			if(!empty_value && !svalue.empty()) {
12361 				svar += " ";
12362 				svar += svalue;
12363 				svalue = "1";
12364 				empty_value = true;
12365 				goto set_option_place;
12366 			}
12367 		}
12368 		CALCULATOR->error(true, "Unrecognized option: %s.", svar.c_str(), NULL);
12369 	}
12370 }
12371 
12372 /*
12373 	calculate entered expression and display result
12374 */
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)12375 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) {
12376 
12377 	if(block_expression_execution || exit_in_progress) return;
12378 
12379 	string saved_execute_str = execute_str;
12380 
12381 	if(b_busy || b_busy_result || b_busy_expression || b_busy_command) return;
12382 
12383 	if(completion_timeout_id != 0) {
12384 		g_source_remove(completion_timeout_id);
12385 		completion_timeout_id = 0;
12386 	}
12387 
12388 	b_busy = true;
12389 	b_busy_expression = true;
12390 
12391 	bool do_factors = false, do_pfe = false, do_expand = false, do_ceu = execute_str.empty(), do_bases = false, do_calendars = false;
12392 	if(do_stack && !rpn_mode) do_stack = false;
12393 	if(do_stack && do_mathoperation && f && stack_index == 0) do_stack = false;
12394 	if(!do_stack) stack_index = 0;
12395 
12396 	if(!mbak_convert.isUndefined() && stack_index == 0) mbak_convert.setUndefined();
12397 
12398 	if(execute_str.empty()) {
12399 		to_fraction = false; to_prefix = 0; to_base = 0; to_bits = 0; to_nbase.clear(); to_caf = -1;
12400 	}
12401 
12402 	if(str.empty() && !do_mathoperation) {
12403 		if(do_stack) {
12404 			GtkTreeIter iter;
12405 			gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(stackstore), &iter, NULL, stack_index);
12406 			gchar *gstr;
12407 			gtk_tree_model_get(GTK_TREE_MODEL(stackstore), &iter, 1, &gstr, -1);
12408 			str = gstr;
12409 			g_free(gstr);
12410 		} else {
12411 			GtkTextIter istart, iend;
12412 			gtk_text_buffer_get_start_iter(expressionbuffer, &istart);
12413 			gtk_text_buffer_get_end_iter(expressionbuffer, &iend);
12414 			gchar *gstr = gtk_text_buffer_get_text(expressionbuffer, &istart, &iend, FALSE);
12415 			str = gstr;
12416 			g_free(gstr);
12417 			if(!force && (expression_has_changed || str.find_first_not_of(SPACES) == string::npos)) {
12418 				b_busy = false;
12419 				b_busy_expression = false;
12420 				return;
12421 			}
12422 			expression_has_changed = false;
12423 			if(!do_mathoperation && !str.empty()) add_to_expression_history(str);
12424 		}
12425 	}
12426 	do_timeout = false;
12427 
12428 	string to_str, str_conv;
12429 
12430 	if(execute_str.empty()) {
12431 		bool double_tag = false;
12432 		to_str = CALCULATOR->parseComments(str, evalops.parse_options, &double_tag);
12433 		if(!to_str.empty()) {
12434 			if(str.empty()) {
12435 				if(!double_tag && current_inhistory_index >= 0) {
12436 					clear_expression_text();
12437 					CALCULATOR->message(MESSAGE_INFORMATION, to_str.c_str(), NULL);
12438 					if(!display_errors(&history_index, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")), &current_inhistory_index, 3)) update_expression_icons(EXPRESSION_CLEAR);
12439 					do_timeout = true;
12440 					b_busy = false;
12441 					b_busy_expression = false;
12442 					return;
12443 				}
12444 				execute_str = CALCULATOR->f_message->referenceName();
12445 				execute_str += "(";
12446 				execute_str += to_str;
12447 				execute_str += ")";
12448 			} else {
12449 				CALCULATOR->message(MESSAGE_INFORMATION, to_str.c_str(), NULL);
12450 			}
12451 		}
12452 		// qalc command
12453 		bool b_command = false;
12454 		if(str[0] == '/' && str.length() > 1) {
12455 			size_t i = str.find_first_not_of(SPACES, 1);
12456 			if(i != string::npos && str[i] > 0 && is_not_in(NUMBER_ELEMENTS OPERATORS, str[i])) {
12457 				b_command = true;
12458 			}
12459 		}
12460 		if(b_command) {
12461 			str.erase(0, 1);
12462 			remove_blank_ends(str);
12463 			size_t slen = str.length();
12464 			size_t ispace = str.find_first_of(SPACES);
12465 			string scom;
12466 			if(ispace == string::npos) {
12467 				scom = "";
12468 			} else {
12469 				scom = str.substr(1, ispace);
12470 			}
12471 			if(equalsIgnoreCase(scom, "convert") || equalsIgnoreCase(scom, "to")) {
12472 				str = string("to") + str.substr(ispace, slen - ispace);
12473 				b_command = false;
12474 			} else if((str.length() > 2 && str[0] == '-' && str[1] == '>') || (str.length() > 3 && str[0] == '\xe2' && ((str[1] == '\x86' && str[2] == '\x92') || (str[1] == '\x9e' && (unsigned char) str[2] >= 148 && (unsigned char) str[3] <= 191)))) {
12475 				b_command = false;
12476 			} else if(str == "M+" || str == "M-" || str == "M−" || str == "MS" || str == "MC") {
12477 				b_command = false;
12478 			}
12479 		}
12480 		if(b_command) {
12481 			remove_blank_ends(str);
12482 			size_t slen = str.length();
12483 			size_t ispace = str.find_first_of(SPACES);
12484 			string scom;
12485 			if(ispace == string::npos) {
12486 				scom = "";
12487 			} else {
12488 				scom = str.substr(0, ispace);
12489 			}
12490 			b_busy = false;
12491 			b_busy_expression = false;
12492 			if(equalsIgnoreCase(scom, "set")) {
12493 				set_previous_expression();
12494 				expression_has_changed = false;
12495 				str = str.substr(ispace + 1, slen - (ispace + 1));
12496 				set_option(str);
12497 			} else if(equalsIgnoreCase(scom, "save") || equalsIgnoreCase(scom, "store")) {
12498 				str = str.substr(ispace + 1, slen - (ispace + 1));
12499 				remove_blank_ends(str);
12500 				if(equalsIgnoreCase(str, "mode")) save_mode();
12501 				else if(equalsIgnoreCase(str, "definitions")) save_defs();
12502 				else {
12503 					string name = str, cat, title;
12504 					if(str[0] == '\"') {
12505 						size_t i = str.find('\"', 1);
12506 						if(i != string::npos) {
12507 							name = str.substr(1, i - 1);
12508 							str = str.substr(i + 1, str.length() - (i + 1));
12509 							remove_blank_ends(str);
12510 						} else {
12511 							str = "";
12512 						}
12513 					} else {
12514 						size_t i = str.find_first_of(SPACES, 1);
12515 						if(i != string::npos) {
12516 							name = str.substr(0, i);
12517 							str = str.substr(i + 1, str.length() - (i + 1));
12518 							remove_blank_ends(str);
12519 						} else {
12520 							str = "";
12521 						}
12522 						bool catset = false;
12523 						if(str.empty()) {
12524 							cat = CALCULATOR->temporaryCategory();
12525 						} else {
12526 							if(str[0] == '\"') {
12527 								size_t i = str.find('\"', 1);
12528 								if(i != string::npos) {
12529 									cat = str.substr(1, i - 1);
12530 									title = str.substr(i + 1, str.length() - (i + 1));
12531 									remove_blank_ends(title);
12532 								}
12533 							} else {
12534 								size_t i = str.find_first_of(SPACES, 1);
12535 								if(i != string::npos) {
12536 									cat = str.substr(0, i);
12537 									title = str.substr(i + 1, str.length() - (i + 1));
12538 									remove_blank_ends(title);
12539 								}
12540 							}
12541 							catset = true;
12542 						}
12543 						bool b = true;
12544 						if(!CALCULATOR->variableNameIsValid(name)) {
12545 							CALCULATOR->error(true, "Illegal name: %s.", name.c_str(), NULL);
12546 							b = false;
12547 						}
12548 						Variable *v = NULL;
12549 						if(b) v = CALCULATOR->getActiveVariable(name);
12550 						if(b && ((!v && CALCULATOR->variableNameTaken(name)) || (v && (!v->isKnown() || !v->isLocal())))) {
12551 							CALCULATOR->error(true, "A unit or variable with the same name (%s) already exists.", name.c_str(), NULL);
12552 							b = false;
12553 						}
12554 						if(b) {
12555 							if(v && v->isLocal() && v->isKnown()) {
12556 								if(catset) v->setCategory(cat);
12557 								if(!title.empty()) v->setTitle(title);
12558 								((KnownVariable*) v)->set(*mstruct);
12559 								if(v->countNames() == 0) {
12560 									ExpressionName ename(name);
12561 									ename.reference = true;
12562 									v->setName(ename, 1);
12563 								} else {
12564 									v->setName(name, 1);
12565 								}
12566 							} else {
12567 								CALCULATOR->addVariable(new KnownVariable(cat, name, *mstruct, title));
12568 							}
12569 							update_vmenu();
12570 						}
12571 					}
12572 				}
12573 			} else if(equalsIgnoreCase(scom, "variable")) {
12574 				str = str.substr(ispace + 1, slen - (ispace + 1));
12575 				remove_blank_ends(str);
12576 				string name = str, expr;
12577 				if(str[0] == '\"') {
12578 					size_t i = str.find('\"', 1);
12579 					if(i != string::npos) {
12580 						name = str.substr(1, i - 1);
12581 						str = str.substr(i + 1, str.length() - (i + 1));
12582 						remove_blank_ends(str);
12583 					} else {
12584 						str = "";
12585 					}
12586 				} else {
12587 					size_t i = str.find_first_of(SPACES, 1);
12588 					if(i != string::npos) {
12589 						name = str.substr(0, i);
12590 						str = str.substr(i + 1, str.length() - (i + 1));
12591 						remove_blank_ends(str);
12592 					} else {
12593 						str = "";
12594 					}
12595 				}
12596 				if(str.length() >= 2 && str[0] == '\"' && str[str.length() - 1] == '\"') str = str.substr(1, str.length() - 2);
12597 				expr = str;
12598 				bool b = true;
12599 				if(!CALCULATOR->variableNameIsValid(name)) {
12600 					CALCULATOR->error(true, "Illegal name: %s.", name.c_str(), NULL);
12601 					b = false;
12602 				}
12603 				Variable *v = NULL;
12604 				if(b) v = CALCULATOR->getActiveVariable(name);
12605 				if(b && ((!v && CALCULATOR->variableNameTaken(name)) || (v && (!v->isKnown() || !v->isLocal())))) {
12606 					CALCULATOR->error(true, "A unit or variable with the same name (%s) already exists.", name.c_str(), NULL);
12607 					b = false;
12608 				}
12609 				if(b) {
12610 					if(v && v->isLocal() && v->isKnown()) {
12611 						((KnownVariable*) v)->set(expr);
12612 						if(v->countNames() == 0) {
12613 							ExpressionName ename(name);
12614 							ename.reference = true;
12615 							v->setName(ename, 1);
12616 						} else {
12617 							v->setName(name, 1);
12618 						}
12619 					} else {
12620 						CALCULATOR->addVariable(new KnownVariable("", name, expr));
12621 					}
12622 					update_vmenu();
12623 				}
12624 			} else if(equalsIgnoreCase(scom, "function")) {
12625 				str = str.substr(ispace + 1, slen - (ispace + 1));
12626 				remove_blank_ends(str);
12627 				string name = str, expr;
12628 				if(str[0] == '\"') {
12629 					size_t i = str.find('\"', 1);
12630 					if(i != string::npos) {
12631 						name = str.substr(1, i - 1);
12632 						str = str.substr(i + 1, str.length() - (i + 1));
12633 						remove_blank_ends(str);
12634 					} else {
12635 						str = "";
12636 					}
12637 				} else {
12638 					size_t i = str.find_first_of(SPACES, 1);
12639 					if(i != string::npos) {
12640 						name = str.substr(0, i);
12641 						str = str.substr(i + 1, str.length() - (i + 1));
12642 						remove_blank_ends(str);
12643 					} else {
12644 						str = "";
12645 					}
12646 				}
12647 				if(str.length() >= 2 && str[0] == '\"' && str[str.length() - 1] == '\"') str = str.substr(1, str.length() - 2);
12648 				expr = str;
12649 				bool b = true;
12650 				if(!CALCULATOR->functionNameIsValid(name)) {
12651 					CALCULATOR->error(true, "Illegal name: %s.", name.c_str(), NULL);
12652 					b = false;
12653 				}
12654 				MathFunction *f = CALCULATOR->getActiveFunction(name);
12655 				if(b && ((!f && CALCULATOR->functionNameTaken(name)) || (f && (!f->isLocal() || f->subtype() != SUBTYPE_USER_FUNCTION)))) {
12656 					CALCULATOR->error(true, "A function with the same name (%s) already exists.", name.c_str(), NULL);
12657 					b = false;
12658 				}
12659 				if(b) {
12660 					if(expr.find("\\") == string::npos) {
12661 						gsub("x", "\\x", expr);
12662 						gsub("y", "\\y", expr);
12663 						gsub("z", "\\z", expr);
12664 					}
12665 					if(f && f->isLocal() && f->subtype() == SUBTYPE_USER_FUNCTION) {
12666 						((UserFunction*) f)->setFormula(expr);
12667 						if(f->countNames() == 0) {
12668 							ExpressionName ename(name);
12669 							ename.reference = true;
12670 							f->setName(ename, 1);
12671 						} else {
12672 							f->setName(name, 1);
12673 						}
12674 					} else {
12675 						CALCULATOR->addFunction(new UserFunction("", name, expr));
12676 					}
12677 					update_fmenu();
12678 				}
12679 			} else if(equalsIgnoreCase(scom, "delete")) {
12680 				str = str.substr(ispace + 1, slen - (ispace + 1));
12681 				remove_blank_ends(str);
12682 				Variable *v = CALCULATOR->getActiveVariable(str);
12683 				if(v && v->isLocal()) {
12684 					v->destroy();
12685 					update_vmenu();
12686 				} else {
12687 					MathFunction *f = CALCULATOR->getActiveFunction(str);
12688 					if(f && f->isLocal()) {
12689 						f->destroy();
12690 						update_fmenu();
12691 					} else {
12692 						CALCULATOR->error(true, "No user-defined variable or function with the specified name (%s) exist.", str.c_str(), NULL);
12693 					}
12694 				}
12695 			} else if(equalsIgnoreCase(scom, "base")) {
12696 				set_previous_expression();
12697 				expression_has_changed = false;
12698 				set_option(str);
12699 			} else if(equalsIgnoreCase(scom, "assume")) {
12700 				set_previous_expression();
12701 				expression_has_changed = false;
12702 				string str2 = "assumptions ";
12703 				set_option(str2 + str.substr(ispace + 1, slen - (ispace + 1)));
12704 			} else if(equalsIgnoreCase(scom, "rpn")) {
12705 				str = str.substr(ispace + 1, slen - (ispace + 1));
12706 				remove_blank_ends(str);
12707 				if(equalsIgnoreCase(str, "syntax")) {
12708 					gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_rpn_mode")), FALSE);
12709 					gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_rpn_syntax")), TRUE);
12710 				} else if(equalsIgnoreCase(str, "stack")) {
12711 					if(evalops.parse_options.parsing_mode == PARSING_MODE_RPN) {
12712 						gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_adaptive_parsing")), TRUE);
12713 					}
12714 					gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_rpn_mode")), TRUE);
12715 				} else {
12716 					int v = s2b(str);
12717 					if(v < 0) {
12718 						CALCULATOR->error(true, "Illegal value: %s.", str.c_str(), NULL);
12719 					} else if(v) {
12720 						gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_rpn_syntax")), TRUE);
12721 						gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_rpn_mode")), TRUE);
12722 					} else {
12723 						if(evalops.parse_options.parsing_mode == PARSING_MODE_RPN) {
12724 							gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_adaptive_parsing")), TRUE);
12725 						}
12726 						gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_rpn_mode")), FALSE);
12727 					}
12728 				}
12729 			} else if(equalsIgnoreCase(str, "exrates")) {
12730 				set_previous_expression();
12731 				expression_has_changed = false;
12732 				on_menu_item_fetch_exchange_rates_activate(NULL, NULL);
12733 			} else if(equalsIgnoreCase(str, "stack")) {
12734 				gtk_expander_set_expanded(GTK_EXPANDER(expander_stack), TRUE);
12735 			} else if(equalsIgnoreCase(str, "swap")) {
12736 				if(CALCULATOR->RPNStackSize() > 1) {
12737 					gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(stackview)));
12738 					on_button_registerswap_clicked(NULL, NULL);
12739 				}
12740 			} else if(equalsIgnoreCase(scom, "swap")) {
12741 				if(CALCULATOR->RPNStackSize() > 1) {
12742 					int index1 = 0, index2 = 0;
12743 					str = str.substr(ispace + 1, slen - (ispace + 1));
12744 					string str2 = "";
12745 					remove_blank_ends(str);
12746 					ispace = str.find_first_of(SPACES);
12747 					if(ispace != string::npos) {
12748 						str2 = str.substr(ispace + 1, str.length() - (ispace + 1));
12749 						str = str.substr(0, ispace);
12750 						remove_blank_ends(str2);
12751 						remove_blank_ends(str);
12752 					}
12753 					index1 = s2i(str);
12754 					if(str2.empty()) index2 = 1;
12755 					else index2 = s2i(str2);
12756 					if(index1 < 0) index1 = (int) CALCULATOR->RPNStackSize() + 1 + index1;
12757 					if(index2 < 0) index2 = (int) CALCULATOR->RPNStackSize() + 1 + index2;
12758 					if(index1 <= 0 || index1 > (int) CALCULATOR->RPNStackSize() || (!str2.empty() && (index2 <= 0 || index2 > (int) CALCULATOR->RPNStackSize()))) {
12759 						CALCULATOR->error(true, "Missing stack index: %s.", i2s(index1).c_str(), NULL);
12760 					} else if(index2 != 1 && index1 != 1) {
12761 						CALCULATOR->error(true, "Unsupported command: %s.", str.c_str(), NULL);
12762 					} else if(index1 != index2) {
12763 						if(index1 == 1) index1 = index2;
12764 						GtkTreeIter iter;
12765 						if(gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(stackstore), &iter, NULL, index1 - 1)) {
12766 							gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(stackview)), &iter);
12767 							on_button_registerswap_clicked(NULL, NULL);
12768 							gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(stackview)));
12769 						}
12770 					}
12771 				}
12772 			} else if(equalsIgnoreCase(scom, "move")) {
12773 				CALCULATOR->error(true, "Unsupported command: %s.", scom.c_str(), NULL);
12774 			} else if(equalsIgnoreCase(str, "rotate")) {
12775 				if(CALCULATOR->RPNStackSize() > 1) {
12776 					gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(stackview)));
12777 					on_button_registerdown_clicked(NULL, NULL);
12778 				}
12779 			} else if(equalsIgnoreCase(scom, "rotate")) {
12780 				if(CALCULATOR->RPNStackSize() > 1) {
12781 					str = str.substr(ispace + 1, slen - (ispace + 1));
12782 					remove_blank_ends(str);
12783 					if(equalsIgnoreCase(str, "up")) {
12784 						gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(stackview)));
12785 						on_button_registerup_clicked(NULL, NULL);
12786 					} else if(equalsIgnoreCase(str, "down")) {
12787 						gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(stackview)));
12788 						on_button_registerdown_clicked(NULL, NULL);
12789 					} else {
12790 						CALCULATOR->error(true, "Illegal value: %s.", str.c_str(), NULL);
12791 					}
12792 				}
12793 			} else if(equalsIgnoreCase(str, "copy")) {
12794 				if(CALCULATOR->RPNStackSize() > 0) {
12795 					gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(stackview)));
12796 					on_button_copyregister_clicked(NULL, NULL);
12797 				}
12798 			} else if(equalsIgnoreCase(scom, "copy")) {
12799 				if(CALCULATOR->RPNStackSize() > 0) {
12800 					str = str.substr(ispace + 1, slen - (ispace + 1));
12801 					remove_blank_ends(str);
12802 					int index1 = s2i(str);
12803 					if(index1 < 0) index1 = (int) CALCULATOR->RPNStackSize() + 1 + index1;
12804 					if(index1 <= 0 || index1 > (int) CALCULATOR->RPNStackSize()) {
12805 						CALCULATOR->error(true, "Missing stack index: %s.", i2s(index1).c_str(), NULL);
12806 					} else {
12807 						GtkTreeIter iter;
12808 						if(gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(stackstore), &iter, NULL, index1 - 1)) {
12809 							gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(stackview)), &iter);
12810 							on_button_copyregister_clicked(NULL, NULL);
12811 							gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(stackview)));
12812 						}
12813 					}
12814 				}
12815 			} else if(equalsIgnoreCase(str, "clear stack")) {
12816 				if(CALCULATOR->RPNStackSize() > 0) on_button_clearstack_clicked(NULL, NULL);
12817 			} else if(equalsIgnoreCase(str, "pop")) {
12818 				if(CALCULATOR->RPNStackSize() > 0) {
12819 					gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(stackview)));
12820 					on_button_deleteregister_clicked(NULL, NULL);
12821 				}
12822 			} else if(equalsIgnoreCase(scom, "pop")) {
12823 				if(CALCULATOR->RPNStackSize() > 0) {
12824 					str = str.substr(ispace + 1, slen - (ispace + 1));
12825 					int index1 = s2i(str);
12826 					if(index1 < 0) index1 = (int) CALCULATOR->RPNStackSize() + 1 + index1;
12827 					if(index1 <= 0 || index1 > (int) CALCULATOR->RPNStackSize()) {
12828 						CALCULATOR->error(true, "Missing stack index: %s.", i2s(index1).c_str(), NULL);
12829 					} else {
12830 						GtkTreeIter iter;
12831 						if(gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(stackstore), &iter, NULL, index1 - 1)) {
12832 							gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(stackview)), &iter);
12833 							on_button_deleteregister_clicked(NULL, NULL);
12834 						}
12835 					}
12836 				}
12837 			} else if(equalsIgnoreCase(str, "factor")) {
12838 				set_previous_expression();
12839 				expression_has_changed = false;
12840 				executeCommand(COMMAND_FACTORIZE);
12841 			} else if(equalsIgnoreCase(str, "partial fraction")) {
12842 				set_previous_expression();
12843 				expression_has_changed = false;
12844 				executeCommand(COMMAND_EXPAND_PARTIAL_FRACTIONS);
12845 			} else if(equalsIgnoreCase(str, "simplify") || equalsIgnoreCase(str, "expand")) {
12846 				set_previous_expression();
12847 				expression_has_changed = false;
12848 				executeCommand(COMMAND_EXPAND);
12849 			} else if(equalsIgnoreCase(str, "exact")) {
12850 				set_previous_expression();
12851 				expression_has_changed = false;
12852 				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "button_exact")), TRUE);
12853 			} else if(equalsIgnoreCase(str, "approximate") || str == "approx") {
12854 				set_previous_expression();
12855 				expression_has_changed = false;
12856 				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "button_exact")), FALSE);
12857 			} else if(equalsIgnoreCase(str, "mode")) {
12858 				CALCULATOR->error(true, "Unsupported command: %s.", str.c_str(), NULL);
12859 			} else if(equalsIgnoreCase(str, "help") || str == "?") {
12860 				show_help("index.html", gtk_builder_get_object(main_builder, "main_window"));
12861 			} else if(equalsIgnoreCase(str, "list")) {
12862 				CALCULATOR->error(true, "Unsupported command: %s.", str.c_str(), NULL);
12863 			} else if(equalsIgnoreCase(scom, "list") || equalsIgnoreCase(scom, "find") || equalsIgnoreCase(scom, "info") || equalsIgnoreCase(scom, "help")) {
12864 				str = str.substr(ispace + 1);
12865 				remove_blank_ends(str);
12866 				char list_type = 0;
12867 				GtkTreeIter iter;
12868 				if(equalsIgnoreCase(scom, "list") || equalsIgnoreCase(scom, "find")) {
12869 					size_t i = str.find_first_of(SPACES);
12870 					string str1, str2;
12871 					if(i == string::npos) {
12872 						str1 = str;
12873 					} else {
12874 						str1 = str.substr(0, i);
12875 						str2 = str.substr(i + 1);
12876 						remove_blank_ends(str2);
12877 					}
12878 					if(equalsIgnoreCase(str1, "currencies")) list_type = 'c';
12879 					else if(equalsIgnoreCase(str1, "functions")) list_type = 'f';
12880 					else if(equalsIgnoreCase(str1, "variables")) list_type = 'v';
12881 					else if(equalsIgnoreCase(str1, "units")) list_type = 'u';
12882 					else if(equalsIgnoreCase(str1, "prefixes")) list_type = 'p';
12883 					if(list_type == 'c') {
12884 						manage_units();
12885 						string s_cat = CALCULATOR->u_euro->category();
12886 						GtkTreeIter iter1;
12887 						if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tUnitCategories_store), &iter1) && gtk_tree_model_iter_children(GTK_TREE_MODEL(tUnitCategories_store), &iter, &iter1)) {
12888 							do {
12889 								gchar *gstr;
12890 								gtk_tree_model_get(GTK_TREE_MODEL(tUnitCategories_store), &iter, 0, &gstr, -1);
12891 								if(s_cat == gstr) {
12892 									gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitCategories)), &iter);
12893 									g_free(gstr);
12894 									break;
12895 								}
12896 								g_free(gstr);
12897 							} while(gtk_tree_model_iter_next(GTK_TREE_MODEL(tUnitCategories_store), &iter));
12898 						}
12899 						gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(units_builder, "units_entry_search")), str2.c_str());
12900 					} else if(list_type == 'f') {
12901 						manage_functions();
12902 						if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tFunctionCategories_store), &iter)) {
12903 							gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tFunctionCategories)), &iter);
12904 						}
12905 						gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(functions_builder, "functions_entry_search")), str2.c_str());
12906 					} else if(list_type == 'v') {
12907 						manage_variables();
12908 						if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tUnitCategories_store), &iter)) {
12909 							gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitCategories)), &iter);
12910 						}
12911 						gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(units_builder, "units_entry_search")), str2.c_str());
12912 					} else if(list_type == 'u') {
12913 						manage_units();
12914 						if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tUnitCategories_store), &iter)) {
12915 							gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitCategories)), &iter);
12916 						}
12917 						gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(units_builder, "units_entry_search")), str2.c_str());
12918 					} else if(list_type == 'p') {
12919 						CALCULATOR->error(true, "Unsupported command: %s.", str.c_str(), NULL);
12920 					}
12921 				}
12922 				if(list_type == 0) {
12923 					ExpressionItem *item = CALCULATOR->getActiveExpressionItem(str);
12924 					if(item) {
12925 						if(item->type() == TYPE_UNIT) {
12926 							manage_units();
12927 							if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tUnitCategories_store), &iter)) {
12928 								gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitCategories)), &iter);
12929 							}
12930 							gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(units_builder, "units_entry_search")), str.c_str());
12931 						} else if(item->type() == TYPE_FUNCTION) {
12932 							manage_functions();
12933 							if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tFunctionCategories_store), &iter)) {
12934 								gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tFunctionCategories)), &iter);
12935 							}
12936 							gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(functions_builder, "functions_entry_search")), str.c_str());
12937 						} else if(item->type() == TYPE_VARIABLE) {
12938 							manage_variables();
12939 							if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tVariableCategories_store), &iter)) {
12940 								gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tVariableCategories)), &iter);
12941 							}
12942 							gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(variables_builder, "variables_entry_search")), str.c_str());
12943 						}
12944 					} else {
12945 						CALCULATOR->error(true, "No function, variable, or unit with the specified name (%s) was found.", str.c_str(), NULL);
12946 					}
12947 				}
12948 			} else if(equalsIgnoreCase(str, "quit") || equalsIgnoreCase(str, "exit")) {
12949 				on_gcalc_exit(NULL, NULL, NULL);
12950 			} else {
12951 				CALCULATOR->error(true, "Unknown command: %s.", str.c_str(), NULL);
12952 			}
12953 			GtkTextIter istart, iend;
12954 			gtk_text_buffer_get_start_iter(expressionbuffer, &istart);
12955 			gtk_text_buffer_get_end_iter(expressionbuffer, &iend);
12956 			gtk_text_buffer_select_range(expressionbuffer, &istart, &iend);
12957 			if(current_inhistory_index < 0) current_inhistory_index = 0;
12958 			if(!display_errors(&history_index, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")), &current_inhistory_index, 3)) update_expression_icons(EXPRESSION_CLEAR);
12959 			do_timeout = true;
12960 			return;
12961 		}
12962 	}
12963 
12964 	if(execute_str.empty()) {
12965 		if(str == "MC") {
12966 			b_busy = false;
12967 			b_busy_expression = false;
12968 			set_previous_expression();
12969 			expression_has_changed = false;
12970 			memory_clear();
12971 			setResult(NULL, false, false);
12972 			return;
12973 		} else if(str == "MS") {
12974 			b_busy = false;
12975 			b_busy_expression = false;
12976 			set_previous_expression();
12977 			expression_has_changed = false;
12978 			memory_store();
12979 			setResult(NULL, false, false);
12980 			return;
12981 		} else if(str == "M+") {
12982 			b_busy = false;
12983 			b_busy_expression = false;
12984 			set_previous_expression();
12985 			expression_has_changed = false;
12986 			memory_add();
12987 			setResult(NULL, false, false);
12988 			return;
12989 		} else if(str == "M-" || str == "M−") {
12990 			b_busy = false;
12991 			b_busy_expression = false;
12992 			set_previous_expression();
12993 			expression_has_changed = false;
12994 			memory_subtract();
12995 			setResult(NULL, false, false);
12996 			return;
12997 		}
12998 	}
12999 
13000 	ComplexNumberForm cnf_bak = evalops.complex_number_form;
13001 	bool b_units_saved = evalops.parse_options.units_enabled;
13002 	AutoPostConversion save_auto_post_conversion = evalops.auto_post_conversion;
13003 	MixedUnitsConversion save_mixed_units_conversion = evalops.mixed_units_conversion;
13004 
13005 	bool had_to_expression = false;
13006 	string from_str = str;
13007 	bool last_is_space = !from_str.empty() && is_in(SPACES, from_str[from_str.length() - 1]);
13008 	if(execute_str.empty() && CALCULATOR->separateToExpression(from_str, to_str, evalops, true, !do_stack && !auto_calculate)) {
13009 		remove_duplicate_blanks(to_str);
13010 		had_to_expression = true;
13011 		string str_left;
13012 		string to_str1, to_str2;
13013 		bool do_to = false;
13014 		while(true) {
13015 			if(!from_str.empty()) {
13016 				if(last_is_space) to_str += " ";
13017 				CALCULATOR->separateToExpression(to_str, str_left, evalops, true, false);
13018 				remove_blank_ends(to_str);
13019 			}
13020 			size_t ispace = to_str.find_first_of(SPACES);
13021 			if(ispace != string::npos) {
13022 				to_str1 = to_str.substr(0, ispace);
13023 				remove_blank_ends(to_str1);
13024 				to_str2 = to_str.substr(ispace + 1);
13025 				remove_blank_ends(to_str2);
13026 			}
13027 			if(equalsIgnoreCase(to_str, "hex") || equalsIgnoreCase(to_str, "hexadecimal") || equalsIgnoreCase(to_str, _("hexadecimal"))) {
13028 				to_base = BASE_HEXADECIMAL;
13029 				do_to = true;
13030 			} else if(equalsIgnoreCase(to_str, "oct") || equalsIgnoreCase(to_str, "octal") || equalsIgnoreCase(to_str, _("octal"))) {
13031 				to_base = BASE_OCTAL;
13032 				do_to = true;
13033 			} else if(equalsIgnoreCase(to_str, "dec") || equalsIgnoreCase(to_str, "decimal") || equalsIgnoreCase(to_str, _("decimal"))) {
13034 				to_base = BASE_DECIMAL;
13035 				do_to = true;
13036 			} else if(equalsIgnoreCase(to_str, "duo") || equalsIgnoreCase(to_str, "duodecimal") || equalsIgnoreCase(to_str, _("duodecimal"))) {
13037 				to_base = BASE_DUODECIMAL;
13038 				do_to = true;
13039 			} else if(equalsIgnoreCase(to_str, "bin") || equalsIgnoreCase(to_str, "binary") || equalsIgnoreCase(to_str, _("binary"))) {
13040 				to_base = BASE_BINARY;
13041 				do_to = true;
13042 			} else if(equalsIgnoreCase(to_str, "roman") || equalsIgnoreCase(to_str, _("roman"))) {
13043 				to_base = BASE_ROMAN_NUMERALS;
13044 				do_to = true;
13045 			} else if(equalsIgnoreCase(to_str, "bijective") || equalsIgnoreCase(to_str, _("bijective"))) {
13046 				to_base = BASE_BIJECTIVE_26;
13047 				do_to = true;
13048 			} else if(equalsIgnoreCase(to_str, "sexa") || equalsIgnoreCase(to_str, "sexagesimal") || equalsIgnoreCase(to_str, _("sexagesimal"))) {
13049 				to_base = BASE_SEXAGESIMAL;
13050 				do_to = true;
13051 			} else if(equalsIgnoreCase(to_str, "fp32") || equalsIgnoreCase(to_str, "binary32") || equalsIgnoreCase(to_str, "float")) {
13052 				to_base = BASE_FP32;
13053 				do_to = true;
13054 			} else if(equalsIgnoreCase(to_str, "fp64") || equalsIgnoreCase(to_str, "binary64") || equalsIgnoreCase(to_str, "double")) {
13055 				to_base = BASE_FP64;
13056 				do_to = true;
13057 			} else if(equalsIgnoreCase(to_str, "fp16") || equalsIgnoreCase(to_str, "binary16")) {
13058 				to_base = BASE_FP16;
13059 				do_to = true;
13060 			} else if(equalsIgnoreCase(to_str, "fp80")) {
13061 				to_base = BASE_FP80;
13062 				do_to = true;
13063 			} else if(equalsIgnoreCase(to_str, "fp128") || equalsIgnoreCase(to_str, "binary128")) {
13064 				to_base = BASE_FP128;
13065 				do_to = true;
13066 			} else if(equalsIgnoreCase(to_str, "time") || equalsIgnoreCase(to_str, _("time"))) {
13067 				to_base = BASE_TIME;
13068 				do_to = true;
13069 			} else if(equalsIgnoreCase(to_str, "Unicode")) {
13070 				to_base = BASE_UNICODE;
13071 				do_to = true;
13072 			} else if(equalsIgnoreCase(to_str, "utc") || equalsIgnoreCase(to_str, "gmt")) {
13073 				printops.time_zone = TIME_ZONE_UTC;
13074 				if(from_str.empty()) {
13075 					b_busy = false;
13076 					b_busy_expression = false;
13077 					setResult(NULL, true, false, false); set_previous_expression();
13078 					printops.custom_time_zone = 0;
13079 					printops.time_zone = TIME_ZONE_LOCAL;
13080 					return;
13081 				}
13082 				do_to = true;
13083 			} else if(to_str.length() > 3 && equalsIgnoreCase(to_str.substr(0, 3), "bin") && is_in(NUMBERS, to_str[3])) {
13084 				to_base = BASE_BINARY;
13085 				int bits = s2i(to_str.substr(3));
13086 				if(bits >= 0) {
13087 					if(bits > 4096) to_bits = 4096;
13088 					else to_bits = bits;
13089 				}
13090 				do_to = true;
13091 			} else if(to_str.length() > 3 && equalsIgnoreCase(to_str.substr(0, 3), "hex") && is_in(NUMBERS, to_str[3])) {
13092 				to_base = BASE_HEXADECIMAL;
13093 				int bits = s2i(to_str.substr(3));
13094 				if(bits >= 0) {
13095 					if(bits > 4096) to_bits = 4096;
13096 					else to_bits = bits;
13097 				}
13098 				do_to = true;
13099 			} else if(to_str.length() > 3 && (equalsIgnoreCase(to_str.substr(0, 3), "utc") || equalsIgnoreCase(to_str.substr(0, 3), "gmt"))) {
13100 				to_str = to_str.substr(3);
13101 				remove_blanks(to_str);
13102 				bool b_minus = false;
13103 				if(to_str[0] == '+') {
13104 					to_str.erase(0, 1);
13105 				} else if(to_str[0] == '-') {
13106 					b_minus = true;
13107 					to_str.erase(0, 1);
13108 				} else if(to_str.find(SIGN_MINUS) == 0) {
13109 					b_minus = true;
13110 					to_str.erase(0, strlen(SIGN_MINUS));
13111 				}
13112 				unsigned int tzh = 0, tzm = 0;
13113 				int itz = 0;
13114 				if(!to_str.empty() && sscanf(to_str.c_str(), "%2u:%2u", &tzh, &tzm) > 0) {
13115 					itz = tzh * 60 + tzm;
13116 					if(b_minus) itz = -itz;
13117 				} else {
13118 					CALCULATOR->error(true, _("Time zone parsing failed."), NULL);
13119 				}
13120 				printops.time_zone = TIME_ZONE_CUSTOM;
13121 				printops.custom_time_zone = itz;
13122 				if(from_str.empty()) {
13123 					b_busy = false;
13124 					b_busy_expression = false;
13125 					setResult(NULL, true, false, false); set_previous_expression();
13126 					printops.custom_time_zone = 0;
13127 					printops.time_zone = TIME_ZONE_LOCAL;
13128 					return;
13129 				}
13130 				do_to = true;
13131 			} else if(to_str == "CET") {
13132 				printops.time_zone = TIME_ZONE_CUSTOM;
13133 				printops.custom_time_zone = 60;
13134 				if(from_str.empty()) {
13135 					b_busy = false;
13136 					b_busy_expression = false;
13137 					setResult(NULL, true, false, false); set_previous_expression();
13138 					printops.custom_time_zone = 0;
13139 					printops.time_zone = TIME_ZONE_LOCAL;
13140 					return;
13141 				}
13142 				do_to = true;
13143 			} else if(equalsIgnoreCase(to_str, "bases") || equalsIgnoreCase(to_str, _("bases"))) {
13144 				if(from_str.empty()) {
13145 					b_busy = false;
13146 					b_busy_expression = false;
13147 					set_previous_expression();
13148 					convert_number_bases(result_text.c_str());
13149 					return;
13150 				}
13151 				do_bases = true;
13152 				execute_str = from_str;
13153 			} else if(equalsIgnoreCase(to_str, "calendars") || equalsIgnoreCase(to_str, _("calendars"))) {
13154 				if(from_str.empty()) {
13155 					b_busy = false;
13156 					b_busy_expression = false;
13157 					set_previous_expression();
13158 					on_popup_menu_item_calendarconversion_activate(NULL, NULL);
13159 					return;
13160 				}
13161 				do_calendars = true;
13162 				execute_str = from_str;
13163 			} else if(equalsIgnoreCase(to_str, "rectangular") || equalsIgnoreCase(to_str, "cartesian") || equalsIgnoreCase(to_str, _("rectangular")) || equalsIgnoreCase(to_str, _("cartesian"))) {
13164 				evalops.complex_number_form = COMPLEX_NUMBER_FORM_RECTANGULAR;
13165 				to_caf = 0;
13166 				do_to = true;
13167 				if(from_str.empty()) {
13168 					b_busy = false;
13169 					b_busy_expression = false;
13170 					executeCommand(COMMAND_EVAL);
13171 					set_previous_expression();
13172 					evalops.complex_number_form = cnf_bak;
13173 					return;
13174 				}
13175 			} else if(equalsIgnoreCase(to_str, "exponential") || equalsIgnoreCase(to_str, _("exponential"))) {
13176 				evalops.complex_number_form = COMPLEX_NUMBER_FORM_EXPONENTIAL;
13177 				to_caf = 0;
13178 				do_to = true;
13179 				if(from_str.empty()) {
13180 					b_busy = false;
13181 					b_busy_expression = false;
13182 					executeCommand(COMMAND_EVAL);
13183 					set_previous_expression();
13184 					evalops.complex_number_form = cnf_bak;
13185 					return;
13186 				}
13187 			} else if(equalsIgnoreCase(to_str, "polar") || equalsIgnoreCase(to_str, _("polar"))) {
13188 				evalops.complex_number_form = COMPLEX_NUMBER_FORM_POLAR;
13189 				to_caf = 0;
13190 				do_to = true;
13191 				if(from_str.empty()) {
13192 					b_busy = false;
13193 					b_busy_expression = false;
13194 					executeCommand(COMMAND_EVAL);
13195 					set_previous_expression();
13196 					evalops.complex_number_form = cnf_bak;
13197 					return;
13198 				}
13199 				to_caf = 0;
13200 				do_to = true;
13201 			} else if(to_str == "cis") {
13202 				evalops.complex_number_form = COMPLEX_NUMBER_FORM_CIS;
13203 				to_caf = 0;
13204 				do_to = true;
13205 				if(from_str.empty()) {
13206 					b_busy = false;
13207 					b_busy_expression = false;
13208 					executeCommand(COMMAND_EVAL);
13209 					set_previous_expression();
13210 					evalops.complex_number_form = cnf_bak;
13211 					return;
13212 				}
13213 			} else if(equalsIgnoreCase(to_str, "phasor") || equalsIgnoreCase(to_str, _("phasor")) || equalsIgnoreCase(to_str, "angle") || equalsIgnoreCase(to_str, _("angle"))) {
13214 				evalops.complex_number_form = COMPLEX_NUMBER_FORM_CIS;
13215 				to_caf = 1;
13216 				do_to = true;
13217 				if(from_str.empty()) {
13218 					b_busy = false;
13219 					b_busy_expression = false;
13220 					executeCommand(COMMAND_EVAL);
13221 					set_previous_expression();
13222 					evalops.complex_number_form = cnf_bak;
13223 					return;
13224 				}
13225 			} else if(equalsIgnoreCase(to_str, "optimal") || equalsIgnoreCase(to_str, _("optimal"))) {
13226 				if(from_str.empty()) {
13227 					b_busy = false;
13228 					b_busy_expression = false;
13229 					executeCommand(COMMAND_CONVERT_OPTIMAL);
13230 					set_previous_expression();
13231 					return;
13232 				}
13233 				evalops.parse_options.units_enabled = true;
13234 				evalops.auto_post_conversion = POST_CONVERSION_OPTIMAL_SI;
13235 				str_conv = "";
13236 				do_to = true;
13237 			} else if(equalsIgnoreCase(to_str, "base") || equalsIgnoreCase(to_str, _("base"))) {
13238 				if(from_str.empty()) {
13239 					b_busy = false;
13240 					b_busy_expression = false;
13241 					executeCommand(COMMAND_CONVERT_BASE);
13242 					set_previous_expression();
13243 					return;
13244 				}
13245 				evalops.parse_options.units_enabled = true;
13246 				evalops.auto_post_conversion = POST_CONVERSION_BASE;
13247 				str_conv = "";
13248 				do_to = true;
13249 			} else if(equalsIgnoreCase(to_str, "mixed") || equalsIgnoreCase(to_str, _("mixed"))) {
13250 				evalops.parse_options.units_enabled = true;
13251 				evalops.auto_post_conversion = POST_CONVERSION_NONE;
13252 				evalops.mixed_units_conversion = MIXED_UNITS_CONVERSION_FORCE_INTEGER;
13253 				if(from_str.empty()) {
13254 					b_busy = false;
13255 					b_busy_expression = false;
13256 					if(!previous_expression.empty()) execute_expression(force, do_mathoperation, op, f, do_stack, stack_index, previous_expression);
13257 					set_previous_expression();
13258 					evalops.auto_post_conversion = save_auto_post_conversion;
13259 					evalops.mixed_units_conversion = save_mixed_units_conversion;
13260 					evalops.parse_options.units_enabled = b_units_saved;
13261 					return;
13262 				}
13263 				do_to = true;
13264 			} else if(equalsIgnoreCase(to_str, "fraction") || equalsIgnoreCase(to_str, _("fraction"))) {
13265 				do_to = true;
13266 				to_fraction = true;
13267 			} else if(equalsIgnoreCase(to_str, "factors") || equalsIgnoreCase(to_str, _("factors")) || equalsIgnoreCase(to_str, "factor")) {
13268 				if(from_str.empty()) {
13269 					b_busy = false;
13270 					b_busy_expression = false;
13271 					executeCommand(COMMAND_FACTORIZE);
13272 					set_previous_expression();
13273 					return;
13274 				}
13275 				do_factors = true;
13276 				execute_str = from_str;
13277 			} else if(equalsIgnoreCase(to_str, "partial fraction") || equalsIgnoreCase(to_str, _("partial fraction"))) {
13278 				if(from_str.empty()) {
13279 					b_busy = false;
13280 					b_busy_expression = false;
13281 					executeCommand(COMMAND_EXPAND_PARTIAL_FRACTIONS);
13282 					set_previous_expression();
13283 					return;
13284 				}
13285 				do_pfe = true;
13286 				execute_str = from_str;
13287 			} else if(equalsIgnoreCase(to_str1, "base") || equalsIgnoreCase(to_str1, _("base"))) {
13288 				base_from_string(to_str2, to_base, to_nbase);
13289 				do_to = true;
13290 			} else if(from_str.empty()) {
13291 				b_busy = false;
13292 				b_busy_expression = false;
13293 				executeCommand(COMMAND_CONVERT_STRING, true, CALCULATOR->unlocalizeExpression(to_str, evalops.parse_options));
13294 				set_previous_expression();
13295 				return;
13296 			} else {
13297 				if(to_str[0] == '?') {
13298 					to_prefix = 1;
13299 				} else if(to_str.length() > 1 && to_str[1] == '?' && (to_str[0] == 'b' || to_str[0] == 'a' || to_str[0] == 'd')) {
13300 					to_prefix = to_str[0];
13301 
13302 				}
13303 				do_to = true;
13304 				if(!str_conv.empty()) str_conv += " to ";
13305 				str_conv += to_str;
13306 			}
13307 			if(str_left.empty()) break;
13308 			to_str = str_left;
13309 		}
13310 		if(do_to) {
13311 			if(from_str.empty()) {
13312 				b_busy = false;
13313 				b_busy_expression = false;
13314 				setResult(NULL, true, false, false);
13315 				set_previous_expression();
13316 				return;
13317 			} else {
13318 				execute_str = from_str;
13319 				if(!str_conv.empty()) {
13320 					execute_str += " to ";
13321 					execute_str += str_conv;
13322 				}
13323 			}
13324 		}
13325 	}
13326 	if(execute_str.empty()) {
13327 		size_t i = str.find_first_of(SPACES LEFT_PARENTHESIS);
13328 		if(i != string::npos) {
13329 			to_str = str.substr(0, i);
13330 			if(to_str == "factor" || equalsIgnoreCase(to_str, "factorize") || equalsIgnoreCase(to_str, _("factorize"))) {
13331 				execute_str = str.substr(i + 1);
13332 				do_factors = true;
13333 			} else if(equalsIgnoreCase(to_str, "expand") || equalsIgnoreCase(to_str, _("expand"))) {
13334 				execute_str = str.substr(i + 1);
13335 				do_expand = true;
13336 			}
13337 		}
13338 	}
13339 
13340 	size_t stack_size = 0;
13341 
13342 	if(do_ceu && str_conv.empty() && gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "convert_button_continuous_conversion"))) && gtk_expander_get_expanded(GTK_EXPANDER(expander_convert)) && !minimal_mode) {
13343 		ParseOptions pa = evalops.parse_options; pa.base = 10;
13344 		string ceu_str = CALCULATOR->unlocalizeExpression(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(main_builder, "convert_entry_unit"))), pa);
13345 		remove_blank_ends(ceu_str);
13346 		if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "convert_button_set_missing_prefixes"))) && !ceu_str.empty()) {
13347 			if(!ceu_str.empty() && ceu_str[0] != '0' && ceu_str[0] != '?' && ceu_str[0] != '+' && ceu_str[0] != '-' && (ceu_str.length() == 1 || ceu_str[1] != '?')) {
13348 				ceu_str = "?" + ceu_str;
13349 			}
13350 		}
13351 		if(ceu_str.empty()) {
13352 			parsed_tostruct->setUndefined();
13353 		} else {
13354 			if(ceu_str[0] == '?') {
13355 				to_prefix = 1;
13356 			} else if(ceu_str.length() > 1 && ceu_str[1] == '?' && (ceu_str[0] == 'b' || ceu_str[0] == 'a' || ceu_str[0] == 'd')) {
13357 				to_prefix = ceu_str[0];
13358 			}
13359 			parsed_tostruct->set(ceu_str);
13360 		}
13361 	} else {
13362 		parsed_tostruct->setUndefined();
13363 	}
13364 	CALCULATOR->resetExchangeRatesUsed();
13365 	if(do_stack) {
13366 		stack_size = CALCULATOR->RPNStackSize();
13367 		if(do_mathoperation && f) {
13368 			CALCULATOR->getRPNRegister(stack_index + 1)->transform(f);
13369 			parsed_mstruct->set(*CALCULATOR->getRPNRegister(stack_index + 1));
13370 			CALCULATOR->calculateRPNRegister(stack_index + 1, 0, evalops);
13371 		} else {
13372 			CALCULATOR->setRPNRegister(stack_index + 1, CALCULATOR->unlocalizeExpression(execute_str.empty() ? str : execute_str, evalops.parse_options), 0, evalops, parsed_mstruct, parsed_tostruct);
13373 		}
13374 	} else if(rpn_mode) {
13375 		stack_size = CALCULATOR->RPNStackSize();
13376 		if(do_mathoperation) {
13377 			if(mstruct) lastx = *mstruct;
13378 			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_lastx")), TRUE);
13379 			if(f) CALCULATOR->calculateRPN(f, 0, evalops, parsed_mstruct);
13380 			else CALCULATOR->calculateRPN(op, 0, evalops, parsed_mstruct);
13381 		} else {
13382 			string str2 = CALCULATOR->unlocalizeExpression(execute_str.empty() ? str : execute_str, evalops.parse_options);
13383 			CALCULATOR->parseSigns(str2);
13384 			remove_blank_ends(str2);
13385 			MathStructure lastx_bak(lastx);
13386 			if(mstruct) lastx = *mstruct;
13387 			if(str2.length() == 1) {
13388 				do_mathoperation = true;
13389 				switch(str2[0]) {
13390 					case '^': {CALCULATOR->calculateRPN(OPERATION_RAISE, 0, evalops, parsed_mstruct); break;}
13391 					case '+': {CALCULATOR->calculateRPN(OPERATION_ADD, 0, evalops, parsed_mstruct); break;}
13392 					case '-': {CALCULATOR->calculateRPN(OPERATION_SUBTRACT, 0, evalops, parsed_mstruct); break;}
13393 					case '*': {CALCULATOR->calculateRPN(OPERATION_MULTIPLY, 0, evalops, parsed_mstruct); break;}
13394 					case '/': {CALCULATOR->calculateRPN(OPERATION_DIVIDE, 0, evalops, parsed_mstruct); break;}
13395 					case '&': {CALCULATOR->calculateRPN(OPERATION_BITWISE_AND, 0, evalops, parsed_mstruct); break;}
13396 					case '|': {CALCULATOR->calculateRPN(OPERATION_BITWISE_OR, 0, evalops, parsed_mstruct); break;}
13397 					case '~': {CALCULATOR->calculateRPNBitwiseNot(0, evalops, parsed_mstruct); break;}
13398 					case '!': {CALCULATOR->calculateRPN(CALCULATOR->f_factorial, 0, evalops, parsed_mstruct); break;}
13399 					case '>': {CALCULATOR->calculateRPN(OPERATION_GREATER, 0, evalops, parsed_mstruct); break;}
13400 					case '<': {CALCULATOR->calculateRPN(OPERATION_LESS, 0, evalops, parsed_mstruct); break;}
13401 					case '=': {CALCULATOR->calculateRPN(OPERATION_EQUALS, 0, evalops, parsed_mstruct); break;}
13402 					case '\\': {
13403 						MathFunction *fdiv = CALCULATOR->getActiveFunction("div");
13404 						if(fdiv) {
13405 							CALCULATOR->calculateRPN(fdiv, 0, evalops, parsed_mstruct);
13406 							break;
13407 						}
13408 					}
13409 					default: {do_mathoperation = false;}
13410 				}
13411 			} else if(str2.length() == 2) {
13412 				if(str2 == "**") {
13413 					CALCULATOR->calculateRPN(OPERATION_RAISE, 0, evalops, parsed_mstruct);
13414 					do_mathoperation = true;
13415 				} else if(str2 == "!!") {
13416 					CALCULATOR->calculateRPN(CALCULATOR->f_factorial2, 0, evalops, parsed_mstruct);
13417 					do_mathoperation = true;
13418 				} else if(str2 == "!=" || str == "=!" || str == "<>") {
13419 					CALCULATOR->calculateRPN(OPERATION_NOT_EQUALS, 0, evalops, parsed_mstruct);
13420 					do_mathoperation = true;
13421 				} else if(str2 == "<=" || str == "=<") {
13422 					CALCULATOR->calculateRPN(OPERATION_EQUALS_LESS, 0, evalops, parsed_mstruct);
13423 					do_mathoperation = true;
13424 				} else if(str2 == ">=" || str == "=>") {
13425 					CALCULATOR->calculateRPN(OPERATION_EQUALS_GREATER, 0, evalops, parsed_mstruct);
13426 					do_mathoperation = true;
13427 				} else if(str2 == "==") {
13428 					CALCULATOR->calculateRPN(OPERATION_EQUALS, 0, evalops, parsed_mstruct);
13429 					do_mathoperation = true;
13430 				} else if(str2 == "//") {
13431 					MathFunction *fdiv = CALCULATOR->getActiveFunction("div");
13432 					if(fdiv) {
13433 						CALCULATOR->calculateRPN(fdiv, 0, evalops, parsed_mstruct);
13434 						do_mathoperation = true;
13435 					}
13436 				}
13437 			} else if(str2.length() == 3) {
13438 				if(str2 == "⊻") {
13439 					CALCULATOR->calculateRPN(OPERATION_BITWISE_XOR, 0, evalops, parsed_mstruct);
13440 					do_mathoperation = true;
13441 				}
13442 			}
13443 			if(!do_mathoperation) {
13444 				bool had_nonnum = false, test_function = true;
13445 				int in_par = 0;
13446 				for(size_t i = 0; i < str2.length(); i++) {
13447 					if(is_in(NUMBERS, str2[i])) {
13448 						if(!had_nonnum || in_par) {
13449 							test_function = false;
13450 							break;
13451 						}
13452 					} else if(str2[i] == '(') {
13453 						if(in_par || !had_nonnum) {
13454 							test_function = false;
13455 							break;
13456 						}
13457 						in_par = i;
13458 					} else if(str2[i] == ')') {
13459 						if(i != str2.length() - 1) {
13460 							test_function = false;
13461 							break;
13462 						}
13463 					} else if(str2[i] == ' ') {
13464 						if(!in_par) {
13465 							test_function = false;
13466 							break;
13467 						}
13468 					} else if(is_in(NOT_IN_NAMES, str2[i])) {
13469 						test_function = false;
13470 						break;
13471 					} else {
13472 						if(in_par) {
13473 							test_function = false;
13474 							break;
13475 						}
13476 						had_nonnum = true;
13477 					}
13478 				}
13479 				f = NULL;
13480 				if(test_function) {
13481 					if(in_par) f = CALCULATOR->getActiveFunction(str2.substr(0, in_par));
13482 					else f = CALCULATOR->getActiveFunction(str2);
13483 				}
13484 				if(f && f->minargs() > 0) {
13485 					do_mathoperation = true;
13486 					CALCULATOR->calculateRPN(f, 0, evalops, parsed_mstruct);
13487 				} else {
13488 					CALCULATOR->RPNStackEnter(str2, 0, evalops, parsed_mstruct, parsed_tostruct);
13489 				}
13490 				if(do_mathoperation) gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_lastx")), TRUE);
13491 				else lastx = lastx_bak;
13492 			}
13493 		}
13494 	} else {
13495 		CALCULATOR->calculate(mstruct, CALCULATOR->unlocalizeExpression(execute_str.empty() ? str : execute_str, evalops.parse_options), 0, evalops, parsed_mstruct, parsed_tostruct);
13496 		result_autocalculated = false;
13497 	}
13498 
13499 	bool title_set = false, was_busy = false;
13500 
13501 	do_progress:
13502 	int i = 0;
13503 	while(CALCULATOR->busy() && i < 50) {
13504 		sleep_ms(10);
13505 		i++;
13506 	}
13507 	i = 0;
13508 
13509 	if(CALCULATOR->busy()) {
13510 		if(update_window_title(_("Calculating…"))) title_set = true;
13511 		if(stack_index == 0 && surface_result) {
13512 			cairo_surface_destroy(surface_result);
13513 			surface_result = NULL;
13514 			gtk_widget_queue_draw(resultview);
13515 		}
13516 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "menubar")), FALSE);
13517 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "buttons")), FALSE);
13518 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "convert")), FALSE);
13519 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "historyview")), FALSE);
13520 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "historyactions")), FALSE);
13521 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "rpntab")), FALSE);
13522 		update_expression_icons(stack_index == 0 ? (!minimal_mode ? RESULT_SPINNER : EXPRESSION_SPINNER) : EXPRESSION_STOP);
13523 		if(!minimal_mode) gtk_spinner_start(GTK_SPINNER(gtk_builder_get_object(main_builder, "resultspinner")));
13524 		else gtk_spinner_start(GTK_SPINNER(gtk_builder_get_object(main_builder, "expressionspinner")));
13525 		g_application_mark_busy(g_application_get_default());
13526 		was_busy = true;
13527 	}
13528 	while(CALCULATOR->busy()) {
13529 		while(gtk_events_pending()) gtk_main_iteration();
13530 		sleep_ms(100);
13531 	}
13532 	if(!do_mathoperation && !str_conv.empty() && parsed_tostruct->containsType(STRUCT_UNIT, true) && !mstruct->containsType(STRUCT_UNIT) && !parsed_mstruct->containsType(STRUCT_UNIT, false, true, true) && !CALCULATOR->hasToExpression(str_conv, false, evalops)) {
13533 		MathStructure to_struct(*parsed_tostruct);
13534 		to_struct.unformat();
13535 		to_struct = CALCULATOR->convertToOptimalUnit(to_struct, evalops, true);
13536 		fix_to_struct_gtk(to_struct);
13537 		if(!to_struct.isZero()) {
13538 			mstruct->multiply(to_struct);
13539 			PrintOptions po = printops;
13540 			po.negative_exponents = false;
13541 			to_struct.format(po);
13542 			if(to_struct.isMultiplication() && to_struct.size() >= 2) {
13543 				if(to_struct[0].isOne()) to_struct.delChild(1, true);
13544 				else if(to_struct[1].isOne()) to_struct.delChild(2, true);
13545 			}
13546 			parsed_mstruct->multiply(to_struct);
13547 			CALCULATOR->calculate(mstruct, 0, evalops, CALCULATOR->unlocalizeExpression(str_conv, evalops.parse_options));
13548 			str_conv = "";
13549 			goto do_progress;
13550 		}
13551 	}
13552 
13553 	if(was_busy) {
13554 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "menubar")), TRUE);
13555 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "buttons")), TRUE);
13556 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "convert")), TRUE);
13557 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "historyview")), TRUE);
13558 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "historyactions")), TRUE);
13559 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "rpntab")), TRUE);
13560 		if(title_set) update_window_title();
13561 		if(!minimal_mode) gtk_spinner_stop(GTK_SPINNER(gtk_builder_get_object(main_builder, "resultspinner")));
13562 		else gtk_spinner_stop(GTK_SPINNER(gtk_builder_get_object(main_builder, "expressionspinner")));
13563 		g_application_unmark_busy(g_application_get_default());
13564 	}
13565 
13566 	b_busy = false;
13567 	b_busy_expression = false;
13568 
13569 	if(rpn_mode && stack_index == 0) {
13570 		mstruct->unref();
13571 		mstruct = CALCULATOR->getRPNRegister(1);
13572 		if(!mstruct) mstruct = new MathStructure();
13573 		else mstruct->ref();
13574 	}
13575 
13576 	if(do_stack && stack_index > 0) {
13577 	} else if(rpn_mode && do_mathoperation) {
13578 		result_text = _("RPN Operation");
13579 	} else {
13580 		result_text = str;
13581 	}
13582 	printops.allow_factorization = (evalops.structuring == STRUCTURING_FACTORIZE);
13583 	if(rpn_mode && stack_index == 0) {
13584 		clear_expression_text();
13585 		while(CALCULATOR->RPNStackSize() < stack_size) {
13586 			RPNRegisterRemoved(1);
13587 			stack_size--;
13588 		}
13589 		if(CALCULATOR->RPNStackSize() > stack_size) {
13590 			RPNRegisterAdded("");
13591 		}
13592 	}
13593 
13594 	if(rpn_mode && do_mathoperation && parsed_tostruct && !parsed_tostruct->isUndefined() && parsed_tostruct->isSymbolic()) {
13595 		mstruct->set(CALCULATOR->convert(*mstruct, parsed_tostruct->symbol(), evalops));
13596 	}
13597 
13598 	// Always perform conversion to optimal (SI) unit when the expression is a number multiplied by a unit and input equals output
13599 	if(!rpn_mode && (!parsed_tostruct || parsed_tostruct->isUndefined()) && execute_str.empty() && !had_to_expression && (evalops.approximation == APPROXIMATION_EXACT || evalops.auto_post_conversion == POST_CONVERSION_OPTIMAL || evalops.auto_post_conversion == POST_CONVERSION_NONE) && parsed_mstruct && mstruct && ((parsed_mstruct->isMultiplication() && parsed_mstruct->size() == 2 && (*parsed_mstruct)[0].isNumber() && (*parsed_mstruct)[1].isUnit_exp() && parsed_mstruct->equals(*mstruct)) || (parsed_mstruct->isNegate() && (*parsed_mstruct)[0].isMultiplication() && (*parsed_mstruct)[0].size() == 2 && (*parsed_mstruct)[0][0].isNumber() && (*parsed_mstruct)[0][1].isUnit_exp() && mstruct->isMultiplication() && mstruct->size() == 2 && (*mstruct)[1] == (*parsed_mstruct)[0][1] && (*mstruct)[0].isNumber() && (*parsed_mstruct)[0][0].number() == -(*mstruct)[0].number()) || (parsed_mstruct->isUnit_exp() && parsed_mstruct->equals(*mstruct)))) {
13600 		Unit *u = NULL;
13601 		MathStructure *munit = NULL;
13602 		if(mstruct->isMultiplication()) munit = &(*mstruct)[1];
13603 		else munit = mstruct;
13604 		if(munit->isUnit()) u = munit->unit();
13605 		else u = (*munit)[0].unit();
13606 		if(u && u->isCurrency()) {
13607 			if(evalops.local_currency_conversion && CALCULATOR->getLocalCurrency() && u != CALCULATOR->getLocalCurrency()) {
13608 				ApproximationMode abak = evalops.approximation;
13609 				if(evalops.approximation == APPROXIMATION_EXACT) evalops.approximation = APPROXIMATION_TRY_EXACT;
13610 				mstruct->set(CALCULATOR->convertToOptimalUnit(*mstruct, evalops, true));
13611 				evalops.approximation = abak;
13612 			}
13613 		} else if(u && u->subtype() != SUBTYPE_BASE_UNIT && !u->isSIUnit()) {
13614 			MathStructure mbak(*mstruct);
13615 			if(evalops.auto_post_conversion == POST_CONVERSION_OPTIMAL || evalops.auto_post_conversion == POST_CONVERSION_NONE) {
13616 				if(munit->isUnit() && u->referenceName() == "oF") {
13617 					u = CALCULATOR->getActiveUnit("oC");
13618 					if(u) mstruct->set(CALCULATOR->convert(*mstruct, u, evalops, true, false));
13619 				} else {
13620 					mstruct->set(CALCULATOR->convertToOptimalUnit(*mstruct, evalops, true));
13621 				}
13622 			}
13623 			if(evalops.approximation == APPROXIMATION_EXACT && ((evalops.auto_post_conversion != POST_CONVERSION_OPTIMAL && evalops.auto_post_conversion != POST_CONVERSION_NONE) || mstruct->equals(mbak))) {
13624 				evalops.approximation = APPROXIMATION_TRY_EXACT;
13625 				if(evalops.auto_post_conversion == POST_CONVERSION_BASE) mstruct->set(CALCULATOR->convertToBaseUnits(*mstruct, evalops));
13626 				else mstruct->set(CALCULATOR->convertToOptimalUnit(*mstruct, evalops, true));
13627 				evalops.approximation = APPROXIMATION_EXACT;
13628 			}
13629 		}
13630 	}
13631 
13632 	if(!do_mathoperation && ((test_ask_tc(*parsed_mstruct) && ask_tc()) || (check_exrates && check_exchange_rates(NULL, stack_index == 0 && !do_bases && !do_calendars && !do_pfe && !do_factors && !do_expand)))) {
13633 		execute_expression(force, do_mathoperation, op, f, rpn_mode, stack_index, saved_execute_str, str, false);
13634 		evalops.complex_number_form = cnf_bak;
13635 		evalops.auto_post_conversion = save_auto_post_conversion;
13636 		evalops.parse_options.units_enabled = b_units_saved;
13637 		evalops.mixed_units_conversion = save_mixed_units_conversion;
13638 		printops.custom_time_zone = 0;
13639 		printops.time_zone = TIME_ZONE_LOCAL;
13640 		return;
13641 	}
13642 
13643 	//update "ans" variables
13644 	if(stack_index == 0) {
13645 		MathStructure m4(vans[3]->get());
13646 		m4.replace(vans[4], vans[4]->get());
13647 		vans[4]->set(m4);
13648 		MathStructure m3(vans[2]->get());
13649 		m3.replace(vans[3], vans[4]);
13650 		vans[3]->set(m3);
13651 		MathStructure m2(vans[1]->get());
13652 		m2.replace(vans[2], vans[3]);
13653 		vans[2]->set(m2);
13654 		MathStructure m1(vans[0]->get());
13655 		m1.replace(vans[1], vans[2]);
13656 		vans[1]->set(m1);
13657 		mstruct->replace(vans[0], vans[1]);
13658 		vans[0]->set(*mstruct);
13659 	}
13660 
13661 	if(do_factors || do_pfe || do_expand) {
13662 		if(do_stack && stack_index != 0) {
13663 			MathStructure *save_mstruct = mstruct;
13664 			mstruct = CALCULATOR->getRPNRegister(stack_index + 1);
13665 			executeCommand(do_pfe ? COMMAND_EXPAND_PARTIAL_FRACTIONS : (do_expand ? COMMAND_EXPAND : COMMAND_FACTORIZE), false);
13666 			mstruct = save_mstruct;
13667 		} else {
13668 			executeCommand(do_pfe ? COMMAND_EXPAND_PARTIAL_FRACTIONS  : (do_expand ? COMMAND_EXPAND : COMMAND_FACTORIZE), false);
13669 		}
13670 	}
13671 
13672 	if(!do_stack) previous_expression = execute_str.empty() ? str : execute_str;
13673 	setResult(NULL, true, stack_index == 0, true, "", stack_index);
13674 
13675 	if(do_bases) convert_number_bases(execute_str.c_str());
13676 	if(do_calendars) on_popup_menu_item_calendarconversion_activate(NULL, NULL);
13677 
13678 	evalops.complex_number_form = cnf_bak;
13679 	evalops.auto_post_conversion = save_auto_post_conversion;
13680 	evalops.parse_options.units_enabled = b_units_saved;
13681 	evalops.mixed_units_conversion = save_mixed_units_conversion;
13682 	printops.custom_time_zone = 0;
13683 	printops.time_zone = TIME_ZONE_LOCAL;
13684 
13685 	if(stack_index == 0) {
13686 		if(!block_conversion_category_switch) {
13687 			Unit *u = CALCULATOR->findMatchingUnit(*mstruct);
13688 			if(u && !u->category().empty()) {
13689 				string s_cat = u->category();
13690 				if(s_cat.empty()) s_cat = _("Uncategorized");
13691 				if(s_cat != selected_unit_category) {
13692 					GtkTreeIter iter = convert_category_map[s_cat];
13693 					GtkTreePath *path = gtk_tree_model_get_path(gtk_tree_view_get_model(GTK_TREE_VIEW(tUnitSelectorCategories)), &iter);
13694 					gtk_tree_view_expand_to_path(GTK_TREE_VIEW(tUnitSelectorCategories), path);
13695 					gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(tUnitSelectorCategories), path, NULL, TRUE, 0.5, 0);
13696 					gtk_tree_path_free(path);
13697 					gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitSelectorCategories)), &iter);
13698 				}
13699 			}
13700 			if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "convert_button_continuous_conversion")))) {
13701 				gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitSelector)));
13702 			}
13703 		}
13704 		gtk_widget_grab_focus(expressiontext);
13705 		GtkTextIter istart, iend;
13706 		gtk_text_buffer_get_start_iter(expressionbuffer, &istart);
13707 		gtk_text_buffer_get_end_iter(expressionbuffer, &iend);
13708 		gtk_text_buffer_select_range(expressionbuffer, &istart, &iend);
13709 		gtk_text_buffer_remove_tag(expressionbuffer, expression_par_tag, &istart, &iend);
13710 		cursor_has_moved = false;
13711 	}
13712 	do_timeout = true;
13713 
13714 }
13715 
execute_from_file(string command_file)13716 void execute_from_file(string command_file) {
13717 	FILE *cfile = fopen(command_file.c_str(), "r");
13718 	if(!cfile) {
13719 		printf(_("Failed to open %s.\n%s"), command_file.c_str(), "");
13720 		return;
13721 	}
13722 	char buffer[10000];
13723 	string str, scom;
13724 	size_t ispace;
13725 	bool rpn_save = rpn_mode;
13726 	bool autocalc_save = auto_calculate;
13727 	auto_calculate = false;
13728 	rpn_mode = false;
13729 	previous_expression = "";
13730 	if(!block_add_to_undo && !expression_is_empty()) add_expression_to_undo();
13731 	gtk_widget_hide(resultview);
13732 	block_add_to_undo++;
13733 	block_expression_history++;
13734 	block_completion();
13735 	while(fgets(buffer, 10000, cfile)) {
13736 		str = buffer;
13737 		remove_blank_ends(str);
13738 		ispace = str.find_first_of(SPACES);
13739 		if(ispace == string::npos) scom = "";
13740 		else scom = str.substr(0, ispace);
13741 		if(equalsIgnoreCase(str, "exrates") || equalsIgnoreCase(str, "stack") || equalsIgnoreCase(str, "swap") || equalsIgnoreCase(str, "rotate") || equalsIgnoreCase(str, "copy") || equalsIgnoreCase(str, "clear stack") || equalsIgnoreCase(str, "exact") || equalsIgnoreCase(str, "approximate") || equalsIgnoreCase(str, "approx") || equalsIgnoreCase(str, "factor") || equalsIgnoreCase(str, "partial fraction") || equalsIgnoreCase(str, "simplify") || equalsIgnoreCase(str, "expand") || equalsIgnoreCase(str, "mode") || equalsIgnoreCase(str, "help") || equalsIgnoreCase(str, "?") || equalsIgnoreCase(str, "list") || equalsIgnoreCase(str, "exit") || equalsIgnoreCase(str, "quit") || equalsIgnoreCase(scom, "variable") || equalsIgnoreCase(scom, "function") || equalsIgnoreCase(scom, "set") || equalsIgnoreCase(scom, "save") || equalsIgnoreCase(scom, "store") || equalsIgnoreCase(scom, "swap") || equalsIgnoreCase(scom, "delete") || equalsIgnoreCase(scom, "assume") || equalsIgnoreCase(scom, "base") || equalsIgnoreCase(scom, "rpn") || equalsIgnoreCase(scom, "move") || equalsIgnoreCase(scom, "rotate") || equalsIgnoreCase(scom, "copy") || equalsIgnoreCase(scom, "pop") || equalsIgnoreCase(scom, "convert") || (equalsIgnoreCase(scom, "to") && scom != "to") || equalsIgnoreCase(scom, "list") || equalsIgnoreCase(scom, "find") || equalsIgnoreCase(scom, "info") || equalsIgnoreCase(scom, "help")) str.insert(0, 1, '/');
13742 		if(!str.empty()) execute_expression(true, false, OPERATION_ADD, NULL, false, 0, "", str.c_str(), false);
13743 	}
13744 	clear_expression_text();
13745 	clearresult();
13746 	gtk_widget_show(resultview);
13747 	expression_has_changed = true;
13748 	if(displayed_mstruct) {
13749 		displayed_mstruct->unref();
13750 		displayed_mstruct = NULL;
13751 	}
13752 	if(parsed_mstruct) parsed_mstruct->clear();
13753 	if(parsed_tostruct) parsed_tostruct->setUndefined();
13754 	if(matrix_mstruct) matrix_mstruct->clear();
13755 	unblock_completion();
13756 	block_add_to_undo--;
13757 	block_expression_history--;
13758 	rpn_mode = rpn_save;
13759 	auto_calculate = autocalc_save;
13760 	previous_expression = "";
13761 	if(mstruct) {
13762 		if(rpn_mode) {
13763 			mstruct->unref();
13764 			mstruct = CALCULATOR->getRPNRegister(1);
13765 			if(!mstruct) mstruct = new MathStructure();
13766 			else mstruct->ref();
13767 		} else {
13768 			mstruct->clear();
13769 		}
13770 	}
13771 	fclose(cfile);
13772 }
13773 
set_rpn_mode(bool b)13774 void set_rpn_mode(bool b) {
13775 	if(b == rpn_mode) return;
13776 	rpn_mode = b;
13777 	update_expression_icons();
13778 	if(rpn_mode) {
13779 		gtk_label_set_angle(GTK_LABEL(gtk_builder_get_object(main_builder, "label_equals")), 90.0);
13780 		// RPN Enter (calculate and add to stack)
13781 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_equals")), _("ENTER"));
13782 		gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_equals")), _("Calculate expression and add to stack"));
13783 		gtk_widget_show(expander_stack);
13784 		show_history = gtk_expander_get_expanded(GTK_EXPANDER(expander_history));
13785 		show_keypad = !persistent_keypad && gtk_expander_get_expanded(GTK_EXPANDER(expander_keypad));
13786 		show_convert = gtk_expander_get_expanded(GTK_EXPANDER(expander_convert));
13787 		if(show_stack) {
13788 			gtk_expander_set_expanded(GTK_EXPANDER(expander_stack), TRUE);
13789 		}
13790 		expression_has_changed = true;
13791 		expression_has_changed2 = true;
13792 		expression_history_index = -1;
13793 		clearresult();
13794 		if(auto_calculate) {
13795 			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);
13796 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_autocalc")), FALSE);
13797 			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);
13798 		}
13799 		if(chain_mode) {
13800 			g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_chain_mode"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_chain_mode_activate, NULL);
13801 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_chain_mode")), FALSE);
13802 			g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_chain_mode"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_chain_mode_activate, NULL);
13803 		}
13804 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "menu_item_autocalc")), FALSE);
13805 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "menu_item_chain_mode")), FALSE);
13806 	} else {
13807 		gtk_label_set_angle(GTK_LABEL(gtk_builder_get_object(main_builder, "label_equals")), 0.0);
13808 		gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "label_equals")), "<big>=</big>");
13809 		gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_equals")), _("Calculate expression"));
13810 		gtk_widget_hide(expander_stack);
13811 		show_stack = gtk_expander_get_expanded(GTK_EXPANDER(expander_stack));
13812 		if(show_stack) {
13813 			if(show_history) gtk_expander_set_expanded(GTK_EXPANDER(expander_history), TRUE);
13814 			else if(show_keypad && !persistent_keypad) gtk_expander_set_expanded(GTK_EXPANDER(expander_keypad), TRUE);
13815 			else if(show_convert) gtk_expander_set_expanded(GTK_EXPANDER(expander_convert), TRUE);
13816 			else gtk_expander_set_expanded(GTK_EXPANDER(expander_stack), FALSE);
13817 		}
13818 		CALCULATOR->clearRPNStack();
13819 		g_signal_handlers_block_matched((gpointer) stackstore, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_stackstore_row_deleted, NULL);
13820 		gtk_list_store_clear(stackstore);
13821 		g_signal_handlers_unblock_matched((gpointer) stackstore, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_stackstore_row_deleted, NULL);
13822 		clearresult();
13823 		if(auto_calculate) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_autocalc")), TRUE);
13824 		if(chain_mode) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_chain_mode")), TRUE);
13825 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "menu_item_autocalc")), TRUE);
13826 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "menu_item_chain_mode")), TRUE);
13827 	}
13828 }
13829 
updateRPNIndexes()13830 void updateRPNIndexes() {
13831 	GtkTreeIter iter;
13832 	if(!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(stackstore), &iter)) return;
13833 	for(int i = 1; ; i++) {
13834 		gtk_list_store_set(stackstore, &iter, 0, i2s(i).c_str(), -1);
13835 		if(!gtk_tree_model_iter_next(GTK_TREE_MODEL(stackstore), &iter)) break;
13836 	}
13837 }
13838 
calculateRPN(int op)13839 void calculateRPN(int op) {
13840 	if(expression_has_changed) {
13841 		if(get_expression_text().find_first_not_of(SPACES) != string::npos) {
13842 			execute_expression(true);
13843 		}
13844 	}
13845 	execute_expression(true, true, (MathOperation) op, NULL);
13846 }
calculateRPN(MathFunction * f)13847 void calculateRPN(MathFunction *f) {
13848 	if(expression_has_changed) {
13849 		if(get_expression_text().find_first_not_of(SPACES) != string::npos) {
13850 			execute_expression(true);
13851 		}
13852 	}
13853 	execute_expression(true, true, OPERATION_ADD, f);
13854 }
RPNRegisterAdded(string text,gint index)13855 void RPNRegisterAdded(string text, gint index) {
13856 	GtkTreeIter iter;
13857 	g_signal_handlers_block_matched((gpointer) stackstore, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_stackstore_row_inserted, NULL);
13858 	gtk_list_store_insert(stackstore, &iter, index);
13859 	g_signal_handlers_unblock_matched((gpointer) stackstore, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_stackstore_row_inserted, NULL);
13860 	gtk_list_store_set(stackstore, &iter, 0, i2s(index + 1).c_str(), 1, text.c_str(), -1);
13861 	updateRPNIndexes();
13862 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_clearstack")), TRUE);
13863 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_copyregister")), TRUE);
13864 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_deleteregister")), TRUE);
13865 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_sqrt")), TRUE);
13866 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_reciprocal")), TRUE);
13867 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_negate")), TRUE);
13868 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_add")), TRUE);
13869 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_sub")), TRUE);
13870 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_times")), TRUE);
13871 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_divide")), TRUE);
13872 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_xy")), TRUE);
13873 	if(CALCULATOR->RPNStackSize() >= 2) {
13874 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_registerdown")), TRUE);
13875 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_registerup")), TRUE);
13876 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_registerswap")), TRUE);
13877 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_sum")), TRUE);
13878 	}
13879 	on_stackview_selection_changed(gtk_tree_view_get_selection(GTK_TREE_VIEW(stackview)), NULL);
13880 }
RPNRegisterRemoved(gint index)13881 void RPNRegisterRemoved(gint index) {
13882 	GtkTreeIter iter;
13883 	gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(stackstore), &iter, NULL, index);
13884 	g_signal_handlers_block_matched((gpointer) stackstore, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_stackstore_row_deleted, NULL);
13885 	gtk_list_store_remove(stackstore, &iter);
13886 	g_signal_handlers_unblock_matched((gpointer) stackstore, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_stackstore_row_deleted, NULL);
13887 	updateRPNIndexes();
13888 	if(CALCULATOR->RPNStackSize() == 0) {
13889 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_clearstack")), FALSE);
13890 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_copyregister")), FALSE);
13891 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_deleteregister")), FALSE);
13892 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_sqrt")), FALSE);
13893 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_reciprocal")), FALSE);
13894 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_negate")), FALSE);
13895 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_add")), FALSE);
13896 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_sub")), FALSE);
13897 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_times")), FALSE);
13898 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_divide")), FALSE);
13899 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_xy")), FALSE);
13900 	}
13901 	if(CALCULATOR->RPNStackSize() < 2) {
13902 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_registerdown")), FALSE);
13903 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_registerup")), FALSE);
13904 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_registerswap")), FALSE);
13905 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_sum")), FALSE);
13906 	}
13907 	on_stackview_selection_changed(gtk_tree_view_get_selection(GTK_TREE_VIEW(stackview)), NULL);
13908 }
RPNRegisterChanged(string text,gint index)13909 void RPNRegisterChanged(string text, gint index) {
13910 	GtkTreeIter iter;
13911 	gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(stackstore), &iter, NULL, index);
13912 	gtk_list_store_set(stackstore, &iter, 1, text.c_str(), -1);
13913 }
13914 
13915 /*
13916 	general function used to insert text in expression entry
13917 */
insert_text(const gchar * name)13918 void insert_text(const gchar *name) {
13919 	if(b_busy) return;
13920 	block_completion();
13921 	overwrite_expression_selection(name);
13922 	if(!gtk_widget_is_focus(expressiontext)) {
13923 		gtk_widget_grab_focus(expressiontext);
13924 	}
13925 	unblock_completion();
13926 }
13927 
recreate_recent_functions()13928 void recreate_recent_functions() {
13929 	GtkWidget *item, *sub;
13930 	sub = f_menu;
13931 	recent_function_items.clear();
13932 	bool b = false;
13933 	for(size_t i = 0; i < recent_functions.size(); i++) {
13934 		if(!CALCULATOR->stillHasFunction(recent_functions[i])) {
13935 			recent_functions.erase(recent_functions.begin() + i);
13936 			i--;
13937 		} else {
13938 			if(!b) {
13939 				MENU_SEPARATOR_PREPEND
13940 				b = true;
13941 			}
13942 			item = gtk_menu_item_new_with_label(recent_functions[i]->title(true).c_str());
13943 			recent_function_items.push_back(item);
13944 			gtk_widget_show(item);
13945 			gtk_menu_shell_prepend(GTK_MENU_SHELL(sub), item);
13946 			g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(insert_function), (gpointer) recent_functions[i]);
13947 		}
13948 	}
13949 	update_mb_fx_menu();
13950 }
recreate_recent_variables()13951 void recreate_recent_variables() {
13952 	GtkWidget *item, *sub;
13953 	sub = v_menu;
13954 	recent_variable_items.clear();
13955 	bool b = false;
13956 	for(size_t i = 0; i < recent_variables.size(); i++) {
13957 		if(!CALCULATOR->stillHasVariable(recent_variables[i])) {
13958 			recent_variables.erase(recent_variables.begin() + i);
13959 			i--;
13960 		} else {
13961 			if(!b) {
13962 				MENU_SEPARATOR_PREPEND
13963 				b = true;
13964 			}
13965 			item = gtk_menu_item_new_with_label(recent_variables[i]->title(true).c_str());
13966 			recent_variable_items.push_back(item);
13967 			gtk_widget_show(item);
13968 			gtk_menu_shell_prepend(GTK_MENU_SHELL(sub), item);
13969 			g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(insert_variable), (gpointer) recent_variables[i]);
13970 		}
13971 	}
13972 	update_mb_pi_menu();
13973 }
recreate_recent_units()13974 void recreate_recent_units() {
13975 	GtkWidget *item, *sub;
13976 	sub = u_menu;
13977 	recent_unit_items.clear();
13978 	bool b = false;
13979 	for(size_t i = 0; i < recent_units.size(); i++) {
13980 		if(!CALCULATOR->stillHasUnit(recent_units[i])) {
13981 			recent_units.erase(recent_units.begin() + i);
13982 			i--;
13983 		} else {
13984 			if(!b) {
13985 				MENU_SEPARATOR_PREPEND
13986 				b = true;
13987 			}
13988 			item = gtk_menu_item_new_with_label(recent_units[i]->title(true).c_str());
13989 			recent_unit_items.push_back(item);
13990 			gtk_widget_show(item);
13991 			gtk_menu_shell_prepend(GTK_MENU_SHELL(sub), item);
13992 			g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(insert_unit), (gpointer) recent_units[i]);
13993 		}
13994 	}
13995 	update_mb_units_menu();
13996 }
13997 
function_inserted(MathFunction * object)13998 void function_inserted(MathFunction *object) {
13999 	if(!object) {
14000 		return;
14001 	}
14002 	GtkWidget *item, *sub;
14003 	sub = f_menu;
14004 	if(recent_function_items.size() <= 0) {
14005 		MENU_SEPARATOR_PREPEND
14006 	}
14007 	for(size_t i = 0; i < recent_functions.size(); i++) {
14008 		if(recent_functions[i] == object) {
14009 			recent_functions.erase(recent_functions.begin() + i);
14010 			gtk_widget_destroy(recent_function_items[i]);
14011 			recent_function_items.erase(recent_function_items.begin() + i);
14012 			break;
14013 		}
14014 	}
14015 	if(recent_function_items.size() >= 5) {
14016 		recent_functions.erase(recent_functions.begin());
14017 		gtk_widget_destroy(recent_function_items[0]);
14018 		recent_function_items.erase(recent_function_items.begin());
14019 	}
14020 	item = gtk_menu_item_new_with_label(object->title(true).c_str());
14021 	recent_function_items.push_back(item);
14022 	recent_functions.push_back(object);
14023 	gtk_widget_show(item);
14024 	gtk_menu_shell_prepend(GTK_MENU_SHELL(sub), item);
14025 	g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(insert_function), (gpointer) object);
14026 	update_mb_fx_menu();
14027 }
variable_inserted(Variable * object)14028 void variable_inserted(Variable *object) {
14029 	if(!object || object == CALCULATOR->v_x || object == CALCULATOR->v_y || object == CALCULATOR->v_z) {
14030 		return;
14031 	}
14032 	GtkWidget *item, *sub;
14033 	sub = v_menu;
14034 	if(recent_variable_items.size() <= 0) {
14035 		MENU_SEPARATOR_PREPEND
14036 	}
14037 	for(size_t i = 0; i < recent_variables.size(); i++) {
14038 		if(recent_variables[i] == object) {
14039 			recent_variables.erase(recent_variables.begin() + i);
14040 			gtk_widget_destroy(recent_variable_items[i]);
14041 			recent_variable_items.erase(recent_variable_items.begin() + i);
14042 			break;
14043 		}
14044 	}
14045 	if(recent_variable_items.size() >= 5) {
14046 		recent_variables.erase(recent_variables.begin());
14047 		gtk_widget_destroy(recent_variable_items[0]);
14048 		recent_variable_items.erase(recent_variable_items.begin());
14049 	}
14050 	item = gtk_menu_item_new_with_label(object->title(true).c_str());
14051 	recent_variable_items.push_back(item);
14052 	recent_variables.push_back(object);
14053 	gtk_widget_show(item);
14054 	gtk_menu_shell_prepend(GTK_MENU_SHELL(sub), item);
14055 	g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(insert_variable), (gpointer) object);
14056 	update_mb_pi_menu();
14057 }
unit_inserted(Unit * object)14058 void unit_inserted(Unit *object) {
14059 	if(!object) {
14060 		return;
14061 	}
14062 	GtkWidget *item, *sub;
14063 	sub = u_menu;
14064 	if(recent_unit_items.size() <= 0) {
14065 		MENU_SEPARATOR_PREPEND
14066 	}
14067 	for(size_t i = 0; i < recent_units.size(); i++) {
14068 		if(recent_units[i] == object) {
14069 			recent_units.erase(recent_units.begin() + i);
14070 			gtk_widget_destroy(recent_unit_items[i]);
14071 			recent_unit_items.erase(recent_unit_items.begin() + i);
14072 			break;
14073 		}
14074 	}
14075 	if(recent_unit_items.size() >= 5) {
14076 		recent_units.erase(recent_units.begin());
14077 		gtk_widget_destroy(recent_unit_items[0]);
14078 		recent_unit_items.erase(recent_unit_items.begin());
14079 	}
14080 	item = gtk_menu_item_new_with_label(object->title(true).c_str());
14081 	recent_unit_items.push_back(item);
14082 	recent_units.push_back(object);
14083 	gtk_widget_show(item);
14084 	gtk_menu_shell_prepend(GTK_MENU_SHELL(sub), item);
14085 	g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(insert_unit), (gpointer) object);
14086 	update_mb_units_menu();
14087 }
14088 
apply_function(MathFunction * f,GtkWidget * =NULL)14089 void apply_function(MathFunction *f, GtkWidget* = NULL) {
14090 	if(b_busy) return;
14091 	if(rpn_mode) {
14092 		calculateRPN(f);
14093 		return;
14094 	}
14095 	string str = f->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressionbuffer).name;
14096 	if(f->args() == 0) {
14097 		str += "()";
14098 	} else {
14099 		str += "(";
14100 		str += get_expression_text();
14101 		str += ")";
14102 	}
14103 	block_add_to_undo++;
14104 	gtk_text_buffer_set_text(expressionbuffer, "", -1);
14105 	block_add_to_undo--;
14106 	insert_text(str.c_str());
14107 	execute_expression();
14108 	function_inserted(f);
14109 }
14110 
on_function_int_input(GtkSpinButton * entry,gpointer new_value,gpointer)14111 gint on_function_int_input(GtkSpinButton *entry, gpointer new_value, gpointer) {
14112 	string str = gtk_entry_get_text(GTK_ENTRY(entry));
14113 	remove_blank_ends(str);
14114 	if(str.find_first_not_of(NUMBERS) != string::npos) {
14115 		MathStructure value;
14116 		CALCULATOR->beginTemporaryStopMessages();
14117 		CALCULATOR->calculate(&value, CALCULATOR->unlocalizeExpression(str, evalops.parse_options), 200, evalops);
14118 		CALCULATOR->endTemporaryStopMessages();
14119 		if(!value.isNumber()) return GTK_INPUT_ERROR;
14120 		bool overflow = false;
14121 		*((gdouble*) new_value) = value.number().intValue(&overflow);
14122 		if(overflow) return GTK_INPUT_ERROR;
14123 		return TRUE;
14124 	}
14125 	return FALSE;
14126 }
14127 
14128 struct FunctionDialog {
14129 	GtkWidget *dialog;
14130 	GtkWidget *b_cancel, *b_exec, *b_insert, *b_keepopen, *w_result;
14131 	vector<GtkWidget*> label;
14132 	vector<GtkWidget*> entry;
14133 	vector<GtkWidget*> type_label;
14134 	vector<GtkWidget*> boolean_buttons;
14135 	vector<int> boolean_index;
14136 	GtkListStore *properties_store;
14137 	bool add_to_menu, keep_open, rpn;
14138 	int args;
14139 };
14140 
14141 unordered_map<MathFunction*, FunctionDialog*> function_dialogs;
14142 
insert_function_do(MathFunction * f,FunctionDialog * fd)14143 void insert_function_do(MathFunction *f, FunctionDialog *fd) {
14144 	string str = f->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext).name + "(", str2;
14145 
14146 	int argcount = fd->args;
14147 	if(f->maxargs() > 0 && f->minargs() < f->maxargs() && argcount > f->minargs()) {
14148 		while(true) {
14149 			ParseOptions pa = evalops.parse_options; pa.base = 10;
14150 			string defstr = CALCULATOR->localizeExpression(f->getDefaultValue(argcount), pa);
14151 			remove_blank_ends(defstr);
14152 			if(f->getArgumentDefinition(argcount) && f->getArgumentDefinition(argcount)->type() == ARGUMENT_TYPE_BOOLEAN) {
14153 				if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(fd->boolean_buttons[fd->boolean_index[argcount - 1]]))) {
14154 					str2 = "1";
14155 				} else {
14156 					str2 = "0";
14157 				}
14158 			} else if(evalops.parse_options.base != BASE_DECIMAL && f->getArgumentDefinition(argcount) && f->getArgumentDefinition(argcount)->type() == ARGUMENT_TYPE_INTEGER) {
14159 				Number nr(gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(fd->entry[argcount - 1])), 1);
14160 				str2 = print_with_evalops(nr);
14161 			} else if(fd->properties_store && f->getArgumentDefinition(argcount) && f->getArgumentDefinition(argcount)->type() == ARGUMENT_TYPE_DATA_PROPERTY) {
14162 				GtkTreeIter iter;
14163 				DataProperty *dp = NULL;
14164 				if(gtk_combo_box_get_active_iter(GTK_COMBO_BOX(fd->entry[argcount - 1]), &iter)) {
14165 					gtk_tree_model_get(GTK_TREE_MODEL(fd->properties_store), &iter, 1, &dp, -1);
14166 				}
14167 				if(dp) {
14168 					str2 = dp->getName();
14169 				} else {
14170 					str2 = "info";
14171 				}
14172 			} else {
14173 				str2 = gtk_entry_get_text(GTK_ENTRY(fd->entry[argcount - 1]));
14174 				remove_blank_ends(str2);
14175 			}
14176 			if(!str2.empty() && f->getArgumentDefinition(argcount) && (f->getArgumentDefinition(argcount)->suggestsQuotes() || (f->getArgumentDefinition(argcount)->type() == ARGUMENT_TYPE_TEXT && str2.find(CALCULATOR->getComma()) == string::npos))) {
14177 				if(str2.length() < 1 || (str2[0] != '\"' && str[0] != '\'')) {
14178 					str2.insert(0, "\"");
14179 					str2 += "\"";
14180 				}
14181 			}
14182 			if(str2.empty() || str2 == defstr) argcount--;
14183 			else break;
14184 			if(argcount == 0 || argcount == f->minargs()) break;
14185 		}
14186 	}
14187 
14188 	int i_vector = f->maxargs() > 0 ? f->maxargs() : argcount;
14189 	for(int i = 0; i < argcount; i++) {
14190 		if(f->getArgumentDefinition(i + 1) && f->getArgumentDefinition(i + 1)->type() == ARGUMENT_TYPE_BOOLEAN) {
14191 			if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(fd->boolean_buttons[fd->boolean_index[i]]))) {
14192 				str2 = "1";
14193 			} else {
14194 				str2 = "0";
14195 			}
14196 		} else if((i != (f->maxargs() > 0 ? f->maxargs() : argcount) - 1 || i_vector == i - 1) && f->getArgumentDefinition(i + 1) && f->getArgumentDefinition(i + 1)->type() == ARGUMENT_TYPE_VECTOR) {
14197 			i_vector = i;
14198 			str2 = gtk_entry_get_text(GTK_ENTRY(fd->entry[i]));
14199 			remove_blank_ends(str2);
14200 			if(str2.find_first_of(PARENTHESISS VECTOR_WRAPS) == string::npos && str2.find_first_of(CALCULATOR->getComma() == COMMA ? COMMAS : CALCULATOR->getComma()) != string::npos) {
14201 				str2.insert(0, 1, '[');
14202 				str2 += ']';
14203 			}
14204 		} else if(evalops.parse_options.base != BASE_DECIMAL && f->getArgumentDefinition(i + 1) && f->getArgumentDefinition(i + 1)->type() == ARGUMENT_TYPE_INTEGER) {
14205 			Number nr(gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(fd->entry[i])), 1);
14206 			str2 = print_with_evalops(nr);
14207 		} else if(fd->properties_store && f->getArgumentDefinition(i + 1) && f->getArgumentDefinition(i + 1)->type() == ARGUMENT_TYPE_DATA_PROPERTY) {
14208 			GtkTreeIter iter;
14209 			DataProperty *dp = NULL;
14210 			if(gtk_combo_box_get_active_iter(GTK_COMBO_BOX(fd->entry[i]), &iter)) {
14211 				gtk_tree_model_get(GTK_TREE_MODEL(fd->properties_store), &iter, 1, &dp, -1);
14212 			}
14213 			if(dp) {
14214 				str2 = dp->getName();
14215 			} else {
14216 				str2 = "info";
14217 			}
14218 		} else {
14219 			str2 = gtk_entry_get_text(GTK_ENTRY(fd->entry[i]));
14220 			remove_blank_ends(str2);
14221 		}
14222 		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))) {
14223 			if(str2.length() < 1 || (str2[0] != '\"' && str[0] != '\'')) {
14224 				str2.insert(0, "\"");
14225 				str2 += "\"";
14226 			}
14227 		}
14228 		if(i > 0) {
14229 			str += CALCULATOR->getComma();
14230 			str += " ";
14231 		}
14232 		str += str2;
14233 	}
14234 	str += ")";
14235 	insert_text(str.c_str());
14236 	if(fd->add_to_menu) function_inserted(f);
14237 }
14238 
on_insert_function_delete(GtkWidget *,GdkEvent *,gpointer p)14239 void on_insert_function_delete(GtkWidget*, GdkEvent*, gpointer p) {
14240 	MathFunction *f = (MathFunction*) p;
14241 	FunctionDialog *fd = function_dialogs[f];
14242 	gtk_widget_destroy(fd->dialog);
14243 	delete fd;
14244 	function_dialogs.erase(f);
14245 }
on_insert_function_close(GtkWidget *,gpointer p)14246 void on_insert_function_close(GtkWidget*, gpointer p) {
14247 	MathFunction *f = (MathFunction*) p;
14248 	FunctionDialog *fd = function_dialogs[f];
14249 	gtk_widget_destroy(fd->dialog);
14250 	delete fd;
14251 	function_dialogs.erase(f);
14252 }
on_insert_function_exec(GtkWidget *,gpointer p)14253 void on_insert_function_exec(GtkWidget*, gpointer p) {
14254 	MathFunction *f = (MathFunction*) p;
14255 	FunctionDialog *fd = function_dialogs[f];
14256 	if(!fd->keep_open) gtk_widget_hide(fd->dialog);
14257 	gtk_text_buffer_set_text(expressionbuffer, "", -1);
14258 	insert_function_do(f, fd);
14259 	execute_expression();
14260 	if(fd->keep_open) {
14261 		string str;
14262 		bool b_approx = result_text_approximate || (mstruct && mstruct->isApproximate());
14263 		if(!b_approx) {
14264 			str = "=";
14265 		} else {
14266 			if(printops.use_unicode_signs && can_display_unicode_string_function(SIGN_ALMOST_EQUAL, (void*) historyview)) {
14267 				str = SIGN_ALMOST_EQUAL;
14268 			} else {
14269 				str = "= ";
14270 				str += _("approx.");
14271 			}
14272 		}
14273 		str += " <span font-weight=\"bold\">";
14274 		str += fix_history_string(result_text);
14275 		str += "</span> ";
14276 		gtk_label_set_markup(GTK_LABEL(fd->w_result), str.c_str());
14277 		gtk_widget_grab_focus(fd->entry[0]);
14278 	} else {
14279 		gtk_widget_destroy(fd->dialog);
14280 		delete fd;
14281 		function_dialogs.erase(f);
14282 	}
14283 }
on_insert_function_insert(GtkWidget *,gpointer p)14284 void on_insert_function_insert(GtkWidget*, gpointer p) {
14285 	MathFunction *f = (MathFunction*) p;
14286 	FunctionDialog *fd = function_dialogs[f];
14287 	if(!fd->keep_open) gtk_widget_hide(fd->dialog);
14288 	insert_function_do(f, fd);
14289 	if(fd->keep_open) {
14290 		gtk_widget_grab_focus(fd->entry[0]);
14291 	} else {
14292 		gtk_widget_destroy(fd->dialog);
14293 		delete fd;
14294 		function_dialogs.erase(f);
14295 	}
14296 }
on_insert_function_rpn(GtkWidget * w,gpointer p)14297 void on_insert_function_rpn(GtkWidget *w, gpointer p) {
14298 	MathFunction *f = (MathFunction*) p;
14299 	FunctionDialog *fd = function_dialogs[f];
14300 	if(!fd->keep_open) gtk_widget_hide(fd->dialog);
14301 	calculateRPN(f);
14302 	if(fd->add_to_menu) function_inserted(f);
14303 	if(fd->keep_open) {
14304 		gtk_widget_grab_focus(fd->entry[0]);
14305 	} else {
14306 		gtk_widget_destroy(fd->dialog);
14307 		delete fd;
14308 		function_dialogs.erase(f);
14309 	}
14310 }
on_insert_function_keepopen(GtkToggleButton * w,gpointer p)14311 void on_insert_function_keepopen(GtkToggleButton *w, gpointer p) {
14312 	MathFunction *f = (MathFunction*) p;
14313 	FunctionDialog *fd = function_dialogs[f];
14314 	fd->keep_open = gtk_toggle_button_get_active(w);
14315 	keep_function_dialog_open = fd->keep_open;
14316 }
on_insert_function_changed(GtkWidget * w,gpointer p)14317 void on_insert_function_changed(GtkWidget *w, gpointer p) {
14318 	MathFunction *f = (MathFunction*) p;
14319 	FunctionDialog *fd = function_dialogs[f];
14320 	gtk_label_set_text(GTK_LABEL(fd->w_result), "");
14321 }
on_insert_function_entry_activated(GtkWidget * w,gpointer p)14322 void on_insert_function_entry_activated(GtkWidget *w, gpointer p) {
14323 	MathFunction *f = (MathFunction*) p;
14324 	FunctionDialog *fd = function_dialogs[f];
14325 	for(int i = 0; i < fd->args; i++) {
14326 		if(fd->entry[i] == w) {
14327 			if(i == fd->args - 1) {
14328 				if(fd->rpn) on_insert_function_rpn(w, p);
14329 				else if(fd->keep_open || rpn_mode) on_insert_function_exec(w, p);
14330 				else on_insert_function_insert(w, p);
14331 			} else {
14332 				if(f->getArgumentDefinition(i + 2) && f->getArgumentDefinition(i + 2)->type() == ARGUMENT_TYPE_BOOLEAN) {
14333 					gtk_widget_grab_focus(fd->boolean_buttons[fd->boolean_index[i + 1]]);
14334 				} else {
14335 					gtk_widget_grab_focus(fd->entry[i + 1]);
14336 				}
14337 			}
14338 			break;
14339 		}
14340 	}
14341 
14342 }
14343 
14344 /*
14345 	insert function
14346 	pops up an argument entry dialog and inserts function into expression entry
14347 	parent is parent window
14348 */
insert_function(MathFunction * f,GtkWidget * parent=NULL,bool add_to_menu=true)14349 void insert_function(MathFunction *f, GtkWidget *parent = NULL, bool add_to_menu = true) {
14350 	if(!f) {
14351 		return;
14352 	}
14353 
14354 	//if function takes no arguments, do not display dialog and insert function directly
14355 	if(f->args() == 0) {
14356 		string str = f->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext).name + "()";
14357 		gchar *gstr = g_strdup(str.c_str());
14358 		function_inserted(f);
14359 		insert_text(gstr);
14360 		g_free(gstr);
14361 		return;
14362 	}
14363 
14364 	GtkTextIter istart, iend;
14365 	gtk_text_buffer_get_selection_bounds(expressionbuffer, &istart, &iend);
14366 
14367 	if(function_dialogs.find(f) != function_dialogs.end()) {
14368 		FunctionDialog *fd = function_dialogs[f];
14369 		if(fd->args > 0) {
14370 			Argument *arg = f->getArgumentDefinition(1);
14371 			if(arg && arg->type() == ARGUMENT_TYPE_BOOLEAN) {
14372 			} else if(fd->properties_store && arg && arg->type() == ARGUMENT_TYPE_DATA_PROPERTY) {
14373 			} else {
14374 				g_signal_handlers_block_matched((gpointer) fd->entry[0], G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_insert_function_changed, NULL);
14375 				//insert selection in expression entry into the first argument entry
14376 				string str = get_selected_expression_text(true), str2;
14377 				CALCULATOR->separateToExpression(str, str2, evalops, true);
14378 				remove_blank_ends(str);
14379 				gtk_entry_set_text(GTK_ENTRY(fd->entry[0]), str.c_str());
14380 				if(arg && arg->type() == ARGUMENT_TYPE_INTEGER) {
14381 					gtk_spin_button_update(GTK_SPIN_BUTTON(fd->entry[0]));
14382 				}
14383 				g_signal_handlers_unblock_matched((gpointer) fd->entry[0], G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_insert_function_changed, NULL);
14384 			}
14385 			gtk_widget_grab_focus(fd->entry[0]);
14386 		}
14387 		gtk_window_present_with_time(GTK_WINDOW(fd->dialog), GDK_CURRENT_TIME);
14388 		return;
14389 	}
14390 
14391 	FunctionDialog *fd = new FunctionDialog;
14392 
14393 	function_dialogs[f] = fd;
14394 
14395 	int args = 0;
14396 	bool has_vector = false;
14397 	if(f->args() > 0) {
14398 		args = f->args();
14399 	} else if(f->minargs() > 0) {
14400 		args = f->minargs() + 1;
14401 		has_vector = true;
14402 	} else {
14403 		args = 1;
14404 		has_vector = true;
14405 	}
14406 	fd->args = args;
14407 
14408 	fd->rpn = rpn_mode && expression_is_empty() && CALCULATOR->RPNStackSize() >= (f->minargs() <= 0 ? 1 : (size_t) f->minargs());
14409 	fd->add_to_menu = add_to_menu;
14410 
14411 	string f_title = f->title(true);
14412 	fd->dialog = gtk_dialog_new();
14413 	gtk_window_set_title(GTK_WINDOW(fd->dialog), f_title.c_str());
14414 	gtk_window_set_transient_for(GTK_WINDOW(fd->dialog), GTK_WINDOW(parent));
14415 	gtk_window_set_destroy_with_parent(GTK_WINDOW(fd->dialog), TRUE);
14416 
14417 	fd->b_keepopen = gtk_check_button_new_with_label(_("Keep open"));
14418 	gtk_dialog_add_action_widget(GTK_DIALOG(fd->dialog), fd->b_keepopen, GTK_RESPONSE_NONE);
14419 	fd->keep_open = keep_function_dialog_open;
14420 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fd->b_keepopen), fd->keep_open);
14421 
14422 	fd->b_cancel = gtk_button_new_with_mnemonic(_("_Close"));
14423 	gtk_dialog_add_action_widget(GTK_DIALOG(fd->dialog), fd->b_cancel, GTK_RESPONSE_REJECT);
14424 
14425 	// RPN Enter (calculate and add to stack)
14426 	fd->b_exec = gtk_button_new_with_mnemonic(rpn_mode ? _("Enter") : _("C_alculate"));
14427 	gtk_dialog_add_action_widget(GTK_DIALOG(fd->dialog), fd->b_exec, GTK_RESPONSE_APPLY);
14428 
14429 	fd->b_insert = gtk_button_new_with_mnemonic(rpn_mode ? _("Apply to Stack") : _("_Insert"));
14430 	if(rpn_mode && CALCULATOR->RPNStackSize() < (f->minargs() <= 0 ? 1 : (size_t) f->minargs())) gtk_widget_set_sensitive(fd->b_insert, FALSE);
14431 	gtk_dialog_add_action_widget(GTK_DIALOG(fd->dialog), fd->b_insert, GTK_RESPONSE_ACCEPT);
14432 
14433 	gtk_container_set_border_width(GTK_CONTAINER(fd->dialog), 6);
14434 	gtk_window_set_resizable(GTK_WINDOW(fd->dialog), FALSE);
14435 	GtkWidget *vbox_pre = gtk_box_new(GTK_ORIENTATION_VERTICAL, 18);
14436 	gtk_container_set_border_width(GTK_CONTAINER(vbox_pre), 6);
14437 	gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(fd->dialog))), vbox_pre);
14438 	f_title.insert(0, "<b>");
14439 	f_title += "</b>";
14440 	GtkWidget *title_label = gtk_label_new(f_title.c_str());
14441 	gtk_label_set_use_markup(GTK_LABEL(title_label), TRUE);
14442 	gtk_widget_set_halign(title_label, GTK_ALIGN_START);
14443 
14444 	gtk_container_add(GTK_CONTAINER(vbox_pre), title_label);
14445 
14446 	GtkWidget *table = gtk_grid_new();
14447 	gtk_grid_set_row_spacing(GTK_GRID(table), 6);
14448 	gtk_grid_set_column_spacing(GTK_GRID(table), 6);
14449 	gtk_grid_set_row_homogeneous(GTK_GRID(table), TRUE);
14450 	gtk_container_add(GTK_CONTAINER(vbox_pre), table);
14451 	gtk_widget_set_hexpand(table, TRUE);
14452 	fd->label.resize(args, NULL);
14453 	fd->entry.resize(args, NULL);
14454 	fd->type_label.resize(args, NULL);
14455 	fd->boolean_index.resize(args, 0);
14456 
14457 	fd->w_result = gtk_label_new("");
14458 	gtk_widget_set_margin_bottom(fd->w_result, 6);
14459 	gtk_label_set_max_width_chars(GTK_LABEL(fd->w_result), 20);
14460 	gtk_label_set_ellipsize(GTK_LABEL(fd->w_result), PANGO_ELLIPSIZE_MIDDLE);
14461 	gtk_widget_set_hexpand(fd->w_result, TRUE);
14462 	gtk_label_set_selectable(GTK_LABEL(fd->w_result), TRUE);
14463 
14464 #if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 16
14465 	gtk_label_set_xalign(GTK_LABEL(fd->w_result), 1.0);
14466 #else
14467 	gtk_misc_set_alignment(GTK_MISC(fd->w_result), 1.0, 0.5);
14468 #endif
14469 
14470 	int bindex = 0;
14471 	string argstr, typestr, defstr;
14472 	string argtype;
14473 	Argument *arg;
14474 	//create argument entries
14475 	fd->properties_store = NULL;
14476 	for(int i = 0; i < args; i++) {
14477 		arg = f->getArgumentDefinition(i + 1);
14478 		if(!arg || arg->name().empty()) {
14479 			if(args == 1) {
14480 				argstr = _("Value");
14481 			} else {
14482 				argstr = _("Argument");
14483 				argstr += " ";
14484 				argstr += i2s(i + 1);
14485 			}
14486 		} else {
14487 			argstr = arg->name();
14488 		}
14489 		typestr = "";
14490 		argtype = "";
14491 		ParseOptions pa = evalops.parse_options; pa.base = 10;
14492 		defstr = CALCULATOR->localizeExpression(f->getDefaultValue(i + 1), pa);
14493 		if(arg && (arg->suggestsQuotes() || arg->type() == ARGUMENT_TYPE_TEXT) && defstr.length() >= 2 && defstr[0] == '\"' && defstr[defstr.length() - 1] == '\"') {
14494 			defstr = defstr.substr(1, defstr.length() - 2);
14495 		}
14496 		fd->label[i] = gtk_label_new(argstr.c_str());
14497 		gtk_widget_set_halign(fd->label[i], GTK_ALIGN_END);
14498 		gtk_widget_set_hexpand(fd->label[i], FALSE);
14499 #if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 12
14500 		gtk_widget_set_margin_end(fd->label[i], 6);
14501 #else
14502 		gtk_widget_set_margin_right(fd->label[i], 6);
14503 #endif
14504 		GtkWidget *combo = NULL;
14505 		if(arg) {
14506 			switch(arg->type()) {
14507 				case ARGUMENT_TYPE_INTEGER: {
14508 					IntegerArgument *iarg = (IntegerArgument*) arg;
14509 					glong min = LONG_MIN, max = LONG_MAX;
14510 					if(iarg->min()) {
14511 						min = iarg->min()->lintValue();
14512 					}
14513 					if(iarg->max()) {
14514 						max = iarg->max()->lintValue();
14515 					}
14516 					fd->entry[i] = gtk_spin_button_new_with_range(min, max, 1);
14517 					gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(fd->entry[i]), evalops.parse_options.base != BASE_DECIMAL);
14518 					gtk_entry_set_alignment(GTK_ENTRY(fd->entry[i]), 1.0);
14519 					g_signal_connect(G_OBJECT(fd->entry[i]), "input", G_CALLBACK(on_function_int_input), NULL);
14520 					g_signal_connect(G_OBJECT(fd->entry[i]), "key-press-event", G_CALLBACK(on_math_entry_key_press_event), NULL);
14521 					if(!arg->zeroForbidden() && min <= 0 && max >= 0) {
14522 						gtk_spin_button_set_value(GTK_SPIN_BUTTON(fd->entry[i]), 0);
14523 					} else {
14524 						if(max < 0) {
14525 							gtk_spin_button_set_value(GTK_SPIN_BUTTON(fd->entry[i]), max);
14526 						} else if(min <= 1) {
14527 							gtk_spin_button_set_value(GTK_SPIN_BUTTON(fd->entry[i]), 1);
14528 						} else {
14529 							gtk_spin_button_set_value(GTK_SPIN_BUTTON(fd->entry[i]), min);
14530 						}
14531 					}
14532 					g_signal_connect(G_OBJECT(fd->entry[i]), "changed", G_CALLBACK(on_insert_function_changed), (gpointer) f);
14533 					g_signal_connect(G_OBJECT(fd->entry[i]), "activate", G_CALLBACK(on_insert_function_entry_activated), (gpointer) f);
14534 					break;
14535 				}
14536 				case ARGUMENT_TYPE_BOOLEAN: {
14537 					fd->boolean_index[i] = bindex;
14538 					bindex += 2;
14539 					fd->entry[i] = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
14540 					gtk_box_set_homogeneous(GTK_BOX(fd->entry[i]), TRUE);
14541 					gtk_widget_set_halign(fd->entry[i], GTK_ALIGN_START);
14542 					fd->boolean_buttons.push_back(gtk_radio_button_new_with_label(NULL, _("True")));
14543 					gtk_box_pack_start(GTK_BOX(fd->entry[i]), fd->boolean_buttons[fd->boolean_buttons.size() - 1], TRUE, TRUE, 0);
14544 					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")));
14545 					gtk_box_pack_end(GTK_BOX(fd->entry[i]), fd->boolean_buttons[fd->boolean_buttons.size() - 1], TRUE, TRUE, 0);
14546 					gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fd->boolean_buttons[fd->boolean_buttons.size() - 1]), TRUE);
14547 					g_signal_connect(G_OBJECT(fd->boolean_buttons[fd->boolean_buttons.size() - 1]), "toggled", G_CALLBACK(on_insert_function_changed), (gpointer) f);
14548 					g_signal_connect(G_OBJECT(fd->boolean_buttons[fd->boolean_buttons.size() - 2]), "toggled", G_CALLBACK(on_insert_function_changed), (gpointer) f);
14549 					break;
14550 				}
14551 				case ARGUMENT_TYPE_DATA_PROPERTY: {
14552 					if(f->subtype() == SUBTYPE_DATA_SET) {
14553 						fd->properties_store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_POINTER);
14554 						gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(fd->properties_store), 0, string_sort_func, GINT_TO_POINTER(0), NULL);
14555 						gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(fd->properties_store), 0, GTK_SORT_ASCENDING);
14556 						fd->entry[i] = gtk_combo_box_new_with_model(GTK_TREE_MODEL(fd->properties_store));
14557 						GtkCellRenderer *cell = gtk_cell_renderer_text_new();
14558 						gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(fd->entry[i]), cell, TRUE);
14559 						gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(fd->entry[i]), cell, "text", 0);
14560 						DataPropertyIter it;
14561 						DataSet *ds = (DataSet*) f;
14562 						DataProperty *dp = ds->getFirstProperty(&it);
14563 						GtkTreeIter iter;
14564 						bool active_set = false;
14565 						if(fd->rpn && (size_t) i < CALCULATOR->RPNStackSize()) {
14566 							GtkTreeIter iter;
14567 							if(gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(stackstore), &iter, NULL, i)) {
14568 								gchar *gstr;
14569 								gtk_tree_model_get(GTK_TREE_MODEL(stackstore), &iter, 1, &gstr, -1);
14570 								defstr = gstr;
14571 								g_free(gstr);
14572 							}
14573 						}
14574 						while(dp) {
14575 							if(!dp->isHidden()) {
14576 								gtk_list_store_append(fd->properties_store, &iter);
14577 								if(!active_set && defstr == dp->getName()) {
14578 									gtk_combo_box_set_active_iter(GTK_COMBO_BOX(fd->entry[i]), &iter);
14579 									active_set = true;
14580 								}
14581 								gtk_list_store_set(fd->properties_store, &iter, 0, dp->title().c_str(), 1, (gpointer) dp, -1);
14582 							}
14583 							dp = ds->getNextProperty(&it);
14584 						}
14585 						gtk_list_store_append(fd->properties_store, &iter);
14586 						if(!active_set) {
14587 							gtk_combo_box_set_active_iter(GTK_COMBO_BOX(fd->entry[i]), &iter);
14588 						}
14589 						gtk_list_store_set(fd->properties_store, &iter, 0, _("Info"), 1, (gpointer) NULL, -1);
14590 						g_signal_connect(G_OBJECT(fd->entry[i]), "changed", G_CALLBACK(on_insert_function_changed), (gpointer) f);
14591 						break;
14592 					}
14593 				}
14594 				default: {
14595 					argtype = arg->print();
14596 					typestr = "";
14597 					if(!argtype.empty()) {
14598 						typestr = "(";
14599 						typestr += argtype;
14600 						typestr += ")";
14601 					}
14602 					if(i == 1 && f == CALCULATOR->f_ascii && arg->type() == ARGUMENT_TYPE_TEXT) {
14603 						combo = gtk_combo_box_text_new_with_entry();
14604 						gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), "UTF-8");
14605 						gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), "UTF-16");
14606 						gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), "UTF-32");
14607 						fd->entry[i] = gtk_bin_get_child(GTK_BIN(combo));
14608 					} else if(i == 3 && f == CALCULATOR->f_date && arg->type() == ARGUMENT_TYPE_TEXT) {
14609 						combo = gtk_combo_box_text_new_with_entry();
14610 						gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), "chinese");
14611 						gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), "coptic");
14612 						gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), "egyptian");
14613 						gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), "ethiopian");
14614 						gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), "gregorian");
14615 						gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), "hebrew");
14616 						gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), "indian");
14617 						gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), "islamic");
14618 						gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), "julian");
14619 						gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), "milankovic");
14620 						gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), "persian");
14621 						fd->entry[i] = gtk_bin_get_child(GTK_BIN(combo));
14622 					} else {
14623 						fd->entry[i] = gtk_entry_new();
14624 					}
14625 					if(i >= f->minargs() && !has_vector) {
14626 						gtk_entry_set_placeholder_text(GTK_ENTRY(fd->entry[i]), _("optional"));
14627 					}
14628 					gtk_entry_set_alignment(GTK_ENTRY(fd->entry[i]), 1.0);
14629 					g_signal_connect(G_OBJECT(fd->entry[i]), "key-press-event", G_CALLBACK(on_math_entry_key_press_event), NULL);
14630 					g_signal_connect(G_OBJECT(fd->entry[i]), "changed", G_CALLBACK(on_insert_function_changed), (gpointer) f);
14631 					g_signal_connect(G_OBJECT(fd->entry[i]), "activate", G_CALLBACK(on_insert_function_entry_activated), (gpointer) f);
14632 				}
14633 			}
14634 		} else {
14635 			fd->entry[i] = gtk_entry_new();
14636 			if(i >= f->minargs() && !has_vector) {
14637 				gtk_entry_set_placeholder_text(GTK_ENTRY(fd->entry[i]), _("optional"));
14638 			}
14639 			gtk_entry_set_alignment(GTK_ENTRY(fd->entry[i]), 1.0);
14640 			g_signal_connect(G_OBJECT(fd->entry[i]), "key-press-event", G_CALLBACK(on_math_entry_key_press_event), NULL);
14641 			g_signal_connect(G_OBJECT(fd->entry[i]), "changed", G_CALLBACK(on_insert_function_changed), (gpointer) f);
14642 			g_signal_connect(G_OBJECT(fd->entry[i]), "activate", G_CALLBACK(on_insert_function_entry_activated), (gpointer) f);
14643 		}
14644 		gtk_widget_set_hexpand(fd->entry[i], TRUE);
14645 		if(arg && arg->type() == ARGUMENT_TYPE_DATE) {
14646 			if(defstr == "now") defstr = CALCULATOR->v_now->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) fd->entry[i]).name;
14647 			else if(defstr == "today") defstr = CALCULATOR->v_today->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) fd->entry[i]).name;
14648 			typestr = typestr.substr(1, typestr.length() - 2);
14649 			fd->type_label[i] = gtk_button_new_with_label(typestr.c_str());
14650 			g_signal_connect(G_OBJECT(fd->type_label[i]), "clicked", G_CALLBACK(on_type_label_date_clicked), (gpointer) fd->entry[i]);
14651 			gtk_widget_set_halign(fd->type_label[i], GTK_ALIGN_FILL);
14652 		} else if(arg && arg->type() == ARGUMENT_TYPE_FILE) {
14653 			typestr = typestr.substr(1, typestr.length() - 2);
14654 			fd->type_label[i] = gtk_button_new_with_label(typestr.c_str());
14655 			g_signal_connect(G_OBJECT(fd->type_label[i]), "clicked", G_CALLBACK(on_type_label_file_clicked), (gpointer) fd->entry[i]);
14656 			gtk_widget_set_halign(fd->type_label[i], GTK_ALIGN_FILL);
14657 		} else if(arg && (arg->type() == ARGUMENT_TYPE_VECTOR || arg->type() == ARGUMENT_TYPE_MATRIX)) {
14658 			typestr = typestr.substr(1, typestr.length() - 2);
14659 			fd->type_label[i] = gtk_button_new_with_label(typestr.c_str());
14660 			if(arg->type() == ARGUMENT_TYPE_VECTOR) g_signal_connect(G_OBJECT(fd->type_label[i]), "clicked", G_CALLBACK(on_type_label_vector_clicked), (gpointer) fd->entry[i]);
14661 			else g_signal_connect(G_OBJECT(fd->type_label[i]), "clicked", G_CALLBACK(on_type_label_matrix_clicked), (gpointer) fd->entry[i]);
14662 			gtk_widget_set_halign(fd->type_label[i], GTK_ALIGN_FILL);
14663 		} else if(!typestr.empty()) {
14664 			fd->type_label[i] = gtk_label_new(typestr.c_str());
14665 			gtk_widget_set_halign(fd->type_label[i], GTK_ALIGN_START);
14666 		} else {
14667 			fd->type_label[i] = NULL;
14668 		}
14669 		if(fd->rpn && (size_t) i < CALCULATOR->RPNStackSize()) {
14670 			GtkTreeIter iter;
14671 			if(gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(stackstore), &iter, NULL, i)) {
14672 				gchar *gstr;
14673 				gtk_tree_model_get(GTK_TREE_MODEL(stackstore), &iter, 1, &gstr, -1);
14674 				if(arg && arg->type() == ARGUMENT_TYPE_BOOLEAN) {
14675 					if(g_strcmp0(gstr, "1") == 0) {
14676 						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);
14677 						gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fd->boolean_buttons[fd->boolean_buttons.size() - 2]), TRUE);
14678 						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);
14679 					}
14680 				} else if(fd->properties_store && arg && arg->type() == ARGUMENT_TYPE_DATA_PROPERTY) {
14681 				} else {
14682 					g_signal_handlers_block_matched((gpointer) fd->entry[i], G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_insert_function_changed, NULL);
14683 					if(i == 0 && args == 1 && (has_vector || arg->type() == ARGUMENT_TYPE_VECTOR)) {
14684 						string rpn_vector = gstr;
14685 						while(gtk_tree_model_iter_next(GTK_TREE_MODEL(stackstore), &iter)) {
14686 							g_free(gstr);
14687 							gtk_tree_model_get(GTK_TREE_MODEL(stackstore), &iter, 1, &gstr, -1);
14688 							rpn_vector += CALCULATOR->getComma();
14689 							rpn_vector += " ";
14690 							rpn_vector += gstr;
14691 						}
14692 						gtk_entry_set_text(GTK_ENTRY(fd->entry[i]), rpn_vector.c_str());
14693 					} else {
14694 						gtk_entry_set_text(GTK_ENTRY(fd->entry[i]), gstr);
14695 						if(arg && arg->type() == ARGUMENT_TYPE_INTEGER) {
14696 							gtk_spin_button_update(GTK_SPIN_BUTTON(fd->entry[i]));
14697 						}
14698 					}
14699 					g_signal_handlers_unblock_matched((gpointer) fd->entry[i], G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_insert_function_changed, NULL);
14700 				}
14701 				g_free(gstr);
14702 			}
14703 		} else if(arg && arg->type() == ARGUMENT_TYPE_BOOLEAN) {
14704 			if(defstr == "1") {
14705 				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);
14706 				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fd->boolean_buttons[fd->boolean_buttons.size() - 2]), TRUE);
14707 				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);
14708 			}
14709 		} else if(fd->properties_store && arg && arg->type() == ARGUMENT_TYPE_DATA_PROPERTY) {
14710 		} else {
14711 			g_signal_handlers_block_matched((gpointer) fd->entry[i], G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_insert_function_changed, NULL);
14712 			if(!defstr.empty() && (i < f->minargs() || has_vector || (defstr != "undefined" && defstr != "\"\""))) {
14713 				gtk_entry_set_text(GTK_ENTRY(fd->entry[i]), defstr.c_str());
14714 				if(arg && arg->type() == ARGUMENT_TYPE_INTEGER) {
14715 					gtk_spin_button_update(GTK_SPIN_BUTTON(fd->entry[i]));
14716 				}
14717 			}
14718 			//insert selection in expression entry into the first argument entry
14719 			if(i == 0) {
14720 				string seltext = get_selected_expression_text(true), str2;
14721 				CALCULATOR->separateToExpression(seltext, str2, evalops, true);
14722 				remove_blank_ends(seltext);
14723 				if(!seltext.empty()) {
14724 					gtk_entry_set_text(GTK_ENTRY(fd->entry[i]), seltext.c_str());
14725 					if(arg && arg->type() == ARGUMENT_TYPE_INTEGER) {
14726 						gtk_spin_button_update(GTK_SPIN_BUTTON(fd->entry[i]));
14727 					}
14728 				}
14729 			}
14730 			g_signal_handlers_unblock_matched((gpointer) fd->entry[i], G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_insert_function_changed, NULL);
14731 		}
14732 		gtk_grid_attach(GTK_GRID(table), fd->label[i], 0, i, 1, 1);
14733 		if(combo) gtk_grid_attach(GTK_GRID(table), combo, 1, i, 1, 1);
14734 		else gtk_grid_attach(GTK_GRID(table), fd->entry[i], 1, i, 1, 1);
14735 		if(fd->type_label[i]) {
14736 			gtk_widget_set_hexpand(fd->type_label[i], FALSE);
14737 			gtk_grid_attach(GTK_GRID(table), fd->type_label[i], 2, i, 1, 1);
14738 		}
14739 	}
14740 
14741 	//display function description
14742 	if(!f->description().empty() || !f->example(true).empty()) {
14743 		GtkWidget *descr_frame = gtk_scrolled_window_new(NULL, NULL);
14744 		gtk_container_add(GTK_CONTAINER(vbox_pre), descr_frame);
14745 		gtk_container_add(GTK_CONTAINER(vbox_pre), fd->w_result);
14746 		GtkWidget *descr = gtk_text_view_new();
14747 		gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(descr), GTK_WRAP_WORD);
14748 		gtk_text_view_set_editable(GTK_TEXT_VIEW(descr), FALSE);
14749 		GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(descr));
14750 		string str;
14751 		if(!f->description().empty()) str += f->description();
14752 		if(!f->example(true).empty()) {
14753 			if(!str.empty()) str += "\n\n";
14754 			str += _("Example:");
14755 			str += " ";
14756 			str += f->example(false);
14757 		}
14758 		gtk_text_buffer_set_text(buffer, str.c_str(), -1);
14759 		gtk_container_add(GTK_CONTAINER(descr_frame), descr);
14760 #if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 18
14761 		gtk_text_view_set_left_margin(GTK_TEXT_VIEW(descr), 12);
14762 		gtk_text_view_set_right_margin(GTK_TEXT_VIEW(descr), 12);
14763 		gtk_text_view_set_top_margin(GTK_TEXT_VIEW(descr), 12);
14764 		gtk_text_view_set_bottom_margin(GTK_TEXT_VIEW(descr), 12);
14765 #else
14766 		gtk_text_view_set_left_margin(GTK_TEXT_VIEW(descr), 6);
14767 		gtk_text_view_set_right_margin(GTK_TEXT_VIEW(descr), 6);
14768 		gtk_text_view_set_pixels_above_lines(GTK_TEXT_VIEW(descr), 6);
14769 #endif
14770 		gtk_widget_show_all(vbox_pre);
14771 		gint nw, mw, nh, mh;
14772 		gtk_widget_get_preferred_width(vbox_pre, &mw, &nw);
14773 		gtk_widget_get_preferred_height(vbox_pre, &mh, &nh);
14774 		PangoLayout *layout_test = gtk_widget_create_pango_layout(descr, NULL);
14775 		pango_layout_set_text(layout_test, str.c_str(), -1);
14776 		pango_layout_set_width(layout_test, (nw - 24) * PANGO_SCALE);
14777 		pango_layout_set_wrap(layout_test, PANGO_WRAP_WORD);
14778 		gint w, h;
14779 		pango_layout_get_pixel_size(layout_test, &w, &h);
14780 		h *= 1.2;
14781 		if(h > nh) h = nh;
14782 		if(h < 100) h = 100;
14783 		gtk_widget_set_size_request(descr_frame, -1, h);
14784 	} else {
14785 		gtk_grid_attach(GTK_GRID(table), fd->w_result, 0, args, 2, 1);
14786 	}
14787 
14788 	g_signal_connect(G_OBJECT(fd->b_exec), "clicked", G_CALLBACK(on_insert_function_exec), (gpointer) f);
14789 	if(fd->rpn) g_signal_connect(G_OBJECT(fd->b_insert), "clicked", G_CALLBACK(on_insert_function_rpn), (gpointer) f);
14790 	else g_signal_connect(G_OBJECT(fd->b_insert), "clicked", G_CALLBACK(on_insert_function_insert), (gpointer) f);
14791 	g_signal_connect(G_OBJECT(fd->b_cancel), "clicked", G_CALLBACK(on_insert_function_close), (gpointer) f);
14792 	g_signal_connect(G_OBJECT(fd->b_keepopen), "toggled", G_CALLBACK(on_insert_function_keepopen), (gpointer) f);
14793 	g_signal_connect(G_OBJECT(fd->dialog), "delete-event", G_CALLBACK(on_insert_function_delete), (gpointer) f);
14794 
14795 	gtk_widget_show_all(fd->dialog);
14796 
14797 	block_add_to_undo++;
14798 	gtk_text_buffer_select_range(expressionbuffer, &istart, &iend);
14799 	block_add_to_undo--;
14800 
14801 }
14802 
14803 /*
14804 	called from function menu
14805 */
insert_function(GtkMenuItem *,gpointer user_data)14806 void insert_function(GtkMenuItem*, gpointer user_data) {
14807 	if(!CALCULATOR->stillHasFunction((MathFunction*) user_data)) return;
14808 	insert_function((MathFunction*) user_data, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")));
14809 }
14810 
14811 /*
14812 	called from variable menu
14813 	just insert text data stored in menu item
14814 */
insert_variable(GtkMenuItem *,gpointer user_data)14815 void insert_variable(GtkMenuItem*, gpointer user_data) {
14816 	Variable *v = (Variable*) user_data;
14817 	if(!CALCULATOR->stillHasVariable(v)) {
14818 		show_message(_("Variable does not exist anymore."), GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")));
14819 		update_vmenu();
14820 		return;
14821 	}
14822 	insert_text(v->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext).name.c_str());
14823 	variable_inserted((Variable*) user_data);
14824 }
insert_var(Variable * v)14825 void insert_var(Variable *v) {
14826 	if(!v || !CALCULATOR->stillHasVariable(v)) {
14827 		show_message(_("Variable does not exist anymore."), GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")));
14828 		return;
14829 	}
14830 	insert_text(v->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext).name.c_str());
14831 }
insert_button_variable(GtkWidget *,gpointer user_data)14832 void insert_button_variable(GtkWidget*, gpointer user_data) {
14833 	insert_var((Variable*) user_data);
14834 }
14835 
14836 //from prefix menu
insert_prefix(GtkMenuItem *,gpointer user_data)14837 void insert_prefix(GtkMenuItem*, gpointer user_data) {
14838 	insert_text(((Prefix*) user_data)->name(printops.abbreviate_names, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) expressiontext).c_str());
14839 }
14840 //from unit menu
insert_unit(GtkMenuItem *,gpointer user_data)14841 void insert_unit(GtkMenuItem*, gpointer user_data) {
14842 	if(!CALCULATOR->stillHasUnit((Unit*) user_data)) return;
14843 	if(((Unit*) user_data)->subtype() == SUBTYPE_COMPOSITE_UNIT) {
14844 		insert_text(((CompositeUnit*) user_data)->print(true, printops.abbreviate_names, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) expressiontext).c_str());
14845 	} else {
14846 		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());
14847 	}
14848 	unit_inserted((Unit*) user_data);
14849 }
14850 
insert_button_unit(GtkMenuItem *,gpointer user_data)14851 void insert_button_unit(GtkMenuItem*, gpointer user_data) {
14852 	if(!CALCULATOR->stillHasUnit((Unit*) user_data)) return;
14853 	if(((Unit*) user_data)->subtype() == SUBTYPE_COMPOSITE_UNIT) {
14854 		insert_text(((CompositeUnit*) user_data)->print(true, printops.abbreviate_names, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) expressiontext).c_str());
14855 	} else {
14856 		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());
14857 	}
14858 	if((Unit*) user_data != latest_button_unit) {
14859 		latest_button_unit = (Unit*) user_data;
14860 		string si_label_str;
14861 		if(((Unit*) user_data)->subtype() == SUBTYPE_COMPOSITE_UNIT) {
14862 			si_label_str = ((CompositeUnit*) latest_button_unit)->print(false, true, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) expressiontext);
14863 		} else {
14864 
14865 			si_label_str = latest_button_unit->preferredDisplayName(true, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext).name;
14866 		}
14867 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_si")), si_label_str.c_str());
14868 		gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_si")), latest_button_unit->title(true).c_str());
14869 	}
14870 }
insert_button_currency(GtkMenuItem *,gpointer user_data)14871 void insert_button_currency(GtkMenuItem*, gpointer user_data) {
14872 	if(!CALCULATOR->stillHasUnit((Unit*) user_data)) return;
14873 	if(((Unit*) user_data)->subtype() == SUBTYPE_COMPOSITE_UNIT) {
14874 		insert_text(((CompositeUnit*) user_data)->print(true, printops.abbreviate_names, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) expressiontext).c_str());
14875 	} else {
14876 		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());
14877 	}
14878 	if((Unit*) user_data != latest_button_currency) {
14879 		latest_button_currency = (Unit*) user_data;
14880 		string currency_label_str;
14881 		if(((Unit*) user_data)->subtype() == SUBTYPE_COMPOSITE_UNIT) {
14882 			currency_label_str = ((CompositeUnit*) latest_button_currency)->print(false, true, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) expressiontext);
14883 		} else {
14884 
14885 			currency_label_str = latest_button_currency->preferredDisplayName(true, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext).name;
14886 		}
14887 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "label_euro")), currency_label_str.c_str());
14888 		gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_euro")), latest_button_currency->title(true).c_str());
14889 	}
14890 }
14891 
set_name_label_and_entry(ExpressionItem * item,GtkWidget * entry,GtkWidget * label)14892 void set_name_label_and_entry(ExpressionItem *item, GtkWidget *entry, GtkWidget *label) {
14893 	const ExpressionName *ename = &item->getName(1);
14894 	gtk_entry_set_text(GTK_ENTRY(entry), ename->name.c_str());
14895 	if(item->countNames() > 1) {
14896 		string str = "+ ";
14897 		for(size_t i = 2; i <= item->countNames(); i++) {
14898 			if(i > 2) str += ", ";
14899 			str += item->getName(i).name;
14900 		}
14901 		gtk_label_set_text(GTK_LABEL(label), str.c_str());
14902 	}
14903 }
set_edited_names(ExpressionItem * item,string str)14904 void set_edited_names(ExpressionItem *item, string str) {
14905 	if(item->isBuiltin() && !(item->type() == TYPE_FUNCTION && item->subtype() == SUBTYPE_DATA_SET)) return;
14906 	if(names_edited) {
14907 		item->clearNames();
14908 		GtkTreeIter iter;
14909 		if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tNames_store), &iter)) {
14910 			ExpressionName ename;
14911 			gchar *gstr;
14912 			while(true) {
14913 				gboolean abbreviation = FALSE, suffix = FALSE, unicode = FALSE, plural = FALSE;
14914 				gboolean reference = FALSE, avoid_input = FALSE, case_sensitive = FALSE, completion_only = FALSE;
14915 				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);
14916 				ename.name = gstr; ename.abbreviation = abbreviation; ename.suffix = suffix;
14917 				ename.unicode = unicode; ename.plural = plural; ename.reference = reference;
14918 				ename.avoid_input = avoid_input; ename.case_sensitive = case_sensitive;
14919 				ename.completion_only = completion_only;
14920 				item->addName(ename);
14921 				g_free(gstr);
14922 				if(!gtk_tree_model_iter_next(GTK_TREE_MODEL(tNames_store), &iter)) break;
14923 			}
14924 		} else {
14925 			item->addName(str);
14926 		}
14927 	} else {
14928 		if(item->countNames() == 0) {
14929 			ExpressionName ename(str);
14930 			ename.reference = true;
14931 			item->setName(ename, 1);
14932 		} else {
14933 			item->setName(str, 1);
14934 		}
14935 
14936 	}
14937 }
14938 
14939 /*
14940 	display edit/new unit dialog
14941 	creates new unit if u == NULL, win is parent window
14942 */
edit_unit(const char * category="",Unit * u=NULL,GtkWidget * win=NULL)14943 void edit_unit(const char *category = "", Unit *u = NULL, GtkWidget *win = NULL) {
14944 
14945 	edited_unit = u;
14946 	names_edited = false;
14947 	editing_unit = true;
14948 	GtkWidget *dialog = get_unit_edit_dialog();
14949 	if(win) gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(win));
14950 
14951 	if(u) {
14952 		if(u->isLocal())
14953 			gtk_window_set_title(GTK_WINDOW(dialog), _("Edit Unit"));
14954 		else
14955 			gtk_window_set_title(GTK_WINDOW(dialog), _("Edit Unit (global)"));
14956 	} else {
14957 		gtk_window_set_title(GTK_WINDOW(dialog), _("New Unit"));
14958 	}
14959 
14960 	GtkTextBuffer *description_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtk_builder_get_object(unitedit_builder, "unit_edit_textview_description")));
14961 
14962 	gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(unitedit_builder, "unit_edit_combo_category")))), category);
14963 
14964 	//clear entries
14965 	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_name")), "");
14966 	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_desc")), "");
14967 	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_base")), "");
14968 	gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_spinbutton_exp")), 1);
14969 	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_relation")), "");
14970 	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_reversed")), "");
14971 	gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(unitedit_builder, "unit_edit_combo_system")))), "");
14972 	gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(unitedit_builder, "unit_edit_label_names")), "");
14973 	gtk_text_buffer_set_text(description_buffer, "", -1);
14974 
14975 	if(u) {
14976 		//fill in original parameters
14977 		if(u->subtype() == SUBTYPE_BASE_UNIT) {
14978 			gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(unitedit_builder, "unit_edit_combobox_class")), UNIT_CLASS_BASE_UNIT);
14979 		} else if(u->subtype() == SUBTYPE_ALIAS_UNIT) {
14980 			gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(unitedit_builder, "unit_edit_combobox_class")), UNIT_CLASS_ALIAS_UNIT);
14981 		} else if(u->subtype() == SUBTYPE_COMPOSITE_UNIT) {
14982 			gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(unitedit_builder, "unit_edit_combobox_class")), UNIT_CLASS_COMPOSITE_UNIT);
14983 		}
14984 		on_unit_edit_combobox_class_changed(GTK_COMBO_BOX(gtk_builder_get_object(unitedit_builder, "unit_edit_combobox_class")), NULL);
14985 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_combobox_class")), !u->isBuiltin());
14986 
14987 		//gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_combobox_class")), u->isLocal() && !u->isBuiltin());
14988 
14989 		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")));
14990 
14991 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_name")), !u->isBuiltin());
14992 
14993 		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());
14994 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_combo_system")), !u->isBuiltin());
14995 
14996 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_checkbutton_hidden")), u->isHidden());
14997 
14998 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_checkbutton_use_prefixes")), u->useWithPrefixesByDefault());
14999 
15000 		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());
15001 		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_desc")), u->title(false).c_str());
15002 		gtk_text_buffer_set_text(description_buffer, u->description().c_str(), -1);
15003 
15004 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_checkbutton_mix")), FALSE);
15005 		gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_spinbutton_mix_priority")), 1);
15006 		gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_spinbutton_mix_min")), 1);
15007 
15008 		switch(u->subtype()) {
15009 			case SUBTYPE_ALIAS_UNIT: {
15010 				AliasUnit *au = (AliasUnit*) u;
15011 				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());
15012 				gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_spinbutton_exp")), au->firstBaseExponent());
15013 				if(au->firstBaseExponent() != 1) gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_frame_mix")), FALSE);
15014 				bool is_relative = false;
15015 				ParseOptions pa = evalops.parse_options; pa.base = 10;
15016 				if(au->uncertainty(&is_relative).empty()) {
15017 					gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_relation")), CALCULATOR->localizeExpression(au->expression(), pa).c_str());
15018 				} else if(is_relative) {
15019 					string value = CALCULATOR->f_uncertainty->referenceName();
15020 					value += "(";
15021 					value += au->expression();
15022 					value += CALCULATOR->getComma();
15023 					value += " ";
15024 					value += CALCULATOR->localizeExpression(au->uncertainty(), pa);
15025 					value += CALCULATOR->getComma();
15026 					value += " 1)";
15027 					gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_relation")), CALCULATOR->localizeExpression(value, pa).c_str());
15028 				} else {
15029 					gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_relation")), CALCULATOR->localizeExpression(au->expression() + SIGN_PLUSMINUS + au->uncertainty(), pa).c_str());
15030 				}
15031 				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_reversed")), CALCULATOR->localizeExpression(au->inverseExpression(), pa).c_str());
15032 				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_box_reversed")), au->hasNonlinearExpression());
15033 				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_checkbutton_exact")), !au->isApproximate());
15034 				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_relation")), !u->isBuiltin());
15035 				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_reversed")), !u->isBuiltin());
15036 				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_checkbutton_exact")), !u->isBuiltin());
15037 				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_spinbutton_exp")), !u->isBuiltin());
15038 				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_base")), !u->isBuiltin());
15039 				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_frame_mix")), !u->isBuiltin());
15040 				if(au->mixWithBase() > 0) {
15041 					gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_checkbutton_mix")), TRUE);
15042 					gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_spinbutton_mix_priority")), au->mixWithBase());
15043 					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);
15044 					on_unit_edit_checkbutton_mix_toggled(GTK_TOGGLE_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_checkbutton_mix")), NULL);
15045 				}
15046 				break;
15047 			}
15048 			case SUBTYPE_COMPOSITE_UNIT: {
15049 				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());
15050 				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_base")), !u->isBuiltin());
15051 			}
15052 			default: {
15053 				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_frame_mix")), FALSE);
15054 			}
15055 		}
15056 	} else {
15057 		//default values
15058 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_checkbutton_hidden")), false);
15059 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_checkbutton_exact")), TRUE);
15060 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_box_reversed")), false);
15061 		gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(unitedit_builder, "unit_edit_combobox_class")), UNIT_CLASS_BASE_UNIT);
15062 		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_relation")), "1");
15063 		on_unit_edit_combobox_class_changed(GTK_COMBO_BOX(gtk_builder_get_object(unitedit_builder, "unit_edit_combobox_class")), NULL);
15064 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_button_ok")), TRUE);
15065 	}
15066 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_button_ok")), FALSE);
15067 	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_name")));
15068 
15069 run_unit_edit_dialog:
15070 	gint response = gtk_dialog_run(GTK_DIALOG(dialog));
15071 	if(response == GTK_RESPONSE_OK) {
15072 		//clicked "OK"
15073 		string str;
15074 		str = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_name")));
15075 		remove_blank_ends(str);
15076 		GtkTreeIter iter;
15077 		if(str.empty() && (!names_edited || !gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tNames_store), &iter))) {
15078 			//no name given
15079 			gtk_notebook_set_current_page(GTK_NOTEBOOK(gtk_builder_get_object(unitedit_builder, "unit_edit_tabs")), 0);
15080 			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_name")));
15081 			show_message(_("Empty name field."), dialog);
15082 			goto run_unit_edit_dialog;
15083 		}
15084 
15085 		//unit with the same name exists -- overwrite or open the dialog again
15086 		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)) {
15087 			gtk_notebook_set_current_page(GTK_NOTEBOOK(gtk_builder_get_object(unitedit_builder, "unit_edit_tabs")), 0);
15088 			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_name")));
15089 			goto run_unit_edit_dialog;
15090 		}
15091 		bool add_unit = false;
15092 		if(u) {
15093 			//edited an existing unit -- update unit
15094 			u->setLocal(true);
15095 			gint i1 = gtk_combo_box_get_active(GTK_COMBO_BOX(gtk_builder_get_object(unitedit_builder, "unit_edit_combobox_class")));
15096 			switch(u->subtype()) {
15097 				case SUBTYPE_ALIAS_UNIT: {
15098 					if(i1 != UNIT_CLASS_ALIAS_UNIT) {
15099 						u->destroy();
15100 						u = NULL;
15101 						break;
15102 					}
15103 					if(!u->isBuiltin()) {
15104 						AliasUnit *au = (AliasUnit*) u;
15105 						Unit *bu = CALCULATOR->getUnit(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_base"))));
15106 						if(!bu) bu = CALCULATOR->getCompositeUnit(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_base"))));
15107 						if(!bu) {
15108 							gtk_notebook_set_current_page(GTK_NOTEBOOK(gtk_builder_get_object(unitedit_builder, "unit_edit_tabs")), 1);
15109 							gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_base")));
15110 							show_message(_("Base unit does not exist."), dialog);
15111 							goto run_unit_edit_dialog;
15112 						}
15113 						au->setBaseUnit(bu);
15114 						ParseOptions pa = evalops.parse_options; pa.base = 10;
15115 						au->setExpression(CALCULATOR->unlocalizeExpression(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_relation"))), pa));
15116 						au->setInverseExpression(au->hasNonlinearExpression() ? CALCULATOR->unlocalizeExpression(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_reversed"))), pa) : "");
15117 						au->setExponent(gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_spinbutton_exp"))));
15118 						au->setApproximate(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_checkbutton_exact"))));
15119 						if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_checkbutton_mix")))) {
15120 							au->setMixWithBase(gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_spinbutton_mix_priority"))));
15121 							au->setMixWithBaseMinimum(gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_spinbutton_mix_min"))));
15122 						} else {
15123 							au->setMixWithBase(0);
15124 						}
15125 					}
15126 					break;
15127 				}
15128 				case SUBTYPE_COMPOSITE_UNIT: {
15129 					if(i1 != UNIT_CLASS_COMPOSITE_UNIT) {
15130 						u->destroy();
15131 						u = NULL;
15132 						break;
15133 					}
15134 					if(!u->isBuiltin()) {
15135 						((CompositeUnit*) u)->setBaseExpression(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_base"))));
15136 					}
15137 					break;
15138 				}
15139 				case SUBTYPE_BASE_UNIT: {
15140 					if(i1 != UNIT_CLASS_BASE_UNIT) {
15141 						u->destroy();
15142 						u = NULL;
15143 						break;
15144 					}
15145 					break;
15146 				}
15147 			}
15148 			if(u) {
15149 				u->setTitle(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_desc"))));
15150 				u->setCategory(gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(gtk_builder_get_object(unitedit_builder, "unit_edit_combo_category"))));
15151 			}
15152 		}
15153 		if(!u) {
15154 			//new unit
15155 			switch(gtk_combo_box_get_active(GTK_COMBO_BOX(gtk_builder_get_object(unitedit_builder, "unit_edit_combobox_class")))) {
15156 				case UNIT_CLASS_ALIAS_UNIT: {
15157 					Unit *bu = CALCULATOR->getUnit(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_base"))));
15158 					if(!bu) bu = CALCULATOR->getCompositeUnit(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_base"))));
15159 					if(!bu) {
15160 						gtk_notebook_set_current_page(GTK_NOTEBOOK(gtk_builder_get_object(unitedit_builder, "unit_edit_tabs")), 1);
15161 						gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_entry_base")));
15162 						show_message(_("Base unit does not exist."), dialog);
15163 						goto run_unit_edit_dialog;
15164 					}
15165 					ParseOptions pa = evalops.parse_options; pa.base = 10;
15166 					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"))), pa), 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"))), pa), true);
15167 					((AliasUnit*) u)->setApproximate(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_checkbutton_exact"))));
15168 					if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_checkbutton_mix")))) {
15169 						((AliasUnit*) u)->setMixWithBase(gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_spinbutton_mix_priority"))));
15170 						((AliasUnit*) u)->setMixWithBaseMinimum(gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_spinbutton_mix_min"))));
15171 					}
15172 					break;
15173 				}
15174 				case UNIT_CLASS_COMPOSITE_UNIT: {
15175 					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);
15176 					u = cu;
15177 					break;
15178 				}
15179 				default: {
15180 					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);
15181 					break;
15182 				}
15183 			}
15184 			add_unit = true;
15185 		}
15186 		if(u) {
15187 			u->setHidden(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_checkbutton_hidden"))));
15188 			GtkTextIter d_iter_s, d_iter_e;
15189 			gtk_text_buffer_get_start_iter(description_buffer, &d_iter_s);
15190 			gtk_text_buffer_get_end_iter(description_buffer, &d_iter_e);
15191 			gchar *gstr_descr = gtk_text_buffer_get_text(description_buffer, &d_iter_s, &d_iter_e, FALSE);
15192 			u->setDescription(gstr_descr);
15193 			g_free(gstr_descr);
15194 			if(!u->isBuiltin()) {
15195 				u->setSystem(gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(gtk_builder_get_object(unitedit_builder, "unit_edit_combo_system"))));
15196 			}
15197 			if(u->subtype() != SUBTYPE_COMPOSITE_UNIT) {
15198 				u->setUseWithPrefixesByDefault(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_checkbutton_use_prefixes"))));
15199 			}
15200 			set_edited_names(u, str);
15201 			if(add_unit) {
15202 				CALCULATOR->addUnit(u);
15203 			}
15204 			//select the new unit
15205 			selected_unit = u;
15206 			if(!u->isActive()) {
15207 				selected_unit_category = _("Inactive");
15208 			} else if(u->category().empty()) {
15209 				selected_unit_category = _("Uncategorized");
15210 			} else {
15211 				selected_unit_category = "/";
15212 				selected_unit_category += u->category();
15213 			}
15214 		}
15215 		update_umenus();
15216 		unit_inserted(u);
15217 	} else if(response == GTK_RESPONSE_HELP) {
15218 		show_help("qalculate-units.html#qalculate-unit-creation", gtk_builder_get_object(unitedit_builder, "unit_edit_dialog"));
15219 		goto run_unit_edit_dialog;
15220 	}
15221 	edited_unit = NULL;
15222 	names_edited = false;
15223 	editing_unit = false;
15224 	gtk_widget_hide(dialog);
15225 }
15226 
edit_argument(Argument * arg)15227 bool edit_argument(Argument *arg) {
15228 	if(!arg) {
15229 		arg = new Argument();
15230 	}
15231 	edited_argument = arg;
15232 	GtkWidget *dialog = get_argument_rules_dialog();
15233 	gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gtk_builder_get_object(functionedit_builder, "function_edit_dialog")));
15234 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_enable_test")), arg->tests());
15235 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_allow_matrix")), arg->matrixAllowed());
15236 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_allow_matrix")), TRUE);
15237 	ParseOptions pa = evalops.parse_options; pa.base = 10;
15238 	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(argumentrules_builder, "argument_rules_entry_condition")), CALCULATOR->localizeExpression(arg->getCustomCondition(), pa).c_str());
15239 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_enable_condition")), !arg->getCustomCondition().empty());
15240 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(argumentrules_builder, "argument_rules_entry_condition")), !arg->getCustomCondition().empty());
15241 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_forbid_zero")), arg->zeroForbidden());
15242 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_handle_vector")), arg->handlesVector());
15243 	switch(arg->type()) {
15244 		case ARGUMENT_TYPE_NUMBER: {
15245 			NumberArgument *farg = (NumberArgument*) arg;
15246 			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(argumentrules_builder, "argument_rules_box_min")), TRUE);
15247 			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_enable_min")), farg->min() != NULL);
15248 			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_min_include_equals")), farg->includeEqualsMin());
15249 			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(argumentrules_builder, "argument_rules_spinbutton_min")), farg->min() != NULL);
15250 			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_min_include_equals")), TRUE);
15251 			gtk_spin_button_set_digits(GTK_SPIN_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_spinbutton_min")), 8);
15252 			gtk_adjustment_set_lower(GTK_ADJUSTMENT(gtk_builder_get_object(argumentrules_builder, "adjustment_min")), INT_MIN);
15253 			gtk_adjustment_set_upper(GTK_ADJUSTMENT(gtk_builder_get_object(argumentrules_builder, "adjustment_min")), INT_MAX);
15254 			if(farg->min()) {
15255 				gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_spinbutton_max")), farg->min()->floatValue());
15256 			} else {
15257 				gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_spinbutton_min")), 0);
15258 			}
15259 			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(argumentrules_builder, "argument_rules_box_max")), TRUE);
15260 			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_enable_max")), farg->max() != NULL);
15261 			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_max_include_equals")), farg->includeEqualsMax());
15262 			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(argumentrules_builder, "argument_rules_spinbutton_max")), farg->max() != NULL);
15263 			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_max_include_equals")), TRUE);
15264 			gtk_spin_button_set_digits(GTK_SPIN_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_spinbutton_max")), 8);
15265 			gtk_adjustment_set_lower(GTK_ADJUSTMENT(gtk_builder_get_object(argumentrules_builder, "adjustment_max")), INT_MIN);
15266 			gtk_adjustment_set_upper(GTK_ADJUSTMENT(gtk_builder_get_object(argumentrules_builder, "adjustment_max")), INT_MAX);
15267 			if(farg->max()) {
15268 				gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_spinbutton_max")), farg->max()->floatValue());
15269 			} else {
15270 				gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_spinbutton_max")), 0);
15271 			}
15272 			break;
15273 		}
15274 		case ARGUMENT_TYPE_INTEGER: {
15275 			IntegerArgument *iarg = (IntegerArgument*) arg;
15276 			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(argumentrules_builder, "argument_rules_box_min")), TRUE);
15277 			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_enable_min")), iarg->min() != NULL);
15278 			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_min_include_equals")), TRUE);
15279 			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(argumentrules_builder, "argument_rules_spinbutton_min")), iarg->min() != NULL);
15280 			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_min_include_equals")), FALSE);
15281 			gtk_spin_button_set_digits(GTK_SPIN_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_spinbutton_min")), 0);
15282 			gtk_adjustment_set_lower(GTK_ADJUSTMENT(gtk_builder_get_object(argumentrules_builder, "adjustment_min")), INT_MIN);
15283 			gtk_adjustment_set_upper(GTK_ADJUSTMENT(gtk_builder_get_object(argumentrules_builder, "adjustment_min")), INT_MAX);
15284 			if(iarg->min()) {
15285 				gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_spinbutton_min")), iarg->min()->intValue());
15286 			} else {
15287 				gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_spinbutton_min")), 0);
15288 			}
15289 			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(argumentrules_builder, "argument_rules_box_max")), TRUE);
15290 			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_enable_max")), iarg->max() != NULL);
15291 			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_max_include_equals")), TRUE);
15292 			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(argumentrules_builder, "argument_rules_spinbutton_max")), iarg->max() != NULL);
15293 			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_max_include_equals")), FALSE);
15294 			gtk_spin_button_set_digits(GTK_SPIN_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_spinbutton_max")), 0);
15295 			gtk_adjustment_set_lower(GTK_ADJUSTMENT(gtk_builder_get_object(argumentrules_builder, "adjustment_max")), INT_MIN);
15296 			gtk_adjustment_set_upper(GTK_ADJUSTMENT(gtk_builder_get_object(argumentrules_builder, "adjustment_max")), INT_MAX);
15297 			if(iarg->max()) {
15298 				gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_spinbutton_max")), iarg->max()->intValue());
15299 			} else {
15300 				gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_spinbutton_max")), 0);
15301 			}
15302 			break;
15303 		}
15304 		case ARGUMENT_TYPE_FREE: {}
15305 		case ARGUMENT_TYPE_MATRIX: {
15306 			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_allow_matrix")), TRUE);
15307 			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_allow_matrix")), FALSE);
15308 		}
15309 		default: {
15310 			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_enable_min")), FALSE);
15311 			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_enable_max")), FALSE);
15312 			gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_spinbutton_min")), 0);
15313 			gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_spinbutton_max")), 0);
15314 			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(argumentrules_builder, "argument_rules_box_min")), FALSE);
15315 			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(argumentrules_builder, "argument_rules_box_max")), FALSE);
15316 		}
15317 	}
15318 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(argumentrules_builder, "argument_rules_button_ok")), FALSE);
15319 	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_enable_test")));
15320 	if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) {
15321 		arg->setTests(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_enable_test"))));
15322 		arg->setMatrixAllowed(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_allow_matrix"))));
15323 		arg->setZeroForbidden(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_forbid_zero"))));
15324 		arg->setHandleVector(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_handle_vector"))));
15325 		if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_enable_condition")))) {
15326 			arg->setCustomCondition(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(argumentrules_builder, "argument_rules_entry_condition"))));
15327 		} else {
15328 			arg->setCustomCondition("");
15329 		}
15330 		if(arg->type() == ARGUMENT_TYPE_NUMBER) {
15331 			NumberArgument *farg = (NumberArgument*) arg;
15332 			farg->setIncludeEqualsMin(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_min_include_equals"))));
15333 			farg->setIncludeEqualsMax(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_max_include_equals"))));
15334 			if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_enable_min")))) {
15335 				Number nr;
15336 				nr.setFloat(gtk_spin_button_get_value(GTK_SPIN_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_spinbutton_min"))));
15337 				farg->setMin(&nr);
15338 			} else {
15339 				farg->setMin(NULL);
15340 			}
15341 			if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_enable_max")))) {
15342 				Number nr;
15343 				nr.setFloat(gtk_spin_button_get_value(GTK_SPIN_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_spinbutton_max"))));
15344 				farg->setMax(&nr);
15345 			} else {
15346 				farg->setMax(NULL);
15347 			}
15348 		} else if(arg->type() == ARGUMENT_TYPE_INTEGER) {
15349 			IntegerArgument *iarg = (IntegerArgument*) arg;
15350 			if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_enable_min")))) {
15351 				Number integ(gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_spinbutton_min"))), 1);
15352 				iarg->setMin(&integ);
15353 			} else {
15354 				iarg->setMin(NULL);
15355 			}
15356 			if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_checkbutton_enable_max")))) {
15357 				Number integ(gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_builder_get_object(argumentrules_builder, "argument_rules_spinbutton_max"))), 1);
15358 				iarg->setMax(&integ);
15359 			} else {
15360 				iarg->setMax(NULL);
15361 			}
15362 		}
15363 		GtkTreeModel *model;
15364 		GtkTreeIter iter;
15365 		GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tFunctionArguments));
15366 		if(gtk_tree_selection_get_selected(select, &model, &iter)) {
15367 			gtk_list_store_set(tFunctionArguments_store, &iter, 0, arg->name().c_str(), 1, arg->printlong().c_str(), 2, (gpointer) arg, -1);
15368 		}
15369 		edited_argument = NULL;
15370 		gtk_widget_hide(dialog);
15371 		return true;
15372 	}
15373 	edited_argument = NULL;
15374 	gtk_widget_hide(dialog);
15375 	return false;
15376 }
15377 
15378 
delete_function(MathFunction * f)15379 void delete_function(MathFunction *f) {
15380 	if(f && f->isLocal()) {
15381 		for(size_t i = 0; i < recent_functions.size(); i++) {
15382 			if(recent_functions[i] == f) {
15383 				recent_functions.erase(recent_functions.begin() + i);
15384 				gtk_widget_destroy(recent_function_items[i]);
15385 				recent_function_items.erase(recent_function_items.begin() + i);
15386 				break;
15387 			}
15388 		}
15389 		//ensure removal of all references in Calculator
15390 		f->destroy();
15391 		//update menus and trees
15392 		update_fmenu();
15393 	}
15394 }
15395 
15396 /*
15397 	display edit/new function dialog
15398 	creates new function if f == NULL, win is parent window
15399 */
edit_function(const char * category="",MathFunction * f=NULL,GtkWidget * win=NULL,const char * name=NULL,const char * expression=NULL,bool enable_ok=true)15400 void edit_function(const char *category = "", MathFunction *f = NULL, GtkWidget *win = NULL, const char *name = NULL, const char *expression = NULL, bool enable_ok = true) {
15401 
15402 	if(f && f->subtype() == SUBTYPE_DATA_SET) {
15403 		edit_dataset((DataSet*) f, win);
15404 		return;
15405 	}
15406 
15407 	GtkWidget *dialog = get_function_edit_dialog();
15408 	if(win) gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(win));
15409 
15410 	edited_function = f;
15411 	names_edited = false;
15412 	editing_function = true;
15413 
15414 	if(f) {
15415 		if(f->isLocal())
15416 			gtk_window_set_title(GTK_WINDOW(dialog), _("Edit Function"));
15417 		else
15418 			gtk_window_set_title(GTK_WINDOW(dialog), _("Edit Function (global)"));
15419 	} else {
15420 		gtk_window_set_title(GTK_WINDOW(dialog), _("New Function"));
15421 	}
15422 
15423 	GtkTextBuffer *description_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtk_builder_get_object(functionedit_builder, "function_edit_textview_description")));
15424 	GtkTextBuffer *expression_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtk_builder_get_object(functionedit_builder, "function_edit_textview_expression")));
15425 
15426 	//clear entries
15427 	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(functionedit_builder, "function_edit_entry_name")), "");
15428 	gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(functionedit_builder, "function_edit_label_names")), "");
15429 	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(functionedit_builder, "function_edit_entry_condition")), "");
15430 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_entry_condition")), !f || !f->isBuiltin());
15431 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_entry_name")), !f || !f->isBuiltin());
15432 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_textview_expression")), !f || !f->isBuiltin());
15433 	gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(functionedit_builder, "function_edit_combo_category")))), category);
15434 	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(functionedit_builder, "function_edit_entry_desc")), "");
15435 	gtk_text_buffer_set_text(description_buffer, "", -1);
15436 	gtk_text_buffer_set_text(expression_buffer, "", -1);
15437 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(functionedit_builder, "function_edit_checkbutton_hidden")), false);
15438 	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(functionedit_builder, "function_edit_entry_argument_name")), "");
15439 
15440 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_combobox_argument_type")), !f || !f->isBuiltin());
15441 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_button_add_argument")), !f || !f->isBuiltin());
15442 
15443 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_button_subfunctions")), !f || !f->isBuiltin());
15444 	gtk_list_store_clear(tSubfunctions_store);
15445 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_button_modify_subfunction")), FALSE);
15446 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_button_remove_subfunction")), FALSE);
15447 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_button_add_subfunction")), !f || !f->isBuiltin());
15448 	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(functionedit_builder, "function_edit_entry_subexpression")), "");
15449 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(functionedit_builder, "function_edit_checkbutton_precalculate")), TRUE);
15450 	selected_subfunction = 0;
15451 	last_subfunction_index = 0;
15452 	if(f) {
15453 		//fill in original paramaters
15454 		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")));
15455 		ParseOptions pa = evalops.parse_options; pa.base = 10;
15456 		if(!f->isBuiltin()) {
15457 			gtk_text_buffer_set_text(expression_buffer, CALCULATOR->localizeExpression(((UserFunction*) f)->formula(), pa).c_str(), -1);
15458 		}
15459 		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());
15460 		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(functionedit_builder, "function_edit_entry_desc")), f->title(false).c_str());
15461 		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(functionedit_builder, "function_edit_entry_condition")), CALCULATOR->localizeExpression(f->condition(), pa).c_str());
15462 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(functionedit_builder, "function_edit_checkbutton_hidden")), f->isHidden());
15463 		gtk_text_buffer_set_text(description_buffer, f->description().c_str(), -1);
15464 
15465 		if(!f->isBuiltin()) {
15466 			GtkTreeIter iter;
15467 			string str, str2;
15468 			for(size_t i = 1; i <= ((UserFunction*) f)->countSubfunctions(); i++) {
15469 				gtk_list_store_append(tSubfunctions_store, &iter);
15470 				if(((UserFunction*) f)->subfunctionPrecalculated(i)) {
15471 					str = _("Yes");
15472 				} else {
15473 					str = _("No");
15474 				}
15475 				str2 = "\\";
15476 				str2 += i2s(i);
15477 				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);
15478 				last_subfunction_index = i;
15479 			}
15480 		}
15481 	}
15482 	if(name) gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(functionedit_builder, "function_edit_entry_name")), name);
15483 	if(expression) gtk_text_buffer_set_text(expression_buffer, expression, -1);
15484 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_button_ok")), enable_ok && (name || expression));
15485 	update_function_arguments_list(f);
15486 	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_entry_name")));
15487 	gtk_notebook_set_current_page(GTK_NOTEBOOK(gtk_builder_get_object(functionedit_builder, "function_edit_tabs")), 0);
15488 
15489 run_function_edit_dialog:
15490 	gint response = gtk_dialog_run(GTK_DIALOG(dialog));
15491 	if(response == GTK_RESPONSE_OK) {
15492 		//clicked "OK"
15493 		string str = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(functionedit_builder, "function_edit_entry_name")));
15494 		remove_blank_ends(str);
15495 		GtkTreeIter iter;
15496 		if(str.empty() && (!names_edited || !gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tNames_store), &iter))) {
15497 			//no name -- open dialog again
15498 			gtk_notebook_set_current_page(GTK_NOTEBOOK(gtk_builder_get_object(functionedit_builder, "function_edit_tabs")), 0);
15499 			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_entry_name")));
15500 			show_message(_("Empty name field."), dialog);
15501 			goto run_function_edit_dialog;
15502 		}
15503 		GtkTextIter e_iter_s, e_iter_e;
15504 		gtk_text_buffer_get_start_iter(expression_buffer, &e_iter_s);
15505 		gtk_text_buffer_get_end_iter(expression_buffer, &e_iter_e);
15506 		gchar *gstr = gtk_text_buffer_get_text(expression_buffer, &e_iter_s, &e_iter_e, FALSE);
15507 		ParseOptions pa = evalops.parse_options; pa.base = 10;
15508 		string str2 = CALCULATOR->unlocalizeExpression(gstr, pa);
15509 		g_free(gstr);
15510 		remove_blank_ends(str2);
15511 		gsub("\n", " ", str2);
15512 		if(!(f && f->isBuiltin()) && str2.empty()) {
15513 			//no expression/relation -- open dialog again
15514 			gtk_notebook_set_current_page(GTK_NOTEBOOK(gtk_builder_get_object(functionedit_builder, "function_edit_tabs")), 1);
15515 			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_textview_expression")));
15516 			show_message(_("Empty expression field."), dialog);
15517 			goto run_function_edit_dialog;
15518 		}
15519 		GtkTextIter d_iter_s, d_iter_e;
15520 		gtk_text_buffer_get_start_iter(description_buffer, &d_iter_s);
15521 		gtk_text_buffer_get_end_iter(description_buffer, &d_iter_e);
15522 		gchar *gstr_descr = gtk_text_buffer_get_text(description_buffer, &d_iter_s, &d_iter_e, FALSE);
15523 		//function with the same name exists -- overwrite or open the dialog again
15524 		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)) {
15525 			gtk_notebook_set_current_page(GTK_NOTEBOOK(gtk_builder_get_object(functionedit_builder, "function_edit_tabs")), 0);
15526 			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_entry_name")));
15527 			goto run_function_edit_dialog;
15528 		}
15529 		bool add_func = false;
15530 		if(f) {
15531 			f->setLocal(true);
15532 			//edited an existing function
15533 			f->setCategory(gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(gtk_builder_get_object(functionedit_builder, "function_edit_combo_category"))));
15534 			f->setTitle(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(functionedit_builder, "function_edit_entry_desc"))));
15535 			f->setDescription(gstr_descr);
15536 			if(!f->isBuiltin()) {
15537 				f->clearArgumentDefinitions();
15538 			}
15539 		} else {
15540 			//new function
15541 			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);
15542 			add_func = true;
15543 		}
15544 		g_free(gstr_descr);
15545 		if(f) {
15546 			f->setCondition(CALCULATOR->unlocalizeExpression(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(functionedit_builder, "function_edit_entry_condition"))), pa));
15547 			GtkTreeIter iter;
15548 			bool b = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tFunctionArguments_store), &iter);
15549 			int i = 1;
15550 			Argument *arg;
15551 			while(b) {
15552 				gtk_tree_model_get(GTK_TREE_MODEL(tFunctionArguments_store), &iter, 2, &arg, -1);
15553 				if(arg && f->isBuiltin() && f->getArgumentDefinition(i)) {
15554 					f->getArgumentDefinition(i)->setName(arg->name());
15555 					delete arg;
15556 				} else if(arg) {
15557 					f->setArgumentDefinition(i, arg);
15558 				}
15559 				b = gtk_tree_model_iter_next(GTK_TREE_MODEL(tFunctionArguments_store), &iter);
15560 				i++;
15561 			}
15562 			if(!f->isBuiltin()) {
15563 				((UserFunction*) f)->clearSubfunctions();
15564 				b = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tSubfunctions_store), &iter);
15565 				while(b) {
15566 					gchar *gstr;
15567 					gboolean g_b = FALSE;
15568 					gtk_tree_model_get(GTK_TREE_MODEL(tSubfunctions_store), &iter, 1, &gstr, 4, &g_b, -1);
15569 					((UserFunction*) f)->addSubfunction(gstr, g_b);
15570 					b = gtk_tree_model_iter_next(GTK_TREE_MODEL(tSubfunctions_store), &iter);
15571 					g_free(gstr);
15572 				}
15573 				((UserFunction*) f)->setFormula(str2);
15574 			}
15575 			f->setHidden(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(functionedit_builder, "function_edit_checkbutton_hidden"))));
15576 			set_edited_names(f, str);
15577 			if(add_func) {
15578 				CALCULATOR->addFunction(f);
15579 			}
15580 			if(!f->isActive()) {
15581 				selected_function_category = _("Inactive");
15582 			} else if(f->category().empty()) {
15583 				selected_function_category = _("Uncategorized");
15584 			} else {
15585 				selected_function_category = "/";
15586 				selected_function_category += f->category();
15587 			}
15588 			//select the new function
15589 			selected_function = f;
15590 		}
15591 		update_fmenu();
15592 		function_inserted(f);
15593 	} else if(response == GTK_RESPONSE_HELP) {
15594 		show_help("qalculate-functions.html#qalculate-function-creation", gtk_builder_get_object(functionedit_builder, "function_edit_dialog"));
15595 		goto run_function_edit_dialog;
15596 	}
15597 	edited_function = NULL;
15598 	names_edited = false;
15599 	editing_function = false;
15600 	gtk_widget_hide(dialog);
15601 }
15602 
15603 /*
15604 	display edit/new function dialog
15605 	creates new function if f == NULL, win is parent window
15606 */
edit_function_simple(const char * category="",MathFunction * f=NULL,GtkWidget * win=NULL)15607 void edit_function_simple(const char *category = "", MathFunction *f = NULL, GtkWidget *win = NULL) {
15608 
15609 	if(f && f->subtype() == SUBTYPE_DATA_SET) {
15610 		edit_dataset((DataSet*) f, win);
15611 		return;
15612 	}
15613 
15614 	GtkWidget *dialog = get_simple_function_edit_dialog();
15615 	if(win) gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(win));
15616 
15617 	edited_function = f;
15618 	editing_function = true;
15619 
15620 	if(f) {
15621 		if(f->isLocal() && f->subtype() == SUBTYPE_USER_FUNCTION) gtk_window_set_title(GTK_WINDOW(dialog), _("Edit Function"));
15622 		else return edit_function(category, f, win);
15623 		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);
15624 	} else {
15625 		gtk_window_set_title(GTK_WINDOW(dialog), _("New Function"));
15626 	}
15627 
15628 	GtkTextBuffer *expression_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtk_builder_get_object(simplefunctionedit_builder, "simple_function_edit_textview_expression")));
15629 
15630 	//clear entries
15631 	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(simplefunctionedit_builder, "simple_function_edit_entry_name")), "");
15632 	gtk_text_buffer_set_text(expression_buffer, "", -1);
15633 
15634 	if(f) {
15635 		//fill in original paramaters
15636 		ParseOptions pa = evalops.parse_options; pa.base = 10;
15637 		gtk_text_buffer_set_text(expression_buffer, CALCULATOR->localizeExpression(((UserFunction*) f)->formula(), pa).c_str(), -1);
15638 		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(simplefunctionedit_builder, "simple_function_edit_entry_name")), f->getName(1).name.c_str());
15639 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(simplefunctionedit_builder, "simple_function_edit_radiobutton_slash")), TRUE);
15640 	} else {
15641 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(simplefunctionedit_builder, "simple_function_edit_radiobutton_noslash")), TRUE);
15642 	}
15643 
15644 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(simplefunctionedit_builder, "simple_function_edit_button_ok")), FALSE);
15645 
15646 	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(simplefunctionedit_builder, "simple_function_edit_entry_name")));
15647 
15648 run_simple_function_edit_dialog:
15649 	gint response = gtk_dialog_run(GTK_DIALOG(dialog));
15650 	if(response == GTK_RESPONSE_OK) {
15651 		//clicked "OK"
15652 		string str = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(simplefunctionedit_builder, "simple_function_edit_entry_name")));
15653 		remove_blank_ends(str);
15654 		if(str.empty()) {
15655 			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(simplefunctionedit_builder, "simple_function_edit_entry_name")));
15656 			show_message(_("Empty name field."), dialog);
15657 			goto run_simple_function_edit_dialog;
15658 		}
15659 		GtkTextIter e_iter_s, e_iter_e;
15660 		gtk_text_buffer_get_start_iter(expression_buffer, &e_iter_s);
15661 		gtk_text_buffer_get_end_iter(expression_buffer, &e_iter_e);;
15662 		gchar *gstr = gtk_text_buffer_get_text(expression_buffer, &e_iter_s, &e_iter_e, FALSE);
15663 		ParseOptions pa = evalops.parse_options; pa.base = 10;
15664 		string str2 = CALCULATOR->unlocalizeExpression(gstr, pa);
15665 		g_free(gstr);
15666 		remove_blank_ends(str2);
15667 		gsub("\n", " ", str2);
15668 		if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(simplefunctionedit_builder, "simple_function_edit_radiobutton_noslash")))) {
15669 			gsub("x", "\\x", str2);
15670 			gsub("y", "\\y", str2);
15671 			gsub("z", "\\z", str2);
15672 		}
15673 		if(str2.empty()) {
15674 			//no expression/relation -- open dialog again
15675 			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(simplefunctionedit_builder, "simple_function_edit_textview_expression")));
15676 			show_message(_("Empty expression field."), dialog);
15677 			goto run_simple_function_edit_dialog;
15678 		}
15679 		//function with the same name exists -- overwrite or open the dialog again
15680 		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)) {
15681 			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(simplefunctionedit_builder, "simple_function_edit_entry_name")));
15682 			goto run_simple_function_edit_dialog;
15683 		}
15684 		if(f) {
15685 			//edited an existing function
15686 			f->setLocal(true);
15687 			((UserFunction*) f)->setFormula(str2);
15688 			f->setName(str, 1);
15689 		} else {
15690 			//new function
15691 			f = new UserFunction(category, str, str2);
15692 			CALCULATOR->addFunction(f);
15693 		}
15694 		update_fmenu();
15695 		function_inserted(f);
15696 	}
15697 	edited_function = NULL;
15698 	names_edited = false;
15699 	editing_function = false;
15700 	gtk_widget_hide(dialog);
15701 	if(response == 1) {
15702 		GtkTextIter e_iter_s, e_iter_e;
15703 		gtk_text_buffer_get_start_iter(expression_buffer, &e_iter_s);
15704 		gtk_text_buffer_get_end_iter(expression_buffer, &e_iter_e);;
15705 		gchar *gstr = gtk_text_buffer_get_text(expression_buffer, &e_iter_s, &e_iter_e, FALSE);
15706 		string str2 = gstr;
15707 		g_free(gstr);
15708 		if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(simplefunctionedit_builder, "simple_function_edit_radiobutton_noslash")))) {
15709 			gsub("x", "\\x", str2);
15710 			gsub("y", "\\y", str2);
15711 			gsub("z", "\\z", str2);
15712 		}
15713 		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"))));
15714 	}
15715 }
15716 
15717 /*
15718 	"New function" menu item selected
15719 */
new_function(GtkMenuItem *,gpointer)15720 void new_function(GtkMenuItem*, gpointer)
15721 {
15722 	edit_function("", NULL, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")));
15723 }
15724 /*
15725 	"New unit" menu item selected
15726 */
new_unit(GtkMenuItem *,gpointer)15727 void new_unit(GtkMenuItem*, gpointer)
15728 {
15729 	edit_unit("", NULL, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")));
15730 }
15731 
15732 /*
15733 	a unit selected in result menu, convert result
15734 */
convert_to_unit(GtkMenuItem *,gpointer user_data)15735 void convert_to_unit(GtkMenuItem*, gpointer user_data)
15736 {
15737 	GtkWidget *edialog;
15738 	Unit *u = (Unit*) user_data;
15739 	if(!u) {
15740 		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"));
15741 		gtk_dialog_run(GTK_DIALOG(edialog));
15742 		gtk_widget_destroy(edialog);
15743 	}
15744 	//result is stored in MathStructure *mstruct
15745 	executeCommand(COMMAND_CONVERT_UNIT, true, "", u);
15746 	focus_keeping_selection();
15747 }
15748 
convert_to_unit_noprefix(GtkMenuItem *,gpointer user_data)15749 void convert_to_unit_noprefix(GtkMenuItem*, gpointer user_data)
15750 {
15751 	GtkWidget *edialog;
15752 	Unit *u = (Unit*) user_data;
15753 	if(!u) {
15754 		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"));
15755 		gtk_dialog_run(GTK_DIALOG(edialog));
15756 		gtk_widget_destroy(edialog);
15757 	}
15758 	string ceu_str = u->name();
15759 	//result is stored in MathStructure *mstruct
15760 	executeCommand(COMMAND_CONVERT_STRING, true, ceu_str);
15761 	focus_keeping_selection();
15762 }
15763 
edit_unknown(const char * category,Variable * var,GtkWidget * win)15764 void edit_unknown(const char *category, Variable *var, GtkWidget *win) {
15765 
15766 	if(var != NULL && var->isKnown()) {
15767 		edit_variable(category, var, NULL, win);
15768 		return;
15769 	}
15770 
15771 	UnknownVariable *v = (UnknownVariable*) var;
15772 	edited_unknown = v;
15773 	names_edited = false;
15774 	editing_unknown = true;
15775 
15776 	GtkWidget *dialog = get_unknown_edit_dialog();
15777 	if(win) gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(win));
15778 
15779 	if(v) {
15780 		if(v->isLocal())
15781 			gtk_window_set_title(GTK_WINDOW(dialog), _("Edit Unknown Variable"));
15782 		else
15783 			gtk_window_set_title(GTK_WINDOW(dialog), _("Edit Unknown Variable (global)"));
15784 	} else {
15785 		gtk_window_set_title(GTK_WINDOW(dialog), _("New Unknown Variable"));
15786 	}
15787 
15788 	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);
15789 	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);
15790 	if(v) {
15791 		//fill in original parameters
15792 		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")));
15793 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unknownedit_builder, "unknown_edit_entry_name")), !v->isBuiltin());
15794 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unknownedit_builder, "unknown_edit_combobox_type")), !v->isBuiltin());
15795 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unknownedit_builder, "unknown_edit_combobox_sign")), !v->isBuiltin());
15796 		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());
15797 		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(unknownedit_builder, "unknown_edit_entry_desc")), v->title(false).c_str());
15798 		if(v->assumptions()) {
15799 			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(unknownedit_builder, "unknown_edit_checkbutton_custom_assumptions")), TRUE);
15800 			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unknownedit_builder, "unknown_edit_hbox_type")), TRUE);
15801 			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unknownedit_builder, "unknown_edit_hbox_sign")), TRUE);
15802 			gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(unknownedit_builder, "unknown_edit_combobox_type")), v->assumptions()->type() - 2);
15803 			gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(unknownedit_builder, "unknown_edit_combobox_sign")), v->assumptions()->sign());
15804 		} else {
15805 			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(unknownedit_builder, "unknown_edit_checkbutton_custom_assumptions")), FALSE);
15806 			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unknownedit_builder, "unknown_edit_hbox_type")), FALSE);
15807 			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unknownedit_builder, "unknown_edit_hbox_sign")), FALSE);
15808 			gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(unknownedit_builder, "unknown_edit_combobox_type")), CALCULATOR->defaultAssumptions()->type() - 2);
15809 			gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(unknownedit_builder, "unknown_edit_combobox_sign")), CALCULATOR->defaultAssumptions()->sign());
15810 		}
15811 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unknownedit_builder, "unknown_edit_button_ok")), FALSE);
15812 	} else {
15813 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unknownedit_builder, "unknown_edit_entry_name")), TRUE);
15814 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unknownedit_builder, "unknown_edit_combobox_type")), TRUE);
15815 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unknownedit_builder, "unknown_edit_combobox_sign")), TRUE);
15816 
15817 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(unknownedit_builder, "unknown_edit_checkbutton_custom_assumptions")), TRUE);
15818 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unknownedit_builder, "unknown_edit_hbox_type")), TRUE);
15819 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unknownedit_builder, "unknown_edit_hbox_sign")), TRUE);
15820 
15821 		//fill in default values
15822 		string v_name = CALCULATOR->getName();
15823 		int i = 1;
15824 		do {
15825 			v_name = "v"; v_name += i2s(i);
15826 			i++;
15827 		} while(CALCULATOR->nameTaken(v_name));
15828 		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(unknownedit_builder, "unknown_edit_entry_name")), v_name.c_str());
15829 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(unknownedit_builder, "unknown_edit_label_names")), "");
15830 		gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(unknownedit_builder, "unknown_edit_combo_category")))), category);
15831 		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(unknownedit_builder, "unknown_edit_entry_desc")), "");
15832 		gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(unknownedit_builder, "unknown_edit_combobox_type")), CALCULATOR->defaultAssumptions()->type() - 2);
15833 		gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(unknownedit_builder, "unknown_edit_combobox_sign")), CALCULATOR->defaultAssumptions()->sign());
15834 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unknownedit_builder, "unknown_edit_button_ok")), TRUE);
15835 	}
15836 	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);
15837 	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);
15838 
15839 	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(unknownedit_builder, "unknown_edit_entry_name")));
15840 
15841 run_unknown_edit_dialog:
15842 	gint response = gtk_dialog_run(GTK_DIALOG(dialog));
15843 	if(response == GTK_RESPONSE_OK) {
15844 		//clicked "OK"
15845 		string str = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(unknownedit_builder, "unknown_edit_entry_name")));
15846 		remove_blank_ends(str);
15847 		GtkTreeIter iter;
15848 		if(str.empty() && (!names_edited || !gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tNames_store), &iter))) {
15849 			//no name -- open dialog again
15850 			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(unknownedit_builder, "unknown_edit_entry_name")));
15851 			show_message(_("Empty name field."), dialog);
15852 			goto run_unknown_edit_dialog;
15853 		}
15854 
15855 		//unknown with the same name exists -- overwrite or open dialog again
15856 		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)) {
15857 			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(unknownedit_builder, "unknown_edit_entry_name")));
15858 			goto run_unknown_edit_dialog;
15859 		}
15860 		if(!v) {
15861 			//no need to create a new unknown when a unknown with the same name exists
15862 			var = CALCULATOR->getActiveVariable(str);
15863 			if(var && var->isLocal() && !var->isKnown()) v = (UnknownVariable*) var;
15864 		}
15865 		bool add_var = false;
15866 		if(v) {
15867 			//update existing unknown
15868 			v->setLocal(true);
15869 		} else {
15870 			//new unknown
15871 			v = new UnknownVariable("", "", "", true);
15872 			add_var = true;
15873 		}
15874 		if(v) {
15875 			if(!v->isBuiltin()) {
15876 				if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(unknownedit_builder, "unknown_edit_checkbutton_custom_assumptions")))) {
15877 					if(!v->assumptions()) v->setAssumptions(new Assumptions());
15878 					v->assumptions()->setType((AssumptionType) (gtk_combo_box_get_active(GTK_COMBO_BOX(gtk_builder_get_object(unknownedit_builder, "unknown_edit_combobox_type"))) + 2));
15879 					v->assumptions()->setSign((AssumptionSign) gtk_combo_box_get_active(GTK_COMBO_BOX(gtk_builder_get_object(unknownedit_builder, "unknown_edit_combobox_sign"))));
15880 				} else {
15881 					v->setAssumptions(NULL);
15882 				}
15883 			}
15884 			v->setCategory(gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(gtk_builder_get_object(unknownedit_builder, "unknown_edit_combo_category"))));
15885 			v->setTitle(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(unknownedit_builder, "unknown_edit_entry_desc"))));
15886 			set_edited_names(v, str);
15887 			if(add_var) {
15888 				CALCULATOR->addVariable(v);
15889 			}
15890 			//select the new unknown
15891 			selected_variable = v;
15892 			if(!v->isActive()) {
15893 				selected_variable_category = _("Inactive");
15894 			} else if(v->category().empty()) {
15895 				selected_variable_category = _("Uncategorized");
15896 			} else {
15897 				selected_variable_category = "/";
15898 				selected_variable_category += v->category();
15899 			}
15900 		}
15901 		update_vmenu();
15902 		variable_inserted(v);
15903 	} else if(response == GTK_RESPONSE_HELP) {
15904 		show_help("qalculate-variables.html#qalculate-variable-creation", gtk_builder_get_object(unknownedit_builder, "unknown_edit_dialog"));
15905 		goto run_unknown_edit_dialog;
15906 	}
15907 	edited_unknown = NULL;
15908 	names_edited = false;
15909 	editing_unknown = false;
15910 	gtk_widget_hide(dialog);
15911 }
15912 
delete_variable(Variable * v)15913 void delete_variable(Variable *v) {
15914 	if(v && !CALCULATOR->stillHasVariable(v)) {
15915 		show_message(_("Variable does not exist anymore."), GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_dialog")));
15916 		update_vmenu();
15917 		return;
15918 	}
15919 	if(v && v->isLocal()) {
15920 		for(size_t i = 0; i < recent_variables.size(); i++) {
15921 			if(recent_variables[i] == v) {
15922 				recent_variables.erase(recent_variables.begin() + i);
15923 				gtk_widget_destroy(recent_variable_items[i]);
15924 				recent_variable_items.erase(recent_variable_items.begin() + i);
15925 				break;
15926 			}
15927 		}
15928 		//ensure that all references are removed in Calculator
15929 		v->destroy();
15930 		update_vmenu();
15931 	}
15932 }
15933 
15934 
15935 /*
15936 	display edit/new variable dialog
15937 	creates new variable if v == NULL, mstruct_ is forced value, win is parent window
15938 */
edit_variable(const char * category,Variable * var,MathStructure * mstruct_,GtkWidget * win)15939 void edit_variable(const char *category, Variable *var, MathStructure *mstruct_, GtkWidget *win) {
15940 
15941 	if(var != NULL && !var->isKnown()) {
15942 		edit_unknown(category, var, win);
15943 		return;
15944 	}
15945 	KnownVariable *v = (KnownVariable*) var;
15946 
15947 	CALCULATOR->beginTemporaryStopMessages();
15948 	if(v != NULL && v->get().isVector() && (!mstruct_ || mstruct_->isVector()) && (v->get().size() != 1 || !v->get()[0].isVector() || v->get()[0].size() > 0)) {
15949 		CALCULATOR->endTemporaryStopMessages();
15950 		edit_matrix(category, v, mstruct_, win);
15951 		return;
15952 	}
15953 
15954 	edited_variable = v;
15955 	names_edited = false;
15956 	editing_variable = true;
15957 	GtkWidget *dialog = get_variable_edit_dialog();
15958 	if(win) gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(win));
15959 
15960 	if(v) {
15961 		if(v->isLocal())
15962 			gtk_window_set_title(GTK_WINDOW(dialog), _("Edit Variable"));
15963 		else
15964 			gtk_window_set_title(GTK_WINDOW(dialog), _("Edit Variable (global)"));
15965 	} else {
15966 		gtk_window_set_title(GTK_WINDOW(dialog), _("New Variable"));
15967 	}
15968 
15969 	gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(variableedit_builder, "variable_edit_label_names")), "");
15970 
15971 	gint w;
15972 	gtk_window_get_size(GTK_WINDOW(dialog), &w, NULL);
15973 	gtk_window_resize(GTK_WINDOW(dialog), w, 1);
15974 
15975 	if(mstruct_) {
15976 		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(variableedit_builder, "variable_edit_box_names")));
15977 		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(variableedit_builder, "variable_edit_entry_value")));
15978 		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(variableedit_builder, "variable_edit_label_value")));
15979 		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(variableedit_builder, "variable_edit_checkbutton_exact")));
15980 	} else {
15981 		gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(variableedit_builder, "variable_edit_box_names")));
15982 		gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(variableedit_builder, "variable_edit_entry_value")));
15983 		gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(variableedit_builder, "variable_edit_label_value")));
15984 		gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(variableedit_builder, "variable_edit_checkbutton_exact")));
15985 	}
15986 
15987 	if(v) {
15988 		//fill in original parameters
15989 		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")));
15990 		string value_str;
15991 		if(v->isExpression()) {
15992 			ParseOptions pa = evalops.parse_options; pa.base = 10;
15993 			value_str = CALCULATOR->localizeExpression(v->expression(), pa);
15994 			bool is_relative = false;
15995 			if(!v->uncertainty(&is_relative).empty()) {
15996 				if(is_relative) {
15997 					value_str.insert(0, "(");
15998 					value_str.insert(0, CALCULATOR->f_uncertainty->referenceName());
15999 					value_str += CALCULATOR->getComma();
16000 					value_str += " ";
16001 					value_str += v->uncertainty();
16002 					value_str += CALCULATOR->getComma();
16003 					value_str += " 1)";
16004 				} else {
16005 					value_str += SIGN_PLUSMINUS;
16006 					value_str += v->uncertainty();
16007 				}
16008 			}
16009 			if(!v->unit().empty() && v->unit() != "auto") {value_str += " "; value_str += v->unit();}
16010 		} else {
16011 			value_str = get_value_string(v->get(), false, NULL);
16012 		}
16013 		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(variableedit_builder, "variable_edit_entry_value")), value_str.c_str());
16014 		bool b_approx = *printops.is_approximate || v->isApproximate();
16015 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(variableedit_builder, "variable_edit_checkbutton_exact")), !b_approx);
16016 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(variableedit_builder, "variable_edit_entry_name")), !v->isBuiltin());
16017 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(variableedit_builder, "variable_edit_entry_value")), !v->isBuiltin());
16018 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(variableedit_builder, "variable_edit_checkbutton_exact")), !v->isBuiltin());
16019 		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());
16020 		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(variableedit_builder, "variable_edit_entry_desc")), v->title(false).c_str());
16021 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(variableedit_builder, "variable_edit_button_ok")), FALSE);
16022 	} else {
16023 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(variableedit_builder, "variable_edit_entry_name")), TRUE);
16024 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(variableedit_builder, "variable_edit_entry_value")), TRUE);
16025 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(variableedit_builder, "variable_edit_checkbutton_exact")), TRUE);
16026 
16027 		//fill in default values
16028 		string v_name;
16029 		int i = 1;
16030 		do {
16031 			v_name = "v"; v_name += i2s(i);
16032 			i++;
16033 		} while(CALCULATOR->nameTaken(v_name));
16034 		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(variableedit_builder, "variable_edit_entry_name")), v_name.c_str());
16035 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(variableedit_builder, "variable_edit_label_names")), "");
16036 		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());
16037 		gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(variableedit_builder, "variable_edit_combo_category")))), category);
16038 		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(variableedit_builder, "variable_edit_entry_desc")), "");
16039 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(variableedit_builder, "variable_edit_checkbutton_exact")), !mstruct_ || !mstruct_->isApproximate());
16040 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(variableedit_builder, "variable_edit_button_ok")), TRUE);
16041 	}
16042 
16043 	CALCULATOR->endTemporaryStopMessages();
16044 
16045 	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(variableedit_builder, "variable_edit_entry_name")));
16046 
16047 run_variable_edit_dialog:
16048 	gint response = gtk_dialog_run(GTK_DIALOG(dialog));
16049 	if(response == GTK_RESPONSE_OK) {
16050 		//clicked "OK"
16051 		string str = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(variableedit_builder, "variable_edit_entry_name")));
16052 		ParseOptions pa = evalops.parse_options; pa.base = 10;
16053 		string str2 = CALCULATOR->unlocalizeExpression(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(variableedit_builder, "variable_edit_entry_value"))), pa);
16054 		remove_blank_ends(str);
16055 		remove_blank_ends(str2);
16056 		GtkTreeIter iter;
16057 		if(str.empty() && (!names_edited || !gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tNames_store), &iter))) {
16058 			//no name -- open dialog again
16059 			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(variableedit_builder, "variable_edit_entry_name")));
16060 			show_message(_("Empty name field."), dialog);
16061 			goto run_variable_edit_dialog;
16062 		}
16063 		if(str2.empty() && !mstruct_) {
16064 			//no value -- open dialog again
16065 			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(variableedit_builder, "variable_edit_entry_value")));
16066 			show_message(_("Empty value field."), dialog);
16067 			goto run_variable_edit_dialog;
16068 		}
16069 		//variable with the same name exists -- overwrite or open dialog again
16070 		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)) {
16071 			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(variableedit_builder, "variable_edit_entry_name")));
16072 			goto run_variable_edit_dialog;
16073 		}
16074 		if(!v) {
16075 			//no need to create a new variable when a variable with the same name exists
16076 			var = CALCULATOR->getActiveVariable(str);
16077 			if(var && var->isLocal() && var->isKnown()) v = (KnownVariable*) var;
16078 		}
16079 		bool add_var = false;
16080 		if(v) {
16081 			//update existing variable
16082 			v->setLocal(true);
16083 			if(!v->isBuiltin()) {
16084 				if(mstruct_) {
16085 					v->set(*mstruct_);
16086 				} else {
16087 					v->set(str2);
16088 				}
16089 				v->setApproximate(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(variableedit_builder, "variable_edit_checkbutton_exact"))));
16090 			}
16091 		} else {
16092 			//new variable
16093 			if(mstruct_) {
16094 				//forced value
16095 				v = new KnownVariable("", "", *mstruct_, "", true);
16096 			} else {
16097 				v = new KnownVariable("", "", str2, "", true);
16098 				v->setApproximate(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(variableedit_builder, "variable_edit_checkbutton_exact"))));
16099 			}
16100 			add_var = true;
16101 		}
16102 		if(v) {
16103 			v->setCategory(gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(gtk_builder_get_object(variableedit_builder, "variable_edit_combo_category"))));
16104 			v->setTitle(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(variableedit_builder, "variable_edit_entry_desc"))));
16105 			set_edited_names(v, str);
16106 			if(add_var) {
16107 				CALCULATOR->addVariable(v);
16108 			}
16109 			//select the new variable
16110 			selected_variable = v;
16111 			if(!v->isActive()) {
16112 				selected_variable_category = _("Inactive");
16113 			} else if(v->category().empty()) {
16114 				selected_variable_category = _("Uncategorized");
16115 			} else {
16116 				selected_variable_category = "/";
16117 				selected_variable_category += v->category();
16118 			}
16119 		}
16120 		update_vmenu();
16121 		variable_inserted(v);
16122 	} else if(response == GTK_RESPONSE_HELP) {
16123 		show_help("qalculate-variables.html#qalculate-variable-creation", gtk_builder_get_object(variableedit_builder, "variable_edit_dialog"));
16124 		goto run_variable_edit_dialog;
16125 	}
16126 	edited_variable = NULL;
16127 	names_edited = false;
16128 	editing_variable = false;
16129 	gtk_widget_hide(dialog);
16130 }
16131 
16132 /*
16133 	display edit/new matrix dialog
16134 	creates new matrix if v == NULL, mstruct_ is forced value, win is parent window
16135 */
edit_matrix(const char * category,Variable * var,MathStructure * mstruct_,GtkWidget * win,gboolean create_vector)16136 void edit_matrix(const char *category, Variable *var, MathStructure *mstruct_, GtkWidget *win, gboolean create_vector) {
16137 
16138 	if(var != NULL && !var->isKnown()) {
16139 		edit_unknown(category, var, win);
16140 		return;
16141 	}
16142 
16143 	KnownVariable *v = (KnownVariable*) var;
16144 
16145 	if((v && !v->get().isVector()) || (mstruct_ && !mstruct_->isVector())) {
16146 		edit_variable(category, v, mstruct_, win);
16147 		return;
16148 	}
16149 
16150 	edited_matrix = v;
16151 	names_edited = false;
16152 	editing_matrix = true;
16153 
16154 	GtkWidget *dialog = get_matrix_edit_dialog();
16155 	if(win) gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(win));
16156 	if(mstruct_) {
16157 		create_vector = !mstruct_->isMatrix();
16158 	} else if(v) {
16159 		create_vector = !v->get().isMatrix();
16160 	}
16161 	if(create_vector) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(matrixedit_builder, "matrix_edit_radiobutton_vector")), TRUE);
16162 	else gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(matrixedit_builder, "matrix_edit_radiobutton_matrix")), TRUE);
16163 
16164 	if(create_vector) {
16165 		if(v) {
16166 			if(v->isLocal())
16167 				gtk_window_set_title(GTK_WINDOW(dialog), _("Edit Vector"));
16168 			else
16169 				gtk_window_set_title(GTK_WINDOW(dialog), _("Edit Vector (global)"));
16170 		} else {
16171 			gtk_window_set_title(GTK_WINDOW(dialog), _("New Vector"));
16172 		}
16173 	} else {
16174 		if(v) {
16175 			if(v->isLocal())
16176 				gtk_window_set_title(GTK_WINDOW(dialog), _("Edit Matrix"));
16177 			else
16178 				gtk_window_set_title(GTK_WINDOW(dialog), _("Edit Matrix (global)"));
16179 		} else {
16180 			gtk_window_set_title(GTK_WINDOW(dialog), _("New Matrix"));
16181 		}
16182 	}
16183 
16184 	int r = 4, c = 4;
16185 	const MathStructure *old_vctr = NULL;
16186 	if(v) {
16187 		if(create_vector) {
16188 			old_vctr = &v->get();
16189 		} else {
16190 			c = v->get().columns();
16191 			r = v->get().rows();
16192 		}
16193 		//fill in original parameters
16194 		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")));
16195 		//can only change name and value of user variable
16196 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_entry_name")), !v->isBuiltin());
16197 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_spinbutton_rows")), !v->isBuiltin());
16198 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_spinbutton_columns")), !v->isBuiltin());
16199 		//gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_table_elements")), !v->isBuiltin());
16200 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_radiobutton_matrix")), !v->isBuiltin());
16201 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_radiobutton_vector")), !v->isBuiltin());
16202 		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());
16203 		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(matrixedit_builder, "matrix_edit_entry_desc")), v->title(false).c_str());
16204 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_button_ok")), FALSE);
16205 	} else {
16206 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_entry_name")), TRUE);
16207 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_spinbutton_rows")), TRUE);
16208 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_spinbutton_columns")), TRUE);
16209 		//gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_table_elements")), TRUE);
16210 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_radiobutton_matrix")), TRUE);
16211 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_radiobutton_vector")), TRUE);
16212 
16213 		//fill in default values
16214 		string v_name;
16215 		int i = 1;
16216 		do {
16217 			v_name = "v"; v_name += i2s(i);
16218 			i++;
16219 		} while(CALCULATOR->nameTaken(v_name));
16220 		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(matrixedit_builder, "matrix_edit_entry_name")), v_name.c_str());
16221 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(matrixedit_builder, "matrix_edit_label_names")), "");
16222 		gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(gtk_builder_get_object(matrixedit_builder, "matrix_edit_combo_category")))), category);
16223 		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(matrixedit_builder, "matrix_edit_entry_desc")), "");
16224 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_button_ok")), TRUE);
16225 	}
16226 	if(mstruct_) {
16227 		//forced value
16228 		if(create_vector) {
16229 			old_vctr = mstruct_;
16230 		} else {
16231 			c = mstruct_->columns();
16232 			r = mstruct_->rows();
16233 		}
16234 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_spinbutton_rows")), FALSE);
16235 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_spinbutton_columns")), FALSE);
16236 		//gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_table_elements")), FALSE);
16237 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_radiobutton_matrix")), FALSE);
16238 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_radiobutton_vector")), FALSE);
16239 
16240 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_button_ok")), TRUE);
16241 	}
16242 
16243 	if(create_vector) {
16244 		if(old_vctr) {
16245 			r = old_vctr->countChildren();
16246 			c = (int) ::sqrt(::sqrt((double) r)) + 8;
16247 			if(c < 10) c = 10;
16248 			if(r % c > 0) {
16249 				r = r / c + 1;
16250 			} else {
16251 				r = r / c;
16252 			}
16253 			if(r < 100) r = 100;
16254 		} else {
16255 			c = 10;
16256 			r = 100;
16257 		}
16258 	}
16259 
16260 	gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(matrixedit_builder, "matrix_edit_spinbutton_rows")), r);
16261 	gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(matrixedit_builder, "matrix_edit_spinbutton_columns")), c);
16262 	on_matrix_edit_spinbutton_columns_value_changed(GTK_SPIN_BUTTON(gtk_builder_get_object(matrixedit_builder, "matrix_edit_spinbutton_columns")), NULL);
16263 	on_matrix_edit_spinbutton_rows_value_changed(GTK_SPIN_BUTTON(gtk_builder_get_object(matrixedit_builder, "matrix_edit_spinbutton_rows")), NULL);
16264 
16265 	CALCULATOR->startControl(2000);
16266 	PrintOptions po;
16267 	po.number_fraction_format = FRACTION_DECIMAL_EXACT;
16268 	po.interval_display = INTERVAL_DISPLAY_PLUSMINUS;
16269 	while(gtk_events_pending()) gtk_main_iteration();
16270 	GtkTreeIter iter;
16271 	bool b = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tMatrixEdit_store), &iter);
16272 	for(size_t index_r = 0; b && index_r < (size_t) r; index_r++) {
16273 		for(size_t index_c = 0; index_c < (size_t) c; index_c++) {
16274 			if(create_vector) {
16275 				if(old_vctr && index_r * c + index_c < old_vctr->countChildren()) {
16276 					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);
16277 				} else {
16278 					gtk_list_store_set(GTK_LIST_STORE(tMatrixEdit_store), &iter, index_c, "", -1);
16279 				}
16280 			} else {
16281 				if(v) {
16282 					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);
16283 				} else if(mstruct_) {
16284 					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);
16285 				} else {
16286 					gtk_list_store_set(GTK_LIST_STORE(tMatrixEdit_store), &iter, index_c, "0", -1);
16287 				}
16288 			}
16289 		}
16290 		b = gtk_tree_model_iter_next(GTK_TREE_MODEL(tMatrixEdit_store), &iter);
16291 	}
16292 	CALCULATOR->stopControl();
16293 	if(r > 0 && c > 0) {
16294 		GtkTreePath *path = gtk_tree_path_new_from_indices(0, -1);
16295 		gtk_tree_view_set_cursor(GTK_TREE_VIEW(tMatrixEdit), path, matrix_edit_columns[0], TRUE);
16296 		while(gtk_events_pending()) gtk_main_iteration();
16297 		gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(tMatrixEdit), path, matrix_edit_columns[0], FALSE, 0.0, 0.0);
16298 		on_tMatrixEdit_cursor_changed(GTK_TREE_VIEW(tMatrixEdit), NULL);
16299 		gtk_tree_path_free(path);
16300 	} else {
16301 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(matrixedit_builder, "matrix_edit_label_position")), "");
16302 	}
16303 	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_entry_name")));
16304 
16305 run_matrix_edit_dialog:
16306 	gint response = gtk_dialog_run(GTK_DIALOG(dialog));
16307 	if(response == GTK_RESPONSE_OK) {
16308 		//clicked "OK"
16309 		string str = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(matrixedit_builder, "matrix_edit_entry_name")));
16310 		remove_blank_ends(str);
16311 		GtkTreeIter iter;
16312 		if(str.empty() && (!names_edited || !gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tNames_store), &iter))) {
16313 			//no name -- open dialog again
16314 			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_entry_name")));
16315 			show_message(_("Empty name field."), dialog);
16316 			goto run_matrix_edit_dialog;
16317 		}
16318 
16319 		//variable with the same name exists -- overwrite or open dialog again
16320 		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)) {
16321 			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_entry_name")));
16322 			goto run_matrix_edit_dialog;
16323 		}
16324 		if(!v) {
16325 			//no need to create a new variable when a variable with the same name exists
16326 			var = CALCULATOR->getActiveVariable(str);
16327 			if(var && var->isLocal() && var->isKnown()) v = (KnownVariable*) var;
16328 		}
16329 		MathStructure mstruct_new;
16330 		if(!mstruct_) {
16331 			b = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tMatrixEdit_store), &iter);
16332 			c = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_builder_get_object(matrixedit_builder, "matrix_edit_spinbutton_columns")));
16333 			r = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_builder_get_object(matrixedit_builder, "matrix_edit_spinbutton_rows")));
16334 			gchar *gstr = NULL;
16335 			string mstr;
16336 			do_timeout = false;
16337 			ParseOptions pa = evalops.parse_options; pa.base = 10; pa.rpn = false;
16338 			if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(matrixedit_builder, "matrix_edit_radiobutton_vector")))) {
16339 				mstruct_new.clearVector();
16340 				for(size_t index_r = 0; index_r < (size_t) r && b; index_r++) {
16341 					for(size_t index_c = 0; index_c < (size_t) c; index_c++) {
16342 						gtk_tree_model_get(GTK_TREE_MODEL(tMatrixEdit_store), &iter, index_c, &gstr, -1);
16343 						mstr = gstr;
16344 						g_free(gstr);
16345 						remove_blank_ends(mstr);
16346 						if(!mstr.empty()) {
16347 							mstruct_new.addChild(CALCULATOR->parse(CALCULATOR->unlocalizeExpression(mstr, pa), pa));
16348 						}
16349 					}
16350 					b = gtk_tree_model_iter_next(GTK_TREE_MODEL(tMatrixEdit_store), &iter);
16351 				}
16352 			} else {
16353 				mstruct_new.clearMatrix();
16354 				mstruct_new.resizeMatrix((size_t) r, (size_t) c, m_undefined);
16355 				for(size_t index_r = 0; index_r < (size_t) r && b; index_r++) {
16356 					for(size_t index_c = 0; index_c < (size_t) c; index_c++) {
16357 						gtk_tree_model_get(GTK_TREE_MODEL(tMatrixEdit_store), &iter, index_c, &gstr, -1);
16358 						mstr = gstr;
16359 						g_free(gstr);
16360 						remove_blank_ends(mstr);
16361 						mstruct_new.setElement(CALCULATOR->parse(CALCULATOR->unlocalizeExpression(mstr, pa), pa), index_r + 1, index_c + 1);
16362 					}
16363 					b = gtk_tree_model_iter_next(GTK_TREE_MODEL(tMatrixEdit_store), &iter);
16364 				}
16365 			}
16366 			display_errors(NULL, dialog);
16367 			do_timeout = true;
16368 		}
16369 		bool add_var = false;
16370 		if(v) {
16371 			v->setLocal(true);
16372 			//update existing variable
16373 			if(!v->isBuiltin()) {
16374 				if(mstruct_) {
16375 					v->set(*mstruct_);
16376 				} else {
16377 					v->set(mstruct_new);
16378 				}
16379 			}
16380 		} else {
16381 			//new variable
16382 			if(mstruct_) {
16383 				v = new KnownVariable("", "", *mstruct_, "", true);
16384 			} else {
16385 				v = new KnownVariable("", "", mstruct_new, "", true);
16386 			}
16387 			add_var = true;
16388 		}
16389 		if(v) {
16390 			v->setCategory(gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(gtk_builder_get_object(matrixedit_builder, "matrix_edit_combo_category"))));
16391 			v->setTitle(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(matrixedit_builder, "matrix_edit_entry_desc"))));
16392 			set_edited_names(v, str);
16393 			if(add_var) {
16394 				CALCULATOR->addVariable(v);
16395 			}
16396 			//select the new variable
16397 			selected_variable = v;
16398 			if(!v->isActive()) {
16399 				selected_variable_category = _("Inactive");
16400 			} else if(v->category().empty()) {
16401 				selected_variable_category = _("Uncategorized");
16402 			} else {
16403 				selected_variable_category = "/";
16404 				selected_variable_category += v->category();
16405 			}
16406 		}
16407 		update_vmenu();
16408 		variable_inserted(v);
16409 	} else if(response == GTK_RESPONSE_HELP) {
16410 		show_help("qalculate-variables.html#qalculate-vectors-matrices", gtk_builder_get_object(matrixedit_builder, "matrix_edit_dialog"));
16411 		goto run_matrix_edit_dialog;
16412 	}
16413 	edited_matrix = NULL;
16414 	names_edited = false;
16415 	editing_matrix = false;
16416 	gtk_widget_hide(dialog);
16417 }
16418 
insert_matrix(const MathStructure * initial_value,GtkWidget * win,gboolean create_vector,bool is_text_struct,bool is_result,GtkEntry * entry)16419 void insert_matrix(const MathStructure *initial_value, GtkWidget *win, gboolean create_vector, bool is_text_struct, bool is_result, GtkEntry *entry) {
16420 
16421 	GtkWidget *dialog = get_matrix_dialog();
16422 	if(win) gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(win));
16423 
16424 	if(initial_value && !initial_value->isVector()) {
16425 		return;
16426 	}
16427 
16428 	GtkTextIter istart, iend;
16429 	if(!entry) gtk_text_buffer_get_selection_bounds(expressionbuffer, &istart, &iend);
16430 
16431 	if(initial_value) {
16432 		create_vector = !initial_value->isMatrix();
16433 	}
16434 	if(create_vector) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(matrix_builder, "matrix_radiobutton_vector")), TRUE);
16435 	else gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(matrix_builder, "matrix_radiobutton_matrix")), TRUE);
16436 
16437 	if(is_result) {
16438 		gtk_button_set_label(GTK_BUTTON(gtk_builder_get_object(matrix_builder, "matrix_button_cancel")), _("_Close"));
16439 		gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(matrix_builder, "matrix_button_cancel")));
16440 		if(create_vector) {
16441 			gtk_window_set_title(GTK_WINDOW(dialog), _("Vector Result"));
16442 		} else {
16443 			gtk_window_set_title(GTK_WINDOW(dialog), _("Matrix Result"));
16444 		}
16445 	} else {
16446 		gtk_button_set_label(GTK_BUTTON(gtk_builder_get_object(matrix_builder, "matrix_button_cancel")), _("_Cancel"));
16447 		gtk_widget_grab_focus(tMatrix);
16448 		if(create_vector) {
16449 			gtk_window_set_title(GTK_WINDOW(dialog), _("Vector"));
16450 		} else {
16451 			gtk_window_set_title(GTK_WINDOW(dialog), _("Matrix"));
16452 		}
16453 	}
16454 
16455 	int r = 4, c = 4;
16456 	if(create_vector) {
16457 		if(initial_value) {
16458 			r = initial_value->countChildren();
16459 			c = (int) sqrt(::sqrt(r)) + 8;
16460 			if(c < 10) c = 10;
16461 			if(r % c > 0) {
16462 				r = r / c + 1;
16463 			} else {
16464 				r = r / c;
16465 			}
16466 			if(r < 100) r = 100;
16467 		} else {
16468 			c = 10;
16469 			r = 100;
16470 		}
16471 	} else if(initial_value) {
16472 		c = initial_value->columns();
16473 		r = initial_value->rows();
16474 	}
16475 
16476 	gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(matrix_builder, "matrix_spinbutton_rows")), r);
16477 	gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(matrix_builder, "matrix_spinbutton_columns")), c);
16478 	on_matrix_spinbutton_columns_value_changed(GTK_SPIN_BUTTON(gtk_builder_get_object(matrix_builder, "matrix_spinbutton_columns")), NULL);
16479 	on_matrix_spinbutton_rows_value_changed(GTK_SPIN_BUTTON(gtk_builder_get_object(matrix_builder, "matrix_spinbutton_rows")), NULL);
16480 
16481 
16482 	printops.can_display_unicode_string_arg = (void*) tMatrix;
16483 	while(gtk_events_pending()) gtk_main_iteration();
16484 	GtkTreeIter iter;
16485 	bool b = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tMatrix_store), &iter);
16486 	CALCULATOR->startControl(5000);
16487 	for(size_t index_r = 0; b && index_r < (size_t) r; index_r++) {
16488 		for(size_t index_c = 0; index_c < (size_t) c; index_c++) {
16489 			if(create_vector) {
16490 				if(initial_value && index_r * c + index_c < initial_value->countChildren()) {
16491 					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);
16492 					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);
16493 				} else {
16494 					gtk_list_store_set(GTK_LIST_STORE(tMatrix_store), &iter, index_c, "", -1);
16495 				}
16496 			} else {
16497 				if(initial_value) {
16498 					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);
16499 					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);
16500 				} else {
16501 					gtk_list_store_set(GTK_LIST_STORE(tMatrix_store), &iter, index_c, "0", -1);
16502 				}
16503 			}
16504 		}
16505 		b = gtk_tree_model_iter_next(GTK_TREE_MODEL(tMatrix_store), &iter);
16506 	}
16507 	CALCULATOR->stopControl();
16508 
16509 	if(r > 0 && c > 0) {
16510 		GtkTreePath *path = gtk_tree_path_new_from_indices(0, -1);
16511 		if(!is_result) gtk_tree_view_set_cursor(GTK_TREE_VIEW(tMatrix), path, matrix_columns[0], TRUE);
16512 		while(gtk_events_pending()) gtk_main_iteration();
16513 		gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(tMatrix), path, matrix_columns[0], FALSE, 0.0, 0.0);
16514 		on_tMatrix_cursor_changed(GTK_TREE_VIEW(tMatrix), NULL);
16515 		gtk_tree_path_free(path);
16516 	} else {
16517 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(matrix_builder, "matrix_label_position")), "");
16518 	}
16519 	printops.can_display_unicode_string_arg = NULL;
16520 
16521 	gint response = gtk_dialog_run(GTK_DIALOG(dialog));
16522 	if(response == GTK_RESPONSE_OK) {
16523 		//clicked "OK"
16524 		string matrixstr, str;
16525 		bool b = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tMatrix_store), &iter);
16526 		c = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_builder_get_object(matrix_builder, "matrix_spinbutton_columns")));
16527 		r = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_builder_get_object(matrix_builder, "matrix_spinbutton_rows")));
16528 		gchar *gstr = NULL;
16529 		if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(matrix_builder, "matrix_radiobutton_vector")))) {
16530 			bool b1 = false;
16531 			matrixstr = "[";
16532 			for(size_t index_r = 0; index_r < (size_t) r && b; index_r++) {
16533 				for(size_t index_c = 0; index_c < (size_t) c; index_c++) {
16534 					gtk_tree_model_get(GTK_TREE_MODEL(tMatrix_store), &iter, index_c, &gstr, -1);
16535 					str = gstr;
16536 					g_free(gstr);
16537 					remove_blank_ends(str);
16538 					if(!str.empty()) {
16539 						if(b1) {
16540 							matrixstr += CALCULATOR->getComma();
16541 							matrixstr += " ";
16542 						} else {
16543 							b1 = true;
16544 						}
16545 						matrixstr += str;
16546 					}
16547 				}
16548 				b = gtk_tree_model_iter_next(GTK_TREE_MODEL(tMatrix_store), &iter);
16549 			}
16550 			matrixstr += "]";
16551 		} else {
16552 			matrixstr = "[";
16553 			bool b1 = false;
16554 			for(size_t index_r = 0; index_r < (size_t) r && b; index_r++) {
16555 				if(b1) {
16556 					matrixstr += CALCULATOR->getComma();
16557 					matrixstr += " ";
16558 				} else {
16559 					b1 = true;
16560 				}
16561 				matrixstr += "[";
16562 				bool b2 = false;
16563 				for(size_t index_c = 0; index_c < (size_t) c; index_c++) {
16564 					if(b2) {
16565 						matrixstr += CALCULATOR->getComma();
16566 						matrixstr += " ";
16567 					} else {
16568 						b2 = true;
16569 					}
16570 					gtk_tree_model_get(GTK_TREE_MODEL(tMatrix_store), &iter, index_c, &gstr, -1);
16571 					str = gstr;
16572 					remove_blank_ends(str);
16573 					g_free(gstr);
16574 					matrixstr += str;
16575 				}
16576 				matrixstr += "]";
16577 				b = gtk_tree_model_iter_next(GTK_TREE_MODEL(tMatrix_store), &iter);
16578 			}
16579 			matrixstr += "]";
16580 		}
16581 		if(entry) {
16582 			gtk_entry_set_text(entry, matrixstr.c_str());
16583 		} else {
16584 			gtk_text_buffer_select_range(expressionbuffer, &istart, &iend);
16585 			insert_text(matrixstr.c_str());
16586 		}
16587 	}
16588 	gtk_widget_hide(dialog);
16589 }
16590 
16591 
edit_dataobject(DataSet * ds,DataObject * o,GtkWidget * win)16592 void edit_dataobject(DataSet *ds, DataObject *o, GtkWidget *win) {
16593 	if(!ds) return;
16594 	GtkWidget *dialog = get_dataobject_edit_dialog();
16595 	if(o) {
16596 		gtk_window_set_title(GTK_WINDOW(dialog), _("Edit Data Object"));
16597 	} else {
16598 		gtk_window_set_title(GTK_WINDOW(dialog), _("New Data Object"));
16599 	}
16600 	if(win) gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(win));
16601 	GtkWidget *ptable = GTK_WIDGET(gtk_builder_get_object(datasets_builder, "dataobject_edit_grid"));
16602 	GList *childlist = gtk_container_get_children(GTK_CONTAINER(ptable));
16603 	for(guint i = 0; ; i++) {
16604 		GtkWidget *w = (GtkWidget*) g_list_nth_data(childlist, i);
16605 		if(!w) break;
16606 		gtk_widget_destroy(w);
16607 	}
16608 	g_list_free(childlist);
16609 	DataPropertyIter it;
16610 	DataProperty *dp = ds->getFirstProperty(&it);
16611 	string sval;
16612 	int rows = 1;
16613 	gtk_grid_remove_column(GTK_GRID(ptable), 0);
16614 	gtk_grid_remove_column(GTK_GRID(ptable), 1);
16615 	gtk_grid_remove_column(GTK_GRID(ptable), 2);
16616 	gtk_grid_remove_column(GTK_GRID(ptable), 3);
16617 	gtk_grid_set_column_spacing(GTK_GRID(ptable), 20);
16618 	GtkWidget *label, *entry, *om;
16619 	vector<GtkWidget*> value_entries;
16620 	vector<GtkWidget*> approx_menus;
16621 	string str;
16622 	while(dp) {
16623 		label = gtk_label_new(dp->title().c_str()); gtk_widget_set_halign(label, GTK_ALIGN_START);
16624 		gtk_grid_attach(GTK_GRID(ptable), label, 0, rows - 1, 1, 1);
16625 
16626 		entry = gtk_entry_new();
16627 		value_entries.push_back(entry);
16628 		int iapprox = -1;
16629 		if(o) {
16630 			gtk_entry_set_text(GTK_ENTRY(entry), o->getProperty(dp, &iapprox).c_str());
16631 		}
16632 		gtk_grid_attach(GTK_GRID(ptable), entry, 1, rows - 1, 1, 1);
16633 
16634 		label = gtk_label_new(dp->getUnitString().c_str()); gtk_widget_set_halign(label, GTK_ALIGN_START);
16635 		gtk_grid_attach(GTK_GRID(ptable), label, 2, rows - 1, 1, 1);
16636 
16637 		om = gtk_combo_box_text_new();
16638 		approx_menus.push_back(om);
16639 		gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(om), NULL, _("Default"));
16640 		gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(om), NULL, _("Approximate"));
16641 		gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(om), NULL, _("Exact"));
16642 		gtk_combo_box_set_active(GTK_COMBO_BOX(om), iapprox + 1);
16643 
16644 		g_signal_connect(entry, "changed", G_CALLBACK(on_dataobject_changed), NULL);
16645 		g_signal_connect(om, "changed", G_CALLBACK(on_dataobject_changed), NULL);
16646 
16647 		gtk_grid_attach(GTK_GRID(ptable), om, 3, rows - 1, 1, 1);
16648 
16649 		rows++;
16650 		dp = ds->getNextProperty(&it);
16651 	}
16652 	if(value_entries.size() > 0) gtk_widget_grab_focus(value_entries[0]);
16653 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasets_builder, "dataobject_edit_button_ok")), FALSE);
16654 	gtk_widget_show_all(ptable);
16655 	if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) {
16656 		bool new_object = (o == NULL);
16657 		if(new_object) {
16658 			o = new DataObject(ds);
16659 			ds->addObject(o);
16660 		}
16661 		dp = ds->getFirstProperty(&it);
16662 		size_t i = 0;
16663 		string val;
16664 		while(dp) {
16665 			val = gtk_entry_get_text(GTK_ENTRY(value_entries[i]));
16666 			remove_blank_ends(val);
16667 			if(!val.empty()) {
16668 				o->setProperty(dp, val, gtk_combo_box_get_active(GTK_COMBO_BOX(approx_menus[i])) - 1);
16669 			} else if(!new_object) {
16670 				o->eraseProperty(dp);
16671 			}
16672 			dp = ds->getNextProperty(&it);
16673 			i++;
16674 		}
16675 		o->setUserModified();
16676 		selected_dataobject = o;
16677 		update_dataobjects();
16678 	}
16679 	/*for(size_t i = 0; i < approx_menus.size(); i++) {
16680 		menu = gtk_option_menu_get_menu(GTK_OPTION_MENU(approx_menus[i]));
16681 		gtk_widget_destroy(menu);
16682 	}*/
16683 	gtk_widget_hide(dialog);
16684 }
16685 
update_dataset_property_list(DataSet *)16686 void update_dataset_property_list(DataSet*) {
16687 	if(!datasetedit_builder) return;
16688 	selected_dataproperty = NULL;
16689 	gtk_list_store_clear(tDataProperties_store);
16690 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasetedit_builder, "dataset_edit_button_edit_property")), FALSE);
16691 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasetedit_builder, "dataset_edit_button_del_property")), FALSE);
16692 	GtkTreeIter iter;
16693 	string str;
16694 	for(size_t i = 0; i < tmp_props.size(); i++) {
16695 		if(tmp_props[i]) {
16696 			gtk_list_store_append(tDataProperties_store, &iter);
16697 			str = "";
16698 			switch(tmp_props[i]->propertyType()) {
16699 				case PROPERTY_STRING: {
16700 					str += _("text");
16701 					break;
16702 				}
16703 				case PROPERTY_NUMBER: {
16704 					if(tmp_props[i]->isApproximate()) {
16705 						str += _("approximate");
16706 						str += " ";
16707 					}
16708 					str += _("number");
16709 					break;
16710 				}
16711 				case PROPERTY_EXPRESSION: {
16712 					if(tmp_props[i]->isApproximate()) {
16713 						str += _("approximate");
16714 						str += " ";
16715 					}
16716 					str += _("expression");
16717 					break;
16718 				}
16719 			}
16720 			if(tmp_props[i]->isKey()) {
16721 				str += " (";
16722 				str += _("key");
16723 				str += ")";
16724 			}
16725 			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);
16726 		}
16727 	}
16728 }
16729 
edit_dataproperty(DataProperty * dp,bool new_property=false)16730 bool edit_dataproperty(DataProperty *dp, bool new_property = false) {
16731 
16732 	GtkWidget *dialog = get_dataproperty_edit_dialog();
16733 	gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gtk_builder_get_object(datasetedit_builder, "dataset_edit_dialog")));
16734 
16735 	edited_dataproperty = dp;
16736 	names_edited = false;
16737 	editing_dataproperty = true;
16738 
16739 	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_entry_name")), dp->getName().c_str());
16740 	if(dp->countNames() > 1) {
16741 		string str = "+ ";
16742 		for(size_t i = 2; i <= dp->countNames(); i++) {
16743 			if(i > 2) str += ", ";
16744 			str += dp->getName(i);
16745 		}
16746 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_label_names")), str.c_str());
16747 	} else {
16748 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_label_names")), "");
16749 	}
16750 
16751 	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_entry_title")), dp->title(false).c_str());
16752 	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_entry_unit")), dp->getUnitString().c_str());
16753 
16754 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_checkbutton_hide")), dp->isHidden());
16755 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_checkbutton_key")), dp->isKey());
16756 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_checkbutton_approximate")), dp->isApproximate());
16757 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_checkbutton_case")), dp->isCaseSensitive());
16758 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_checkbutton_brackets")), dp->usesBrackets());
16759 
16760 	GtkTextBuffer *description_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_textview_description")));
16761 	gtk_text_buffer_set_text(description_buffer, dp->description().c_str(), -1);
16762 
16763 	switch(dp->propertyType()) {
16764 		case PROPERTY_STRING: {
16765 			gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_combobox_type")), 0);
16766 			break;
16767 		}
16768 		case PROPERTY_NUMBER: {
16769 			gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_combobox_type")), 1);
16770 			break;
16771 		}
16772 		case PROPERTY_EXPRESSION: {
16773 			gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_combobox_type")), 2);
16774 			break;
16775 		}
16776 	}
16777 
16778 	bool return_val = false;
16779 
16780 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_button_ok")), new_property);
16781 
16782 	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_entry_name")));
16783 
16784 	run_dataproperty_edit_dialog:
16785 	if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) {
16786 
16787 		string str = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_entry_name")));
16788 		remove_blank_ends(str);
16789 		GtkTreeIter iter;
16790 		if(str.empty() && (!names_edited || !gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tNames_store), &iter))) {
16791 			//no name -- open dialog again
16792 			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_entry_name")));
16793 			show_message(_("Empty name field."), dialog);
16794 			goto run_dataproperty_edit_dialog;
16795 		}
16796 
16797 		dp->setTitle(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_entry_title"))));
16798 		dp->setUnit(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_entry_unit"))));
16799 
16800 		dp->setHidden(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_checkbutton_hide"))));
16801 		dp->setKey(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_checkbutton_key"))));
16802 		dp->setApproximate(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_checkbutton_approximate"))));
16803 		dp->setCaseSensitive(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_checkbutton_case"))));
16804 		dp->setUsesBrackets(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_checkbutton_brackets"))));
16805 
16806 		GtkTextIter e_iter_s, e_iter_e;
16807 		gtk_text_buffer_get_start_iter(description_buffer, &e_iter_s);
16808 		gtk_text_buffer_get_end_iter(description_buffer, &e_iter_e);
16809 		gchar *gstr = gtk_text_buffer_get_text(description_buffer, &e_iter_s, &e_iter_e, FALSE);
16810 		dp->setDescription(gstr);
16811 		g_free(gstr);
16812 
16813 		switch(gtk_combo_box_get_active(GTK_COMBO_BOX(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_combobox_type")))) {
16814 			case 0: {
16815 				dp->setPropertyType(PROPERTY_STRING);
16816 				break;
16817 			}
16818 			case 1: {
16819 				dp->setPropertyType(PROPERTY_NUMBER);
16820 				break;
16821 			}
16822 			case 2: {
16823 				dp->setPropertyType(PROPERTY_EXPRESSION);
16824 				break;
16825 			}
16826 		}
16827 		if(names_edited) {
16828 			dp->clearNames();
16829 			GtkTreeIter iter;
16830 			if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tNames_store), &iter)) {
16831 				gchar *gstr;
16832 				while(true) {
16833 					gboolean reference = FALSE;
16834 					gtk_tree_model_get(GTK_TREE_MODEL(tNames_store), &iter, NAMES_NAME_COLUMN, &gstr, NAMES_REFERENCE_COLUMN, &reference, -1);
16835 					dp->addName(gstr, reference);
16836 					g_free(gstr);
16837 					if(!gtk_tree_model_iter_next(GTK_TREE_MODEL(tNames_store), &iter)) break;
16838 				}
16839 			} else {
16840 				dp->addName(str);
16841 			}
16842 		} else {
16843 			dp->setName(str, 1);
16844 		}
16845 
16846 		return_val = true;
16847 
16848 	}
16849 
16850 	names_edited = false;
16851 	editing_dataproperty = false;
16852 	edited_dataproperty = NULL;
16853 
16854 	gtk_widget_hide(dialog);
16855 
16856 	return return_val;
16857 
16858 }
16859 
16860 
edit_dataset(DataSet * ds,GtkWidget * win)16861 void edit_dataset(DataSet *ds, GtkWidget *win) {
16862 	GtkWidget *dialog = get_dataset_edit_dialog();
16863 	if(win) gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(win));
16864 
16865 	edited_dataset = ds;
16866 	names_edited = false;
16867 	editing_dataset = true;
16868 
16869 	if(ds) {
16870 		if(ds->isLocal())
16871 			gtk_window_set_title(GTK_WINDOW(dialog), _("Edit Data Set"));
16872 		else
16873 			gtk_window_set_title(GTK_WINDOW(dialog), _("Edit Data Set (global)"));
16874 	} else {
16875 		gtk_window_set_title(GTK_WINDOW(dialog), _("New Data Set"));
16876 	}
16877 
16878 	GtkTextBuffer *description_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtk_builder_get_object(datasetedit_builder, "dataset_edit_textview_description")));
16879 	GtkTextBuffer *copyright_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtk_builder_get_object(datasetedit_builder, "dataset_edit_textview_copyright")));
16880 
16881 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasetedit_builder, "dataset_edit_textview_copyright")), !ds || ds->isLocal());
16882 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasetedit_builder, "dataset_edit_entry_file")), !ds || ds->isLocal());
16883 
16884 	//clear entries
16885 	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataset_edit_entry_name")), "");
16886 	gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(datasetedit_builder, "dataset_edit_label_names")), "");
16887 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasetedit_builder, "dataset_edit_entry_name")), TRUE);
16888 	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataset_edit_entry_desc")), "");
16889 	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataset_edit_entry_file")), "");
16890 	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataset_edit_entry_object_name")), "");
16891 	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataset_edit_entry_property_name")), "");
16892 	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataset_edit_entry_default_property")), _("info"));
16893 	gtk_text_buffer_set_text(description_buffer, "", -1);
16894 	gtk_text_buffer_set_text(copyright_buffer, "", -1);
16895 
16896 	gtk_list_store_clear(tDataProperties_store);
16897 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasetedit_builder, "dataset_edit_button_edit_property")), FALSE);
16898 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasetedit_builder, "dataset_edit_button_del_property")), FALSE);
16899 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasetedit_builder, "dataset_edit_button_new_property")), TRUE);
16900 
16901 	if(ds) {
16902 		//fill in original paramaters
16903 		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")));
16904 		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataset_edit_entry_desc")), ds->title(false).c_str());
16905 		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataset_edit_entry_file")), ds->defaultDataFile().c_str());
16906 		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataset_edit_entry_default_property")), ds->defaultProperty().c_str());
16907 		Argument *arg = ds->getArgumentDefinition(1);
16908 		if(arg) {
16909 			gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataset_edit_entry_object_name")), arg->name().c_str());
16910 		}
16911 		arg = ds->getArgumentDefinition(2);
16912 		if(arg) {
16913 			gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataset_edit_entry_property_name")), arg->name().c_str());
16914 		}
16915 		gtk_text_buffer_set_text(description_buffer, ds->description().c_str(), -1);
16916 		gtk_text_buffer_set_text(copyright_buffer, ds->copyright().c_str(), -1);
16917 		DataPropertyIter it;
16918 		DataProperty *dp = ds->getFirstProperty(&it);
16919 		while(dp) {
16920 			tmp_props.push_back(new DataProperty(*dp));
16921 			tmp_props_orig.push_back(dp);
16922 			dp = ds->getNextProperty(&it);
16923 		}
16924 
16925 	}
16926 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasetedit_builder, "dataset_edit_button_ok")), FALSE);
16927 
16928 	update_dataset_property_list(ds);
16929 
16930 	gtk_notebook_set_current_page(GTK_NOTEBOOK(gtk_builder_get_object(datasetedit_builder, "dataset_edit_tabs")), 0);
16931 
16932 	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(datasetedit_builder, "dataset_edit_entry_desc")));
16933 
16934 	run_dataset_edit_dialog:
16935 	if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) {
16936 		//clicked "OK"
16937 		string str = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataset_edit_entry_name")));
16938 		remove_blank_ends(str);
16939 		GtkTreeIter iter;
16940 		if(str.empty() && (!names_edited || !gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tNames_store), &iter))) {
16941 			//no name -- open dialog again
16942 			gtk_notebook_set_current_page(GTK_NOTEBOOK(gtk_builder_get_object(datasetedit_builder, "dataset_edit_tabs")), 2);
16943 			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(datasetedit_builder, "dataset_edit_entry_name")));
16944 			show_message(_("Empty name field."), dialog);
16945 			goto run_dataset_edit_dialog;
16946 		}
16947 		GtkTextIter d_iter_s, d_iter_e;
16948 		gtk_text_buffer_get_start_iter(description_buffer, &d_iter_s);
16949 		gtk_text_buffer_get_end_iter(description_buffer, &d_iter_e);
16950 		GtkTextIter c_iter_s, c_iter_e;
16951 		gtk_text_buffer_get_start_iter(copyright_buffer, &c_iter_s);
16952 		gtk_text_buffer_get_end_iter(copyright_buffer, &c_iter_e);
16953 		//dataset with the same name exists -- overwrite or open the dialog again
16954 		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)) {
16955 			gtk_notebook_set_current_page(GTK_NOTEBOOK(gtk_builder_get_object(datasetedit_builder, "dataset_edit_tabs")), 2);
16956 			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(datasetedit_builder, "dataset_edit_entry_name")));
16957 			goto run_dataset_edit_dialog;
16958 		}
16959 		bool add_func = false;
16960 		gchar *gstr_descr = gtk_text_buffer_get_text(description_buffer, &d_iter_s, &d_iter_e, FALSE);
16961 		if(ds) {
16962 			//edited an existing dataset
16963 			ds->setTitle(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataset_edit_entry_desc"))));
16964 			if(ds->isLocal()) ds->setDefaultDataFile(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataset_edit_entry_file"))));
16965 			ds->setDescription(gstr_descr);
16966 		} else {
16967 			//new dataset
16968 			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);
16969 			add_func = true;
16970 		}
16971 		g_free(gstr_descr);
16972 		string str2;
16973 		if(ds) {
16974 			str2 = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataset_edit_entry_object_name")));
16975 			remove_blank_ends(str2);
16976 			if(str2.empty()) str2 = _("Object");
16977 			Argument *arg = ds->getArgumentDefinition(1);
16978 			if(arg) {
16979 				arg->setName(str2);
16980 			}
16981 			str2 = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataset_edit_entry_property_name")));
16982 			remove_blank_ends(str2);
16983 			if(str2.empty()) str2 = _("Property");
16984 			arg = ds->getArgumentDefinition(2);
16985 			if(arg) {
16986 				arg->setName(str2);
16987 			}
16988 			ds->setDefaultProperty(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(datasetedit_builder, "dataset_edit_entry_default_property"))));
16989 			gchar *gstr = gtk_text_buffer_get_text(copyright_buffer, &c_iter_s, &c_iter_e, FALSE);
16990 			ds->setCopyright(gstr);
16991 			g_free(gstr);
16992 			for(size_t i = 0; i < tmp_props.size();) {
16993 				if(!tmp_props[i]) {
16994 					if(tmp_props_orig[i]) ds->delProperty(tmp_props_orig[i]);
16995 					i++;
16996 				} else if(tmp_props[i]->isUserModified()) {
16997 					if(tmp_props_orig[i]) {
16998 						tmp_props_orig[i]->set(*tmp_props[i]);
16999 						i++;
17000 					} else {
17001 						ds->addProperty(tmp_props[i]);
17002 						tmp_props.erase(tmp_props.begin() + i);
17003 					}
17004 				} else {
17005 					i++;
17006 				}
17007 			}
17008 			set_edited_names(ds, str);
17009 			if(add_func) {
17010 				CALCULATOR->addDataSet(ds);
17011 				ds->loadObjects();
17012 				ds->setObjectsLoaded(true);
17013 			}
17014 			selected_dataset = ds;
17015 		}
17016 		update_fmenu();
17017 		function_inserted(ds);
17018 		update_datasets_tree();
17019 	}
17020 	for(size_t i = 0; i < tmp_props.size(); i++) {
17021 		if(tmp_props[i]) delete tmp_props[i];
17022 	}
17023 	tmp_props.clear();
17024 	tmp_props_orig.clear();
17025 	edited_dataset = NULL;
17026 	editing_dataset = false;
17027 	names_edited = false;
17028 	gtk_widget_hide(dialog);
17029 }
17030 
import_csv_file(GtkWidget * win)17031 void import_csv_file(GtkWidget *win) {
17032 
17033 	GtkWidget *dialog = get_csv_import_dialog();
17034 	if(win) gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(win));
17035 
17036 	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(csvimport_builder, "csv_import_entry_name")), "");
17037 	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(csvimport_builder, "csv_import_entry_file")), "");
17038 	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(csvimport_builder, "csv_import_entry_desc")), "");
17039 
17040 	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(csvimport_builder, "csv_import_entry_file")));
17041 
17042 run_csv_import_dialog:
17043 	if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) {
17044 		//clicked "OK"
17045 		string str = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(csvimport_builder, "csv_import_entry_file")));
17046 		remove_blank_ends(str);
17047 		if(str.empty()) {
17048 			//no filename -- open dialog again
17049 			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(csvimport_builder, "csv_import_entry_file")));
17050 			show_message(_("No file name entered."), dialog);
17051 			goto run_csv_import_dialog;
17052 		}
17053 		string name_str = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(csvimport_builder, "csv_import_entry_name")));
17054 		remove_blank_ends(name_str);
17055 		if(name_str.empty()) {
17056 			//no name -- open dialog again
17057 			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(csvimport_builder, "csv_import_entry_name")));
17058 			show_message(_("Empty name field."), dialog);
17059 			goto run_csv_import_dialog;
17060 		}
17061 		//variable with the same name exists -- overwrite or open dialog again
17062 		if(CALCULATOR->variableNameTaken(name_str) && !ask_question(_("An unit or variable with the same name already exists.\nDo you want to overwrite it?"), dialog)) {
17063 			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(csvimport_builder, "csv_import_entry_name")));
17064 			goto run_csv_import_dialog;
17065 		}
17066 		string delimiter = "";
17067 		switch(gtk_combo_box_get_active(GTK_COMBO_BOX(gtk_builder_get_object(csvimport_builder, "csv_import_combobox_delimiter")))) {
17068 			case DELIMITER_COMMA: {
17069 				delimiter = ",";
17070 				break;
17071 			}
17072 			case DELIMITER_TABULATOR: {
17073 				delimiter = "\t";
17074 				break;
17075 			}
17076 			case DELIMITER_SEMICOLON: {
17077 				delimiter = ";";
17078 				break;
17079 			}
17080 			case DELIMITER_SPACE: {
17081 				delimiter = " ";
17082 				break;
17083 			}
17084 			case DELIMITER_OTHER: {
17085 				delimiter = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(csvimport_builder, "csv_import_entry_delimiter_other")));
17086 				break;
17087 			}
17088 		}
17089 		if(delimiter.empty()) {
17090 			//no filename -- open dialog again
17091 			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(csvimport_builder, "csv_import_entry_delimiter_other")));
17092 			show_message(_("No delimiter selected."), dialog);
17093 			goto run_csv_import_dialog;
17094 		}
17095 		do_timeout = false;
17096 		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"))))) {
17097 			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());
17098 			gtk_dialog_run(GTK_DIALOG(edialog));
17099 			gtk_widget_destroy(edialog);
17100 		}
17101 		display_errors(NULL, dialog);
17102 		do_timeout = true;
17103 		update_vmenu();
17104 	}
17105 	gtk_widget_hide(dialog);
17106 }
17107 
export_csv_file(KnownVariable * v,GtkWidget * win)17108 void export_csv_file(KnownVariable *v, GtkWidget *win) {
17109 
17110 	GtkWidget *dialog = get_csv_export_dialog();
17111 	if(win) gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(win));
17112 
17113 	if(v) {
17114 		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());
17115 		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());
17116 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(csvexport_builder, "csv_export_radiobutton_matrix")), TRUE);
17117 	} else {
17118 		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(csvexport_builder, "csv_export_entry_file")), "");
17119 		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(csvexport_builder, "csv_export_entry_matrix")), "");
17120 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(csvexport_builder, "csv_export_radiobutton_current")), TRUE);
17121 	}
17122 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(csvexport_builder, "csv_export_radiobutton_matrix")), !v);
17123 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(csvexport_builder, "csv_export_radiobutton_current")), !v);
17124 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(csvexport_builder, "csv_export_entry_matrix")), FALSE);
17125 
17126 	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(csvexport_builder, "csv_export_entry_file")));
17127 
17128 run_csv_export_dialog:
17129 	if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) {
17130 		//clicked "OK"
17131 		string str = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(csvexport_builder, "csv_export_entry_file")));
17132 		remove_blank_ends(str);
17133 		if(str.empty()) {
17134 			//no filename -- open dialog again
17135 			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(csvexport_builder, "csv_export_entry_file")));
17136 			show_message(_("No file name entered."), dialog);
17137 			goto run_csv_export_dialog;
17138 		}
17139 		string delimiter = "";
17140 		switch(gtk_combo_box_get_active(GTK_COMBO_BOX(gtk_builder_get_object(csvexport_builder, "csv_export_combobox_delimiter")))) {
17141 			case DELIMITER_COMMA: {
17142 				delimiter = ",";
17143 				break;
17144 			}
17145 			case DELIMITER_TABULATOR: {
17146 				delimiter = "\t";
17147 				break;
17148 			}
17149 			case DELIMITER_SEMICOLON: {
17150 				delimiter = ";";
17151 				break;
17152 			}
17153 			case DELIMITER_SPACE: {
17154 				delimiter = " ";
17155 				break;
17156 			}
17157 			case DELIMITER_OTHER: {
17158 				delimiter = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(csvexport_builder, "csv_export_entry_delimiter_other")));
17159 				break;
17160 			}
17161 		}
17162 		if(delimiter.empty()) {
17163 			//no delimiter -- open dialog again
17164 			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(csvexport_builder, "csv_export_entry_delimiter_other")));
17165 			show_message(_("No delimiter selected."), dialog);
17166 			goto run_csv_export_dialog;
17167 		}
17168 		MathStructure *matrix_struct;
17169 		if(v) {
17170 			matrix_struct = (MathStructure*) &v->get();
17171 		} else if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(csvexport_builder, "csv_export_radiobutton_current")))) {
17172 			matrix_struct = mstruct;
17173 		} else {
17174 			string str2 = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(csvexport_builder, "csv_export_entry_matrix")));
17175 			remove_blank_ends(str2);
17176 			if(str2.empty()) {
17177 				gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(csvexport_builder, "csv_export_entry_matrix")));
17178 				show_message(_("No variable name entered."), dialog);
17179 				goto run_csv_export_dialog;
17180 			}
17181 			Variable *var = CALCULATOR->getActiveVariable(str2);
17182 			if(!var || !var->isKnown()) {
17183 				var = CALCULATOR->getVariable(str2);
17184 				while(var && !var->isKnown()) {
17185 					var = CALCULATOR->getVariable(str2);
17186 				}
17187 			}
17188 			if(!var || !var->isKnown()) {
17189 				gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(csvexport_builder, "csv_export_entry_matrix")));
17190 				show_message(_("No known variable with entered name found."), dialog);
17191 				goto run_csv_export_dialog;
17192 			}
17193 			matrix_struct = (MathStructure*) &((KnownVariable*) var)->get();
17194 		}
17195 		CALCULATOR->startControl(600000);
17196 		if(!CALCULATOR->exportCSV(*matrix_struct, str.c_str(), delimiter) && CALCULATOR->aborted()) {
17197 			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());
17198 			gtk_dialog_run(GTK_DIALOG(edialog));
17199 			gtk_widget_destroy(edialog);
17200 		}
17201 		CALCULATOR->stopControl();
17202 	}
17203 	gtk_widget_hide(dialog);
17204 
17205 }
17206 
edit_names(ExpressionItem * item,const gchar * namestr,GtkWidget * win,bool is_dp,DataProperty * dp)17207 void edit_names(ExpressionItem *item, const gchar *namestr, GtkWidget *win, bool is_dp, DataProperty *dp) {
17208 
17209 	GtkWidget *dialog = get_names_edit_dialog();
17210 	if(win) gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(win));
17211 
17212 	GtkTreeIter iter;
17213 
17214 	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)));
17215 	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)));
17216 
17217 	if(!names_edited) {
17218 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(namesedit_builder, "names_edit_button_modify")), FALSE);
17219 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(namesedit_builder, "names_edit_button_remove")), FALSE);
17220 
17221 		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(namesedit_builder, "names_edit_entry_name")), "");
17222 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_reference")), FALSE);
17223 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_abbreviation")), FALSE);
17224 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_plural")), FALSE);
17225 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_suffix")), FALSE);
17226 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_avoid_input")), FALSE);
17227 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_case_sensitive")), FALSE);
17228 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_unicode")), FALSE);
17229 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_completion_only")), FALSE);
17230 
17231 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_abbreviation")), !is_dp);
17232 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_plural")), !is_dp);
17233 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_suffix")), !is_dp);
17234 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_avoid_input")), !is_dp);
17235 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_case_sensitive")), !is_dp);
17236 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_unicode")), !is_dp);
17237 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(namesedit_builder, "names_edit_checkbutton_completion_only")), !is_dp);
17238 
17239 		gtk_list_store_clear(tNames_store);
17240 
17241 		if(!is_dp && item && item->countNames() > 0) {
17242 			for(size_t i = 1; i <= item->countNames(); i++) {
17243 				const ExpressionName *ename = &item->getName(i);
17244 				gtk_list_store_append(tNames_store, &iter);
17245 				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);
17246 				if(i == 1 && namestr && strlen(namestr) > 0) {
17247 					gtk_list_store_set(tNames_store, &iter, NAMES_NAME_COLUMN, namestr, -1);
17248 				}
17249 			}
17250 		} else if(is_dp && dp && dp->countNames() > 0) {
17251 			for(size_t i = 1; i <= dp->countNames(); i++) {
17252 				gtk_list_store_append(tNames_store, &iter);
17253 				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);
17254 				if(i == 1 && namestr && strlen(namestr) > 0) {
17255 					gtk_list_store_set(tNames_store, &iter, NAMES_NAME_COLUMN, namestr, -1);
17256 				}
17257 			}
17258 		} else if(namestr && strlen(namestr) > 0) {
17259 			gtk_list_store_append(tNames_store, &iter);
17260 			if(is_dp) {
17261 				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);
17262 			} else {
17263 				ExpressionName ename(namestr);
17264 				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);
17265 			}
17266 		}
17267 	} else if(namestr && strlen(namestr) > 0) {
17268 		if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tNames_store), &iter)) {
17269 			gtk_list_store_set(tNames_store, &iter, NAMES_NAME_COLUMN, namestr, -1);
17270 		}
17271 		on_tNames_selection_changed(gtk_tree_view_get_selection(GTK_TREE_VIEW(tNames)), NULL);
17272 	}
17273 
17274 	if(!(item && item->isBuiltin() && !(item->type() == TYPE_FUNCTION && item->subtype() == SUBTYPE_DATA_SET))) {
17275 		gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(namesedit_builder, "names_edit_entry_name")));
17276 	} else {
17277 		gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(namesedit_builder, "button_close")));
17278 	}
17279 
17280 	gtk_dialog_run(GTK_DIALOG(dialog));
17281 	names_edited = true;
17282 
17283 	gtk_widget_hide(dialog);
17284 }
17285 
17286 
17287 /*
17288 	add a new variable (from menu) with the value of result
17289 */
add_as_variable()17290 void add_as_variable()
17291 {
17292 	edit_variable(CALCULATOR->temporaryCategory().c_str(), NULL, mstruct, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")));
17293 }
17294 
new_unknown(GtkMenuItem *,gpointer)17295 void new_unknown(GtkMenuItem*, gpointer)
17296 {
17297 	edit_unknown(_("My Variables"), NULL, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")));
17298 }
17299 
17300 /*
17301 	add a new variable (from menu)
17302 */
new_variable(GtkMenuItem *,gpointer)17303 void new_variable(GtkMenuItem*, gpointer)
17304 {
17305 	edit_variable(_("My Variables"), NULL, NULL, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")));
17306 }
17307 
17308 /*
17309 	add a new matrix (from menu)
17310 */
new_matrix(GtkMenuItem *,gpointer)17311 void new_matrix(GtkMenuItem*, gpointer)
17312 {
17313 	edit_matrix(_("Matrices"), NULL, NULL, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")), FALSE);
17314 }
17315 /*
17316 	add a new vector (from menu)
17317 */
new_vector(GtkMenuItem *,gpointer)17318 void new_vector(GtkMenuItem*, gpointer)
17319 {
17320 	edit_matrix(_("Vectors"), NULL, NULL, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")), TRUE);
17321 }
17322 
is_number(const gchar * expr)17323 bool is_number(const gchar *expr) {
17324 	string str = CALCULATOR->unlocalizeExpression(expr, evalops.parse_options);
17325 	CALCULATOR->parseSigns(str);
17326 	for(size_t i = 0; i < str.length(); i++) {
17327 		if(is_not_in(NUMBER_ELEMENTS, str[i]) && (i > 0 || str.length() == 1 || is_not_in(MINUS PLUS, str[0]))) return false;
17328 	}
17329 	return true;
17330 }
last_is_number(const gchar * expr)17331 bool last_is_number(const gchar *expr) {
17332 	string str = CALCULATOR->unlocalizeExpression(expr, evalops.parse_options);
17333 	CALCULATOR->parseSigns(str);
17334 	if(str.empty()) return false;
17335 	return is_not_in(OPERATORS SPACES SEXADOT DOT LEFT_VECTOR_WRAP LEFT_PARENTHESIS COMMAS, str[str.length() - 1]);
17336 }
17337 
17338 /*
17339 	insert function when button clicked
17340 */
insertButtonFunction(MathFunction * f,bool save_to_recent=false,bool apply_to_stack=true)17341 void insertButtonFunction(MathFunction *f, bool save_to_recent = false, bool apply_to_stack = true) {
17342 	if(!f) return;
17343 	if(!CALCULATOR->stillHasFunction(f)) return;
17344 	if(rpn_mode && apply_to_stack && (f->minargs() <= 1 || (int) CALCULATOR->RPNStackSize() >= f->minargs())) {
17345 		calculateRPN(f);
17346 		return;
17347 	}
17348 
17349 	if(f->minargs() > 2) return insert_function(f, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")), save_to_recent);
17350 
17351 	bool b_bitrot = (f->referenceName() == "bitrot");
17352 
17353 	const ExpressionName *ename = &f->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext);
17354 	Argument *arg = f->getArgumentDefinition(1);
17355 	Argument *arg2 = f->getArgumentDefinition(2);
17356 	bool b_text = (arg && arg->type() == ARGUMENT_TYPE_TEXT);
17357 	bool b_text2 = (arg2 && arg2->type() == ARGUMENT_TYPE_TEXT);
17358 	GtkTextIter istart, iend, ipos;
17359 	gtk_text_buffer_get_start_iter(expressionbuffer, &istart);
17360 	gtk_text_buffer_get_end_iter(expressionbuffer, &iend);
17361 	gchar *expr = gtk_text_buffer_get_text(expressionbuffer, &istart, &iend, FALSE);
17362 	GtkTextMark *mpos = gtk_text_buffer_get_insert(expressionbuffer);
17363 	gtk_text_buffer_get_iter_at_mark(expressionbuffer, &ipos, mpos);
17364 	if(!gtk_text_buffer_get_has_selection(expressionbuffer) && gtk_text_iter_is_end(&ipos)) {
17365 		if(!rpn_mode && chain_mode) {
17366 			string str;
17367 			GtkTextIter ibegin;
17368 			gtk_text_buffer_get_end_iter(expressionbuffer, &ibegin);
17369 			gchar *p = expr + strlen(expr), *prev_p = p;
17370 			int nr_of_p = 0;
17371 			bool prev_plusminus = false;
17372 			while(p != expr) {
17373 				p = g_utf8_prev_char(p);
17374 				if(p[0] == LEFT_PARENTHESIS_CH) {
17375 					if(nr_of_p == 0) {
17376 						if(!prev_plusminus) {gtk_text_iter_backward_char(&ibegin);}
17377 						break;
17378 					}
17379 					nr_of_p--;
17380 				} else if(p[0] == RIGHT_PARENTHESIS_CH) {
17381 					if(nr_of_p == 0 && prev_p != expr + strlen(expr)) {
17382 						if(prev_plusminus) {gtk_text_iter_forward_char(&ibegin);}
17383 						break;
17384 					}
17385 					nr_of_p++;
17386 				} else if(nr_of_p == 0) {
17387 					if(p[0] < 0) {
17388 						for(size_t i = 0; p + i < prev_p; i++) str += p[i];
17389 						CALCULATOR->parseSigns(str);
17390 						if(!str.empty() && str[0] > 0) {
17391 							if(is_in("+-", str[0])) {
17392 								prev_plusminus = true;
17393 							} else if(is_in("*/&|=><^", str[0])) {
17394 								break;
17395 							} else if(prev_plusminus) {
17396 								gtk_text_iter_forward_char(&ibegin);
17397 								break;
17398 							}
17399 						}
17400 					} else if(is_in("+-", p[0])) {
17401 						prev_plusminus = true;
17402 					} else if(is_in("*/&|=><^", p[0])) {
17403 						break;
17404 					} else if(prev_plusminus) {
17405 						gtk_text_iter_forward_char(&ibegin);
17406 						break;
17407 					}
17408 				}
17409 				gtk_text_iter_backward_char(&ibegin);
17410 				prev_p = p;
17411 			}
17412 			gtk_text_buffer_select_range(expressionbuffer, &ibegin, &iend);
17413 		} else if(last_is_number(expr)) {
17414 			// special case: the user just entered a number, then select all, so that it gets executed
17415 			gtk_text_buffer_select_range(expressionbuffer, &istart, &iend);
17416 		}
17417 	}
17418 	string str2;
17419 	int index = 2;
17420 	if(b_bitrot || f == CALCULATOR->f_bitcmp) {
17421 		Argument *arg3 = f->getArgumentDefinition(3);
17422 		Argument *arg4 = NULL;
17423 		if(b_bitrot) {
17424 			arg4 = arg2;
17425 			arg2 = arg3;
17426 			arg3 = f->getArgumentDefinition(4);
17427 		}
17428 		if(!arg2 || !arg3 || (b_bitrot && !arg4)) return;
17429 		gtk_text_buffer_get_selection_bounds(expressionbuffer, &istart, &iend);
17430 		GtkWidget *dialog = gtk_dialog_new_with_buttons(f->title(true).c_str(), GTK_WINDOW(mainwindow), (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT), _("_Cancel"), GTK_RESPONSE_CANCEL, _("_OK"), GTK_RESPONSE_OK, NULL);
17431 		gtk_container_set_border_width(GTK_CONTAINER(dialog), 6);
17432 		GtkWidget *grid = gtk_grid_new();
17433 		gtk_grid_set_row_homogeneous(GTK_GRID(grid), TRUE);
17434 		gtk_grid_set_column_spacing(GTK_GRID(grid), 12);
17435 		gtk_container_set_border_width(GTK_CONTAINER(grid), 6);
17436 		gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), grid);
17437 		GtkWidget *w3 = NULL;
17438 		if(b_bitrot) {
17439 			GtkWidget *label2 = gtk_label_new(arg4->name().c_str());
17440 			gtk_widget_set_halign(label2, GTK_ALIGN_START);
17441 			gtk_grid_attach(GTK_GRID(grid), label2, 0, 0, 1, 1);
17442 			glong min = LONG_MIN, max = LONG_MAX;
17443 			if(arg4->type() == ARGUMENT_TYPE_INTEGER) {
17444 				IntegerArgument *iarg = (IntegerArgument*) arg4;
17445 				if(iarg->min()) {
17446 					min = iarg->min()->lintValue();
17447 				}
17448 				if(iarg->max()) {
17449 					max = iarg->max()->lintValue();
17450 				}
17451 			}
17452 			w3 = gtk_spin_button_new_with_range(min, max, 1);
17453 			gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(w3), evalops.parse_options.base != BASE_DECIMAL);
17454 			gtk_entry_set_alignment(GTK_ENTRY(w3), 1.0);
17455 			g_signal_connect(G_OBJECT(w3), "input", G_CALLBACK(on_function_int_input), NULL);
17456 			g_signal_connect(G_OBJECT(w3), "key-press-event", G_CALLBACK(on_math_entry_key_press_event), NULL);
17457 			if(!f->getDefaultValue(index).empty()) {
17458 				gtk_spin_button_set_value(GTK_SPIN_BUTTON(w3), s2i(f->getDefaultValue(index)));
17459 			} else if(!arg2->zeroForbidden() && min <= 0 && max >= 0) {
17460 				gtk_spin_button_set_value(GTK_SPIN_BUTTON(w3), 0);
17461 			} else {
17462 				if(max < 0) {
17463 					gtk_spin_button_set_value(GTK_SPIN_BUTTON(w3), max);
17464 				} else if(min <= 1) {
17465 					gtk_spin_button_set_value(GTK_SPIN_BUTTON(w3), 1);
17466 				} else {
17467 					gtk_spin_button_set_value(GTK_SPIN_BUTTON(w3), min);
17468 				}
17469 			}
17470 			gtk_grid_attach(GTK_GRID(grid), w3, 1, 0, 1, 1);
17471 		}
17472 		GtkWidget *label = gtk_label_new(arg2->name().c_str());
17473 		gtk_widget_set_halign(label, GTK_ALIGN_START);
17474 		gtk_grid_attach(GTK_GRID(grid), label, 0, b_bitrot ? 1 : 0, 1, 1);
17475 		GtkWidget *w1 = gtk_combo_box_text_new();
17476 		gtk_widget_set_hexpand(w1, TRUE);
17477 		gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(w1), "8");
17478 		gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(w1), "16");
17479 		gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(w1), "32");
17480 		gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(w1), "64");
17481 		gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(w1), "128");
17482 		gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(w1), "256");
17483 		gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(w1), "512");
17484 		gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(w1), "1024");
17485 		switch(default_bits) {
17486 			case 8: {gtk_combo_box_set_active(GTK_COMBO_BOX(w1), 0); break;}
17487 			case 16: {gtk_combo_box_set_active(GTK_COMBO_BOX(w1), 1); break;}
17488 			case 64: {gtk_combo_box_set_active(GTK_COMBO_BOX(w1), 3); break;}
17489 			case 128: {gtk_combo_box_set_active(GTK_COMBO_BOX(w1), 4); break;}
17490 			case 256: {gtk_combo_box_set_active(GTK_COMBO_BOX(w1), 5); break;}
17491 			case 512: {gtk_combo_box_set_active(GTK_COMBO_BOX(w1), 6); break;}
17492 			case 1024: {gtk_combo_box_set_active(GTK_COMBO_BOX(w1), 7); break;}
17493 			default: {gtk_combo_box_set_active(GTK_COMBO_BOX(w1), 2); break;}
17494 		}
17495 		gtk_grid_attach(GTK_GRID(grid), w1, 1, b_bitrot ? 1 : 0, 1, 1);
17496 		GtkWidget *w2 = gtk_check_button_new_with_label(arg3->name().c_str());
17497 		if(default_signed > 0 || (default_signed < 0 && b_bitrot)) {
17498 			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w2), TRUE);
17499 		} else {
17500 			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w2), FALSE);
17501 		}
17502 		gtk_widget_set_halign(w2, GTK_ALIGN_END);
17503 		gtk_widget_set_hexpand(w2, TRUE);
17504 		gtk_grid_attach(GTK_GRID(grid), w2, 0, b_bitrot ? 2 : 1, 2, 1);
17505 		gtk_widget_show_all(dialog);
17506 		if(gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_OK) {
17507 			g_free(expr);
17508 			gtk_widget_destroy(dialog);
17509 			gtk_text_buffer_select_range(expressionbuffer, &istart, &iend);
17510 			return;
17511 		}
17512 		gtk_text_buffer_select_range(expressionbuffer, &istart, &iend);
17513 		Number bits;
17514 		switch(gtk_combo_box_get_active(GTK_COMBO_BOX(w1))) {
17515 			case 0: {bits = 8; break;}
17516 			case 1: {bits = 16; break;}
17517 			case 3: {bits = 64; break;}
17518 			case 4: {bits = 128; break;}
17519 			case 5: {bits = 256; break;}
17520 			case 6: {bits = 512; break;}
17521 			case 7: {bits = 1024; break;}
17522 			default: {bits = 32; break;}
17523 		}
17524 		if(b_bitrot) {
17525 			if(evalops.parse_options.base != BASE_DECIMAL) {
17526 				Number nr(gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(w3)), 1);
17527 				str2 += print_with_evalops(nr);
17528 			} else {
17529 				str2 += gtk_entry_get_text(GTK_ENTRY(w3));
17530 			}
17531 			str2 += CALCULATOR->getComma();
17532 			str2 += " ";
17533 		}
17534 		str2 += print_with_evalops(bits);
17535 		str2 += CALCULATOR->getComma();
17536 		str2 += " ";
17537 		if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w2))) str2 += "1";
17538 		else str2 += "0";
17539 		default_bits = bits.intValue();
17540 		default_signed = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w2));
17541 		gtk_widget_destroy(dialog);
17542 	} else if(f->minargs() > 1 && ((arg2 && (f == CALCULATOR->f_root || arg2->type() == ARGUMENT_TYPE_INTEGER)) xor (arg && arg->type() == ARGUMENT_TYPE_INTEGER))) {
17543 		if(arg && arg->type() == ARGUMENT_TYPE_INTEGER) {
17544 			arg2 = arg;
17545 			index = 1;
17546 		}
17547 		gtk_text_buffer_get_selection_bounds(expressionbuffer, &istart, &iend);
17548 		GtkWidget *dialog = gtk_dialog_new_with_buttons(f->title(true).c_str(), GTK_WINDOW(mainwindow), (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT), _("_Cancel"), GTK_RESPONSE_CANCEL, _("_OK"), GTK_RESPONSE_OK, NULL);
17549 		gtk_container_set_border_width(GTK_CONTAINER(dialog), 6);
17550 		GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 12);
17551 		gtk_container_set_border_width(GTK_CONTAINER(hbox), 6);
17552 		gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), hbox);
17553 		GtkWidget *label = gtk_label_new(arg2->name().c_str());
17554 		gtk_widget_set_halign(label, GTK_ALIGN_START);
17555 		gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 0);
17556 		IntegerArgument *iarg = (IntegerArgument*) arg2;
17557 		glong min = LONG_MIN, max = LONG_MAX;
17558 		if(iarg->min()) {
17559 			min = iarg->min()->lintValue();
17560 		}
17561 		if(iarg->max()) {
17562 			max = iarg->max()->lintValue();
17563 		}
17564 		GtkWidget *entry = gtk_spin_button_new_with_range(min, max, 1);
17565 		gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(entry), evalops.parse_options.base != BASE_DECIMAL);
17566 		gtk_entry_set_alignment(GTK_ENTRY(entry), 1.0);
17567 		g_signal_connect(G_OBJECT(entry), "key-press-event", G_CALLBACK(on_math_entry_key_press_event), NULL);
17568 		g_signal_connect(GTK_SPIN_BUTTON(entry), "input", G_CALLBACK(on_function_int_input), NULL);
17569 		if(!f->getDefaultValue(index).empty()) {
17570 			gtk_spin_button_set_value(GTK_SPIN_BUTTON(entry), s2i(f->getDefaultValue(index)));
17571 		} else if(f == CALCULATOR->f_root) {
17572 			gtk_spin_button_set_value(GTK_SPIN_BUTTON(entry), 2);
17573 		} else if(!arg2->zeroForbidden() && min <= 0 && max >= 0) {
17574 			gtk_spin_button_set_value(GTK_SPIN_BUTTON(entry), 0);
17575 		} else {
17576 			if(max < 0) {
17577 				gtk_spin_button_set_value(GTK_SPIN_BUTTON(entry), max);
17578 			} else if(min <= 1) {
17579 				gtk_spin_button_set_value(GTK_SPIN_BUTTON(entry), 1);
17580 			} else {
17581 				gtk_spin_button_set_value(GTK_SPIN_BUTTON(entry), min);
17582 			}
17583 		}
17584 		gtk_box_pack_end(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
17585 		gtk_widget_show_all(dialog);
17586 		if(gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_OK) {
17587 			g_free(expr);
17588 			gtk_widget_destroy(dialog);
17589 			gtk_text_buffer_select_range(expressionbuffer, &istart, &iend);
17590 			return;
17591 		}
17592 		gtk_text_buffer_select_range(expressionbuffer, &istart, &iend);
17593 		if(evalops.parse_options.base != BASE_DECIMAL) {
17594 			Number nr(gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(entry)), 1);
17595 			str2 = print_with_evalops(nr);
17596 		} else {
17597 			str2 = gtk_entry_get_text(GTK_ENTRY(entry));
17598 		}
17599 		gtk_widget_destroy(dialog);
17600 	}
17601 	if(gtk_text_buffer_get_has_selection(expressionbuffer)) {
17602 		gtk_text_buffer_get_selection_bounds(expressionbuffer, &istart, &iend);
17603 		// execute expression, if the whole expression was selected, no need for additional enter
17604 		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)));
17605 		//set selection as argument
17606 		gchar *gstr = gtk_text_buffer_get_text(expressionbuffer, &istart, &iend, FALSE);
17607 		string str = gstr;
17608 		remove_blank_ends(str);
17609 		gchar *gstr2;
17610 		if(b_text && str.length() > 0 && (str[0] == '\"' || str[0] == '\'')) b_text = false;
17611 		if(f->minargs() > 1 || !str2.empty()) {
17612 			if(b_text2) {
17613 				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);
17614 				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());
17615 			} else {
17616 				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);
17617 				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());
17618 			}
17619 		} else {
17620 			gstr2 = g_strdup_printf(b_text ? "%s(\"%s\")" : "%s(%s)", ename->name.c_str(), gstr);
17621 		}
17622 		insert_text(gstr2);
17623 		if(f->minargs() > 1) {
17624 			GtkTextIter iter;
17625 			gtk_text_buffer_get_iter_at_mark(expressionbuffer, &iter, gtk_text_buffer_get_insert(expressionbuffer));
17626 			gtk_text_iter_backward_chars(&iter, b_text2 ? 2 : 1);
17627 			gtk_text_buffer_place_cursor(expressionbuffer, &iter);
17628 		}
17629 		if(do_exec) execute_expression();
17630 		g_free(gstr);
17631 		g_free(gstr2);
17632 	} else {
17633 		if(f->minargs() > 1 || !str2.empty()) {
17634 			gchar *gstr2;
17635 			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());
17636 			else gstr2 = g_strdup_printf(b_text ? "%s(\"\"%s %s)" : "%s(%s %s)", ename->name.c_str(), CALCULATOR->getComma().c_str(), str2.c_str());
17637 			insert_text(gstr2);
17638 			GtkTextIter iter;
17639 			gtk_text_buffer_get_iter_at_mark(expressionbuffer, &iter, gtk_text_buffer_get_insert(expressionbuffer));
17640 			if(index == 2) {
17641 				gtk_text_iter_backward_chars(&iter, g_utf8_strlen(str2.c_str(), -1) + (b_text ? 4 : 3));
17642 			} else {
17643 				gtk_text_iter_backward_chars(&iter, b_text ? 2 : 1);
17644 			}
17645 			gtk_text_buffer_place_cursor(expressionbuffer, &iter);
17646 			g_free(gstr2);
17647 		} else {
17648 			gchar *gstr2;
17649 			gstr2 = g_strdup_printf(b_text ? "%s(\"\")" : "%s()", ename->name.c_str());
17650 			insert_text(gstr2);
17651 			GtkTextIter iter;
17652 			gtk_text_buffer_get_iter_at_mark(expressionbuffer, &iter, gtk_text_buffer_get_insert(expressionbuffer));
17653 			gtk_text_iter_backward_chars(&iter, b_text ? 2 : 1);
17654 			gtk_text_buffer_place_cursor(expressionbuffer, &iter);
17655 			g_free(gstr2);
17656 		}
17657 	}
17658 	g_free(expr);
17659 	if(save_to_recent) function_inserted(f);
17660 }
insert_button_function(GtkMenuItem *,gpointer user_data)17661 void insert_button_function(GtkMenuItem*, gpointer user_data) {
17662 	insertButtonFunction((MathFunction*) user_data);
17663 }
insert_button_function_save(GtkMenuItem *,gpointer user_data)17664 void insert_button_function_save(GtkMenuItem*, gpointer user_data) {
17665 	insertButtonFunction((MathFunction*) user_data, true);
17666 }
insert_button_function_norpn(GtkMenuItem *,gpointer user_data)17667 void insert_button_function_norpn(GtkMenuItem*, gpointer user_data) {
17668 	insertButtonFunction((MathFunction*) user_data, true, false);
17669 }
insert_function_operator(MathFunction * f)17670 void insert_function_operator(MathFunction *f) {
17671 	if(rpn_mode || evalops.parse_options.parsing_mode == PARSING_MODE_RPN || is_at_beginning_of_expression()) {
17672 		insertButtonFunction(f);
17673 	} else if(f == CALCULATOR->f_mod) {
17674 		if(wrap_expression_selection() >= 0) insert_text(" mod ");
17675 		else insertButtonFunction(f);
17676 	} else if(f == CALCULATOR->f_rem) {
17677 		if(wrap_expression_selection() >= 0) insert_text(" rem ");
17678 		else insertButtonFunction(f);
17679 	} else {
17680 		insertButtonFunction(f);
17681 	}
17682 }
insert_function_operator(GtkMenuItem *,gpointer user_data)17683 void insert_function_operator(GtkMenuItem*, gpointer user_data) {
17684 	insert_function_operator((MathFunction*) user_data);
17685 }
17686 
17687 /*
17688 	Button clicked -- insert text (1,2,3,... +,-,...)
17689 */
button_pressed(GtkButton *,gpointer user_data)17690 void button_pressed(GtkButton*, gpointer user_data) {
17691 	insert_text((gchar*) user_data);
17692 }
17693 
17694 /*
17695 	variables, functions and units enabled/disabled from menu
17696 */
set_clean_mode(GtkMenuItem * w,gpointer)17697 void set_clean_mode(GtkMenuItem *w, gpointer) {
17698 	gboolean b = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
17699 	evalops.parse_options.functions_enabled = !b;
17700 	evalops.parse_options.variables_enabled = !b;
17701 	evalops.parse_options.units_enabled = !b;
17702 	expression_format_updated(true);
17703 }
17704 
17705 /*
17706 	Open variable manager
17707 */
manage_variables()17708 void manage_variables() {
17709 	GtkWidget *dialog = get_variables_dialog();
17710 	if(!gtk_widget_is_visible(dialog)) {
17711 		gtk_widget_grab_focus(tVariables);
17712 		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(variables_builder, "variables_entry_search")), "");
17713 		gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")));
17714 		gtk_widget_show(dialog);
17715 	}
17716 	gtk_window_present_with_time(GTK_WINDOW(dialog), GDK_CURRENT_TIME);
17717 }
17718 
17719 /*
17720 	Open function manager
17721 */
manage_functions()17722 void manage_functions() {
17723 	GtkWidget *dialog = get_functions_dialog();
17724 	if(!gtk_widget_is_visible(dialog)) {
17725 		gtk_widget_grab_focus(tFunctions);
17726 		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(functions_builder, "functions_entry_search")), "");
17727 		gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")));
17728 		gtk_widget_show(dialog);
17729 	}
17730 	gtk_window_present_with_time(GTK_WINDOW(dialog), GDK_CURRENT_TIME);
17731 }
17732 
17733 /*
17734 	Open unit manager
17735 */
manage_units()17736 void manage_units() {
17737 	GtkWidget *dialog = get_units_dialog();
17738 	if(!gtk_widget_is_visible(dialog)) {
17739 		gtk_widget_grab_focus(tUnits);
17740 		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(units_builder, "units_entry_search")), "");
17741 		gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")));
17742 		gtk_widget_show(dialog);
17743 	}
17744 	gtk_window_present_with_time(GTK_WINDOW(dialog), GDK_CURRENT_TIME);
17745 }
17746 
17747 /*
17748 	do the conversion in unit manager
17749 */
convert_in_wUnits(int toFrom)17750 void convert_in_wUnits(int toFrom) {
17751 	//units
17752 	Unit *uFrom = get_selected_unit();
17753 	Unit *uTo = get_selected_to_unit();
17754 
17755 	if(uFrom && uTo) {
17756 		//values
17757 		const gchar *fromValue = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(units_builder, "units_entry_from_val")));
17758 		const gchar *toValue = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(units_builder, "units_entry_to_val")));
17759 		old_fromValue = fromValue;
17760 		old_toValue = toValue;
17761 		//determine conversion direction
17762 		bool b = false;
17763 		if(toFrom > 0) {
17764 			if(CALCULATOR->timedOutString() == toValue) return;
17765 			if(uFrom == uTo) {
17766 				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(units_builder, "units_entry_from_val")), toValue);
17767 			} else {
17768 				EvaluationOptions eo;
17769 				eo.approximation = APPROXIMATION_APPROXIMATE;
17770 				eo.parse_options = evalops.parse_options;
17771 				eo.parse_options.base = 10;
17772 				if(eo.parse_options.parsing_mode == PARSING_MODE_RPN || eo.parse_options.parsing_mode == PARSING_MODE_CHAIN) eo.parse_options.parsing_mode = PARSING_MODE_ADAPTIVE;
17773 				eo.parse_options.read_precision = DONT_READ_PRECISION;
17774 				PrintOptions po;
17775 				po.is_approximate = &b;
17776 				po.number_fraction_format = FRACTION_DECIMAL;
17777 				po.interval_display = INTERVAL_DISPLAY_SIGNIFICANT_DIGITS;
17778 				CALCULATOR->resetExchangeRatesUsed();
17779 				do_timeout = false;
17780 				MathStructure v_mstruct = CALCULATOR->convert(CALCULATOR->unlocalizeExpression(toValue, eo.parse_options), uTo, uFrom, 1500, eo);
17781 				if(!v_mstruct.isAborted() && check_exchange_rates(get_units_dialog())) v_mstruct = CALCULATOR->convert(CALCULATOR->unlocalizeExpression(toValue, eo.parse_options), uTo, uFrom, 1500, eo);
17782 				if(v_mstruct.isAborted()) {
17783 					old_fromValue = CALCULATOR->timedOutString();
17784 				} else {
17785 					old_fromValue = CALCULATOR->print(v_mstruct, 300, po);
17786 				}
17787 				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(units_builder, "units_entry_from_val")), old_fromValue.c_str());
17788 				b = b || v_mstruct.isApproximate();
17789 				display_errors(NULL, GTK_WIDGET(gtk_builder_get_object(units_builder, "units_dialog")));
17790 				do_timeout = true;
17791 			}
17792 		} else {
17793 			if(CALCULATOR->timedOutString() == fromValue) return;
17794 			if(uFrom == uTo) {
17795 				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(units_builder, "units_entry_to_val")), fromValue);
17796 			} else {
17797 				EvaluationOptions eo;
17798 				eo.approximation = APPROXIMATION_APPROXIMATE;
17799 				eo.parse_options = evalops.parse_options;
17800 				eo.parse_options.base = 10;
17801 				if(eo.parse_options.parsing_mode == PARSING_MODE_RPN || eo.parse_options.parsing_mode == PARSING_MODE_CHAIN) eo.parse_options.parsing_mode = PARSING_MODE_ADAPTIVE;
17802 				eo.parse_options.read_precision = DONT_READ_PRECISION;
17803 				PrintOptions po;
17804 				po.is_approximate = &b;
17805 				po.number_fraction_format = FRACTION_DECIMAL;
17806 				po.interval_display = INTERVAL_DISPLAY_SIGNIFICANT_DIGITS;
17807 				CALCULATOR->resetExchangeRatesUsed();
17808 				do_timeout = false;
17809 				MathStructure v_mstruct = CALCULATOR->convert(CALCULATOR->unlocalizeExpression(fromValue, eo.parse_options), uFrom, uTo, 1500, eo);
17810 				if(!v_mstruct.isAborted() && check_exchange_rates(get_units_dialog())) v_mstruct = CALCULATOR->convert(CALCULATOR->unlocalizeExpression(fromValue, eo.parse_options), uFrom, uTo, 1500, eo);
17811 				if(v_mstruct.isAborted()) {
17812 					old_toValue = CALCULATOR->timedOutString();
17813 				} else {
17814 					old_toValue = CALCULATOR->print(v_mstruct, 300, po);
17815 				}
17816 				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(units_builder, "units_entry_to_val")), old_toValue.c_str());
17817 				b = b || v_mstruct.isApproximate();
17818 				display_errors(NULL, GTK_WIDGET(gtk_builder_get_object(units_builder, "units_dialog")));
17819 				do_timeout = true;
17820 			}
17821 		}
17822 		if(b && printops.use_unicode_signs && can_display_unicode_string_function(SIGN_ALMOST_EQUAL, (void*) gtk_builder_get_object(units_builder, "units_label_equals"))) {
17823 			gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(units_builder, "units_label_equals")), SIGN_ALMOST_EQUAL);
17824 		} else {
17825 			gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(units_builder, "units_label_equals")), "=");
17826 		}
17827 	}
17828 }
17829 
17830 /*
17831 	save definitions to ~/.conf/qalculate/qalculate.cfg
17832 	the hard work is done in the Calculator class
17833 */
save_defs()17834 void save_defs() {
17835 	if(!CALCULATOR->saveDefinitions()) {
17836 		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"));
17837 		gtk_dialog_run(GTK_DIALOG(edialog));
17838 		gtk_widget_destroy(edialog);
17839 	}
17840 }
17841 
17842 /*
17843 	save mode to file
17844 */
save_mode()17845 void save_mode() {
17846 	save_preferences(true);
17847 }
17848 
17849 /*
17850 	remember current mode
17851 */
set_saved_mode()17852 void set_saved_mode() {
17853 	modes[1].precision = CALCULATOR->getPrecision();
17854 	modes[1].interval = CALCULATOR->usesIntervalArithmetic();
17855 	modes[1].adaptive_interval_display = adaptive_interval_display;
17856 	modes[1].variable_units_enabled = CALCULATOR->variableUnitsEnabled();
17857 	modes[1].po = printops;
17858 	modes[1].po.allow_factorization = (evalops.structuring == STRUCTURING_FACTORIZE);
17859 	modes[1].eo = evalops;
17860 	modes[1].at = CALCULATOR->defaultAssumptions()->type();
17861 	modes[1].as = CALCULATOR->defaultAssumptions()->sign();
17862 	modes[1].rpn_mode = rpn_mode;
17863 	modes[1].autocalc = auto_calculate;
17864 	modes[1].chain_mode = chain_mode;
17865 	modes[1].keypad = visible_keypad;
17866 	modes[1].custom_output_base = CALCULATOR->customOutputBase();
17867 	modes[1].custom_input_base = CALCULATOR->customInputBase();
17868 	modes[1].complex_angle_form = complex_angle_form;
17869 }
17870 
save_mode_as(string name,bool * new_mode=NULL)17871 size_t save_mode_as(string name, bool *new_mode = NULL) {
17872 	remove_blank_ends(name);
17873 	size_t index = 0;
17874 	for(; index < modes.size(); index++) {
17875 		if(modes[index].name == name) {
17876 			if(new_mode) *new_mode = false;
17877 			break;
17878 		}
17879 	}
17880 	if(index >= modes.size()) {
17881 		modes.resize(modes.size() + 1);
17882 		index = modes.size() - 1;
17883 		if(new_mode) *new_mode = true;
17884 	}
17885 	modes[index].po = printops;
17886 	modes[index].po.allow_factorization = (evalops.structuring == STRUCTURING_FACTORIZE);
17887 	modes[index].eo = evalops;
17888 	modes[index].precision = CALCULATOR->getPrecision();
17889 	modes[index].interval = CALCULATOR->usesIntervalArithmetic();
17890 	modes[index].adaptive_interval_display = adaptive_interval_display;
17891 	modes[index].variable_units_enabled = CALCULATOR->variableUnitsEnabled();
17892 	modes[index].at = CALCULATOR->defaultAssumptions()->type();
17893 	modes[index].as = CALCULATOR->defaultAssumptions()->sign();
17894 	modes[index].name = name;
17895 	modes[index].rpn_mode = rpn_mode;
17896 	modes[index].autocalc = auto_calculate;
17897 	modes[index].chain_mode = chain_mode;
17898 	modes[index].keypad = visible_keypad;
17899 	modes[index].custom_output_base = CALCULATOR->customOutputBase();
17900 	modes[index].custom_input_base = CALCULATOR->customInputBase();
17901 	modes[index].complex_angle_form = complex_angle_form;
17902 	return index;
17903 }
17904 
load_mode(const mode_struct & mode)17905 void load_mode(const mode_struct &mode) {
17906 	block_result_update++;
17907 	block_expression_execution++;
17908 	block_display_parse++;
17909 	if(mode.keypad == 1) {
17910 		programming_inbase = 0;
17911 		programming_outbase = 0;
17912 	}
17913 	if(mode.name == _("Preset") || mode.name == _("Default")) current_mode = "";
17914 	else current_mode = mode.name;
17915 	update_window_title();
17916 	CALCULATOR->setCustomOutputBase(mode.custom_output_base);
17917 	CALCULATOR->setCustomInputBase(mode.custom_input_base);
17918 	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.chain_mode, mode.complex_angle_form, false);
17919 	evalops.approximation = mode.eo.approximation;
17920 	block_result_update--;
17921 	block_expression_execution--;
17922 	block_display_parse--;
17923 	printops.allow_factorization = (evalops.structuring == STRUCTURING_FACTORIZE);
17924 	update_message_print_options();
17925 	update_status_text();
17926 	auto_calculate = mode.autocalc;
17927 	chain_mode = mode.chain_mode;
17928 	complex_angle_form = mode.complex_angle_form;
17929 	set_rpn_mode(mode.rpn_mode);
17930 	GtkTextIter istart, iend;
17931 	gtk_text_buffer_get_start_iter(expressionbuffer, &istart);
17932 	gtk_text_buffer_get_end_iter(expressionbuffer, &iend);
17933 	gchar *gtext = gtk_text_buffer_get_text(expressionbuffer, &istart, &iend, FALSE);
17934 	string str = gtext;
17935 	g_free(gtext);
17936 	if(auto_calculate && !rpn_mode) {
17937 		do_auto_calc();
17938 	} else if(rpn_mode || expression_has_changed || str.find_first_not_of(SPACES) == string::npos) {
17939 		setResult(NULL, true, false, false);
17940 	} else {
17941 		execute_expression(false);
17942 	}
17943 	expression_has_changed2 = true;
17944 	display_parse_status();
17945 }
load_mode(string name)17946 void load_mode(string name) {
17947 	for(size_t i = 0; i < modes.size(); i++) {
17948 		if(modes[i].name == name) {
17949 			load_mode(modes[i]);
17950 			return;
17951 		}
17952 	}
17953 }
load_mode(size_t index)17954 void load_mode(size_t index) {
17955 	if(index < modes.size()) {
17956 		load_mode(modes[index]);
17957 	}
17958 }
17959 
on_popup_menu_item_completion_level_toggled(GtkCheckMenuItem * w,gpointer p)17960 void on_popup_menu_item_completion_level_toggled(GtkCheckMenuItem *w, gpointer p) {
17961 	if(!gtk_check_menu_item_get_active(w)) return;
17962 	int completion_level = GPOINTER_TO_INT(p);
17963 	enable_completion = completion_level > 0;
17964 	enable_completion2 = completion_level > 2;
17965 	if(completion_level > 1) completion_min = 1;
17966 	else completion_min = 2;
17967 	if(completion_level > 3) completion_min2 = 1;
17968 	else completion_min2 = 2;
17969 }
on_popup_menu_item_completion_delay_toggled(GtkCheckMenuItem * w,gpointer)17970 void on_popup_menu_item_completion_delay_toggled(GtkCheckMenuItem *w, gpointer) {
17971 	if(gtk_check_menu_item_get_active(w)) completion_delay = 500;
17972 	else completion_delay = 0;
17973 }
on_popup_menu_item_custom_completion_activated(GtkMenuItem *,gpointer)17974 void on_popup_menu_item_custom_completion_activated(GtkMenuItem*, gpointer) {
17975 	GtkWidget *dialog = get_preferences_dialog();
17976 	gtk_notebook_set_current_page(GTK_NOTEBOOK(gtk_builder_get_object(preferences_builder, "preferences_tabs")), 3);
17977 	gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")));
17978 	gtk_widget_show(dialog);
17979 }
on_popup_menu_item_read_precision_activate(GtkMenuItem * w,gpointer)17980 void on_popup_menu_item_read_precision_activate(GtkMenuItem *w, gpointer) {
17981 	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)));
17982 }
on_popup_menu_item_limit_implicit_multiplication_activate(GtkMenuItem * w,gpointer)17983 void on_popup_menu_item_limit_implicit_multiplication_activate(GtkMenuItem *w, gpointer) {
17984 	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)));
17985 }
on_popup_menu_item_adaptive_parsing_activate(GtkMenuItem * w,gpointer)17986 void on_popup_menu_item_adaptive_parsing_activate(GtkMenuItem *w, gpointer) {
17987 	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)));
17988 }
on_popup_menu_item_chain_syntax_activate(GtkMenuItem * w,gpointer)17989 void on_popup_menu_item_chain_syntax_activate(GtkMenuItem *w, gpointer) {
17990 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_chain_syntax")), gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)));
17991 }
on_popup_menu_item_ignore_whitespace_activate(GtkMenuItem * w,gpointer)17992 void on_popup_menu_item_ignore_whitespace_activate(GtkMenuItem *w, gpointer) {
17993 	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)));
17994 }
on_popup_menu_item_no_special_implicit_multiplication_activate(GtkMenuItem * w,gpointer)17995 void on_popup_menu_item_no_special_implicit_multiplication_activate(GtkMenuItem *w, gpointer) {
17996 	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)));
17997 }
on_popup_menu_item_rpn_syntax_activate(GtkMenuItem * w,gpointer)17998 void on_popup_menu_item_rpn_syntax_activate(GtkMenuItem *w, gpointer) {
17999 	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)));
18000 }
on_popup_menu_item_rpn_mode_activate(GtkMenuItem * w,gpointer)18001 void on_popup_menu_item_rpn_mode_activate(GtkMenuItem *w, gpointer) {
18002 	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)));
18003 }
expression_set_from_undo_buffer()18004 void expression_set_from_undo_buffer() {
18005 	if(undo_index < expression_undo_buffer.size()) {
18006 		string str_old = get_expression_text();
18007 		string str_new = expression_undo_buffer[undo_index];
18008 		if(str_old == str_new) return;
18009 		size_t i;
18010 		block_add_to_undo++;
18011 		GtkTextIter istart, iend;
18012 		if(str_old.length() > str_new.length()) {
18013 			if((i = str_old.find(str_new)) != string::npos) {
18014 				if(i != 0) {
18015 					gtk_text_buffer_get_iter_at_offset(expressionbuffer, &iend, g_utf8_strlen(str_old.c_str(), i));
18016 					gtk_text_buffer_get_start_iter(expressionbuffer, &istart);
18017 					gtk_text_buffer_delete(expressionbuffer, &istart, &iend);
18018 				}
18019 				if(i + str_new.length() < str_old.length()) {
18020 					gtk_text_buffer_get_iter_at_offset(expressionbuffer, &istart, g_utf8_strlen(str_new.c_str(), -1));
18021 					gtk_text_buffer_get_end_iter(expressionbuffer, &iend);
18022 					gtk_text_buffer_delete(expressionbuffer, &istart, &iend);
18023 				}
18024 				block_add_to_undo--;
18025 				return;
18026 			}
18027 			for(i = 0; i < str_new.length(); i++) {
18028 				if(str_new[i] != str_old[i]) {
18029 					if(i == 0) break;
18030 					string str_test = str_old.substr(0, i);
18031 					str_test += str_old.substr(i + str_old.length() - str_new.length());
18032 					if(str_test == str_new) {
18033 						gtk_text_buffer_get_iter_at_offset(expressionbuffer, &istart, g_utf8_strlen(str_old.c_str(), i));
18034 						gtk_text_buffer_get_iter_at_offset(expressionbuffer, &iend, g_utf8_strlen(str_old.c_str(), i + str_old.length() - str_new.length()));
18035 						gtk_text_buffer_delete(expressionbuffer, &istart, &iend);
18036 						block_add_to_undo--;
18037 						return;
18038 					}
18039 					if(str_new.length() + 1 == str_old.length()) break;
18040 					str_test = str_old.substr(0, i);
18041 					str_test += str_old.substr(i + str_old.length() - str_new.length() - 1);
18042 					size_t i2 = i;
18043 					while((i2 = str_test.find(')', i2 + 1)) != string::npos) {
18044 						string str_test2 = str_test;
18045 						str_test2.erase(str_test2.begin() + i2);
18046 						if(str_test2 == str_new) {
18047 							gtk_text_buffer_get_iter_at_offset(expressionbuffer, &istart, g_utf8_strlen(str_old.c_str(), i));
18048 							gtk_text_buffer_get_iter_at_offset(expressionbuffer, &iend, g_utf8_strlen(str_old.c_str(), i + str_old.length() - str_new.length() - 1));
18049 							gtk_text_buffer_delete(expressionbuffer, &istart, &iend);
18050 							gtk_text_buffer_get_iter_at_offset(expressionbuffer, &istart, g_utf8_strlen(str_old.c_str(), i2));
18051 							iend = istart;
18052 							gtk_text_iter_forward_char(&iend);
18053 							gtk_text_buffer_delete(expressionbuffer, &istart, &iend);
18054 							block_add_to_undo--;
18055 							return;
18056 						}
18057 					}
18058 					break;
18059 				}
18060 			}
18061 		} else if(str_new.length() > str_old.length()) {
18062 			if((i = str_new.find(str_old)) != string::npos) {
18063 				if(i + str_old.length() < str_new.length()) {
18064 					gtk_text_buffer_get_end_iter(expressionbuffer, &iend);
18065 					gtk_text_buffer_insert(expressionbuffer, &iend, str_new.substr(i + str_old.length(), str_new.length() - (i + str_old.length())).c_str(), -1);
18066 				}
18067 				if(i > 0) {
18068 					gtk_text_buffer_get_start_iter(expressionbuffer, &istart);
18069 					gtk_text_buffer_insert(expressionbuffer, &istart, str_new.substr(0, i).c_str(), -1);
18070 				}
18071 				block_add_to_undo--;
18072 				return;
18073 			}
18074 			for(i = 0; i < str_old.length(); i++) {
18075 				if(str_old[i] != str_new[i]) {
18076 					if(i == 0) break;
18077 					string str_test = str_new.substr(0, i);
18078 					str_test += str_new.substr(i + str_new.length() - str_old.length());
18079 					if(str_test == str_old) {
18080 						gtk_text_buffer_get_iter_at_offset(expressionbuffer, &istart, g_utf8_strlen(str_new.c_str(), i));
18081 						gtk_text_buffer_insert(expressionbuffer, &istart, str_new.substr(i, str_new.length() - str_old.length()).c_str(), -1);
18082 						block_add_to_undo--;
18083 						return;
18084 					}
18085 					if(str_old.length() + 1 == str_new.length()) break;
18086 					str_test = str_new.substr(0, i);
18087 					str_test += str_new.substr(i + str_new.length() - str_old.length() - 1);
18088 					size_t i2 = i;
18089 					while((i2 = str_test.find(')', i2 + 1)) != string::npos) {
18090 						string str_test2 = str_test;
18091 						str_test2.erase(str_test2.begin() + i2);
18092 						if(str_test2 == str_old) {
18093 							gtk_text_buffer_get_iter_at_offset(expressionbuffer, &istart, g_utf8_strlen(str_new.c_str(), i));
18094 							gtk_text_buffer_insert(expressionbuffer, &istart, str_new.substr(i, str_new.length() - str_old.length() - 1).c_str(), -1);
18095 							gtk_text_buffer_get_iter_at_offset(expressionbuffer, &istart, g_utf8_strlen(str_new.c_str(), i2 + str_new.length() - str_old.length() - 1));
18096 							gtk_text_buffer_insert(expressionbuffer, &istart, ")", -1);
18097 							block_add_to_undo--;
18098 							return;
18099 						}
18100 					}
18101 					break;
18102 				}
18103 			}
18104 		}
18105 		gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(expressiontext), FALSE);
18106 		gtk_text_buffer_set_text(expressionbuffer, str_new.c_str(), -1);
18107 		gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(expressiontext), TRUE);
18108 		block_add_to_undo--;
18109 	}
18110 }
expression_undo()18111 void expression_undo() {
18112 	if(undo_index == 0) return;
18113 	undo_index--;
18114 	expression_set_from_undo_buffer();
18115 }
expression_redo()18116 void expression_redo() {
18117 	if(undo_index >= expression_undo_buffer.size() - 1) return;
18118 	undo_index++;
18119 	expression_set_from_undo_buffer();
18120 }
18121 
18122 bool block_popup_input_base = false;
on_popup_menu_item_input_base(GtkMenuItem * w,gpointer data)18123 void on_popup_menu_item_input_base(GtkMenuItem *w, gpointer data) {
18124 	if(block_popup_input_base) return;
18125 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
18126 	if(GPOINTER_TO_INT(data) == BASE_CUSTOM) {
18127 		GtkWidget *dialog = get_set_base_dialog();
18128 		gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")));
18129 		gtk_widget_show(dialog);
18130 		gtk_window_present_with_time(GTK_WINDOW(dialog), GDK_CURRENT_TIME);
18131 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_other")), TRUE);
18132 		gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(setbase_builder, "set_base_entry_input_other")));
18133 	} else {
18134 		evalops.parse_options.base = GPOINTER_TO_INT(data);
18135 		input_base_updated_from_menu();
18136 		update_keypad_bases();
18137 		expression_format_updated(false);
18138 		on_historyview_selection_changed(NULL, NULL);
18139 	}
18140 }
on_expressiontext_populate_popup(GtkTextView *,GtkMenu * menu,gpointer)18141 void on_expressiontext_populate_popup(GtkTextView*, GtkMenu *menu, gpointer) {
18142 	popup_menu_expressiontext = menu;
18143 	GtkWidget *item, *sub, *sub2;
18144 	GSList *group = NULL;
18145 	gchar *gstr;
18146 	sub = GTK_WIDGET(menu);
18147 	MENU_ITEM(_("Clear"), on_popup_menu_item_clear_activate)
18148 	gtk_accel_label_set_accel(GTK_ACCEL_LABEL(gtk_bin_get_child(GTK_BIN(item))), GDK_KEY_Escape, (GdkModifierType) 0);
18149 	if(expression_is_empty()) gtk_widget_set_sensitive(item, FALSE);
18150 	MENU_SEPARATOR
18151 	if(b_busy) {
18152 		MENU_ITEM(_("Abort"), on_popup_menu_item_abort_activate)
18153 		return;
18154 	}
18155 	MENU_ITEM(_("Undo"), expression_undo)
18156 	gtk_accel_label_set_accel(GTK_ACCEL_LABEL(gtk_bin_get_child(GTK_BIN(item))), GDK_KEY_z, (GdkModifierType) GDK_CONTROL_MASK);
18157 	if(undo_index == 0) gtk_widget_set_sensitive(item, FALSE);
18158 	MENU_ITEM(_("Redo"), expression_redo)
18159 	gtk_accel_label_set_accel(GTK_ACCEL_LABEL(gtk_bin_get_child(GTK_BIN(item))), GDK_KEY_z, (GdkModifierType) (GDK_SHIFT_MASK | GDK_CONTROL_MASK));
18160 	if(undo_index >= expression_undo_buffer.size() - 1) gtk_widget_set_sensitive(item, FALSE);
18161 	MENU_SEPARATOR
18162 	sub2 = sub;
18163 	SUBMENU_ITEM(_("Completion Mode"), sub2);
18164 	int completion_level = 0;
18165 	if(enable_completion) {
18166 		if(enable_completion2) {
18167 			if(completion_min2 > 1) completion_level = 3;
18168 			else completion_level = 4;
18169 		} else {
18170 			if(completion_min > 1) completion_level = 1;
18171 			else completion_level = 2;
18172 		}
18173 	}
18174 	for(gint i = 0; i < 5; i++) {
18175 		switch(i) {
18176 			case 1: {item = gtk_radio_menu_item_new_with_label(group, _("Limited strict completion")); break;}
18177 			case 2: {item = gtk_radio_menu_item_new_with_label(group, _("Strict completion")); break;}
18178 			case 3: {item = gtk_radio_menu_item_new_with_label(group, _("Limited full completion")); break;}
18179 			case 4: {item = gtk_radio_menu_item_new_with_label(group, _("Full completion")); break;}
18180 			default: {item = gtk_radio_menu_item_new_with_label(group, _("No completion"));}
18181 		}
18182 		group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(item));
18183 		gtk_widget_show(item);
18184 		if(i == completion_level) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), TRUE);
18185 		g_signal_connect(G_OBJECT(item), "toggled", G_CALLBACK(on_popup_menu_item_completion_level_toggled), GINT_TO_POINTER(i));
18186 		gtk_menu_shell_append(GTK_MENU_SHELL(sub), item);
18187 	}
18188 	MENU_SEPARATOR
18189 	CHECK_MENU_ITEM(_("Delayed completion"), on_popup_menu_item_completion_delay_toggled, completion_delay > 0)
18190 	MENU_SEPARATOR
18191 	MENU_ITEM(_("Customize completion…"), on_popup_menu_item_custom_completion_activated)
18192 	group = NULL;
18193 	SUBMENU_ITEM(_("Parsing Mode"), sub2);
18194 	POPUP_RADIO_MENU_ITEM(on_popup_menu_item_adaptive_parsing_activate, gtk_builder_get_object(main_builder, "menu_item_adaptive_parsing"))
18195 	POPUP_RADIO_MENU_ITEM(on_popup_menu_item_ignore_whitespace_activate, gtk_builder_get_object(main_builder, "menu_item_ignore_whitespace"))
18196 	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"))
18197 	POPUP_RADIO_MENU_ITEM(on_popup_menu_item_chain_syntax_activate, gtk_builder_get_object(main_builder, "menu_item_chain_syntax"))
18198 	POPUP_RADIO_MENU_ITEM(on_popup_menu_item_rpn_syntax_activate, gtk_builder_get_object(main_builder, "menu_item_rpn_syntax"))
18199 	MENU_SEPARATOR
18200 	POPUP_CHECK_MENU_ITEM(on_popup_menu_item_limit_implicit_multiplication_activate, gtk_builder_get_object(main_builder, "menu_item_limit_implicit_multiplication"))
18201 	POPUP_CHECK_MENU_ITEM(on_popup_menu_item_read_precision_activate, gtk_builder_get_object(main_builder, "menu_item_read_precision"))
18202 	POPUP_CHECK_MENU_ITEM(on_popup_menu_item_rpn_mode_activate, gtk_builder_get_object(main_builder, "menu_item_rpn_mode"))
18203 	SUBMENU_ITEM(_("Number Base"), sub2);
18204 	group = NULL;
18205 	block_popup_input_base = true;
18206 	RADIO_MENU_ITEM_WITH_INT(_("Binary"), on_popup_menu_item_input_base, evalops.parse_options.base == 2, 2)
18207 	RADIO_MENU_ITEM_WITH_INT(_("Octal"), on_popup_menu_item_input_base, evalops.parse_options.base == 8, 8)
18208 	RADIO_MENU_ITEM_WITH_INT(_("Decimal"), on_popup_menu_item_input_base, evalops.parse_options.base == 10, 10)
18209 	RADIO_MENU_ITEM_WITH_INT(_("Duodecimal"), on_popup_menu_item_input_base, evalops.parse_options.base == 12, 12)
18210 	RADIO_MENU_ITEM_WITH_INT(_("Hexadecimal"), on_popup_menu_item_input_base, evalops.parse_options.base == 16, 16)
18211 	RADIO_MENU_ITEM_WITH_INT(_("Roman Numerals"), on_popup_menu_item_input_base, evalops.parse_options.base == BASE_ROMAN_NUMERALS, BASE_ROMAN_NUMERALS)
18212 	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)
18213 	block_popup_input_base = false;
18214 	SUBMENU_ITEM(_("Meta Modes"), sub2)
18215 	popup_expression_mode_items.clear();
18216 	for(size_t i = 0; i < modes.size(); i++) {
18217 		item = gtk_menu_item_new_with_label(modes[i].name.c_str());
18218 		gtk_widget_show(item);
18219 		g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(on_menu_item_meta_mode_activate), (gpointer) modes[i].name.c_str());
18220 		g_signal_connect(G_OBJECT(item), "button-press-event", G_CALLBACK(on_menu_item_meta_mode_button_press), (gpointer) modes[i].name.c_str());
18221 		g_signal_connect(G_OBJECT(item), "popup-menu", G_CALLBACK(on_menu_item_meta_mode_popup_menu), (gpointer) modes[i].name.c_str());
18222 		popup_expression_mode_items.push_back(item);
18223 		gtk_menu_shell_insert(GTK_MENU_SHELL(sub), item, (gint) i);
18224 	}
18225 	MENU_SEPARATOR
18226 	MENU_ITEM(_("Save Mode…"), on_menu_item_meta_mode_save_activate)
18227 	sub = sub2;
18228 	MENU_SEPARATOR
18229 	MENU_ITEM(_("Insert Date…"), on_menu_item_insert_date_activate)
18230 	MENU_ITEM(_("Insert Matrix…"), on_menu_item_insert_matrix_activate)
18231 	MENU_ITEM(_("Insert Vector…"), on_menu_item_insert_vector_activate)
18232 }
18233 
on_combobox_base_changed(GtkComboBox * w,gpointer)18234 void on_combobox_base_changed(GtkComboBox *w, gpointer) {
18235 	switch(gtk_combo_box_get_active(w)) {
18236 		case 0: {
18237 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_binary")), TRUE);
18238 			break;
18239 		}
18240 		case 1: {
18241 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_octal")), TRUE);
18242 			break;
18243 		}
18244 		case 2: {
18245 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_decimal")), TRUE);
18246 			break;
18247 		}
18248 		case 3: {
18249 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_duodecimal")), TRUE);
18250 			break;
18251 		}
18252 		case 4: {
18253 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_hexadecimal")), TRUE);
18254 			break;
18255 		}
18256 		case 5: {
18257 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_sexagesimal")), TRUE);
18258 			break;
18259 		}
18260 		case 6: {
18261 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_time_format")), TRUE);
18262 			break;
18263 		}
18264 		case 7: {
18265 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_roman")), TRUE);
18266 			break;
18267 		}
18268 		case 8: {
18269 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_custom_base")), TRUE);
18270 			break;
18271 		}
18272 	}
18273 	focus_keeping_selection();
18274 }
on_combobox_numerical_display_changed(GtkComboBox * w,gpointer)18275 void on_combobox_numerical_display_changed(GtkComboBox *w, gpointer) {
18276 	gint i = gtk_combo_box_get_active(w);
18277 	block_result_update++;
18278 	if(default_fraction_fraction < 0) {
18279 		if(i == 0 || i == 4) {
18280 			if(printops.number_fraction_format == FRACTION_FRACTIONAL) {
18281 				gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_fraction_combined")), TRUE);
18282 			}
18283 		} else {
18284 			if(printops.number_fraction_format == FRACTION_COMBINED) {
18285 				gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_fraction_fraction")), TRUE);
18286 			}
18287 		}
18288 		default_fraction_fraction = -1;
18289 	}
18290 	bool sne_bak = scientific_negexp, snml_bak = scientific_notminuslast, snp_bak = scientific_noprefix;
18291 	if(i == 0 || i == 4) {
18292 		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_negative_exponents")), FALSE);
18293 		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_sort_minus_last")), TRUE);
18294 		int ap_bak = auto_prefix;
18295 		if(auto_prefix == 1) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_display_prefixes_for_selected_units")), TRUE);
18296 		else if(auto_prefix == 2) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_display_prefixes_for_currencies")), TRUE);
18297 		else if(auto_prefix == 3) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_display_prefixes_for_all_units")), TRUE);
18298 		auto_prefix = ap_bak;
18299 	} else {
18300 		if(i != 1) {
18301 			if(scientific_negexp) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_negative_exponents")), TRUE);
18302 			if(scientific_notminuslast) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_sort_minus_last")), FALSE);
18303 		}
18304 		if(printops.use_unit_prefixes && scientific_noprefix) {
18305 			if(printops.use_prefixes_for_all_units) auto_prefix = 3;
18306 			else if(printops.use_prefixes_for_currencies) auto_prefix = 2;
18307 			else auto_prefix = 1;
18308 			int ap_bak = auto_prefix;
18309 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_display_no_prefixes")), TRUE);
18310 			auto_prefix = ap_bak;
18311 		}
18312 	}
18313 	scientific_negexp = sne_bak; scientific_notminuslast = snml_bak; scientific_noprefix = snp_bak;
18314 
18315 	block_result_update--;
18316 	switch(i) {
18317 		case 0: {
18318 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_display_normal")), TRUE);
18319 			break;
18320 		}
18321 		case 1: {
18322 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_display_engineering")), TRUE);
18323 			break;
18324 		}
18325 		case 2: {
18326 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_display_scientific")), TRUE);
18327 			break;
18328 		}
18329 		case 3: {
18330 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_display_purely_scientific")), TRUE);
18331 			break;
18332 		}
18333 		case 4: {
18334 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_display_non_scientific")), TRUE);
18335 			break;
18336 		}
18337 	}
18338 	focus_keeping_selection();
18339 }
18340 
on_button_exact_toggled(GtkToggleButton * w,gpointer)18341 void on_button_exact_toggled(GtkToggleButton *w, gpointer) {
18342 	if(gtk_toggle_button_get_active(w)) {
18343 		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_always_exact")), TRUE);
18344 	} else {
18345 		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_try_exact")), TRUE);
18346 	}
18347 	focus_keeping_selection();
18348 }
18349 
on_button_fraction_toggled(GtkToggleButton * w,gpointer)18350 void on_button_fraction_toggled(GtkToggleButton *w, gpointer) {
18351 	if(gtk_toggle_button_get_active(w)) {
18352 		if(default_fraction_fraction >= 0) {
18353 			if(default_fraction_fraction == FRACTION_FRACTIONAL) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_fraction_fraction")), TRUE);
18354 			else gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_fraction_combined")), TRUE);
18355 		} else {
18356 			if(printops.min_exp != EXP_NONE && printops.min_exp != EXP_PRECISION) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_fraction_fraction")), TRUE);
18357 			else gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_fraction_combined")), TRUE);
18358 			default_fraction_fraction = -1;
18359 		}
18360 
18361 	} else {
18362 		if(evalops.approximation == APPROXIMATION_EXACT) {
18363 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_fraction_decimal_exact")), TRUE);
18364 			automatic_fraction = true;
18365 		} else {
18366 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_fraction_decimal")), TRUE);
18367 		}
18368 	}
18369 	focus_keeping_selection();
18370 }
18371 
show_tabs(bool do_show)18372 void show_tabs(bool do_show) {
18373 	if(do_show == gtk_widget_get_visible(tabs)) return;
18374 	gint w, h;
18375 	gtk_window_get_size(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), &w, &h);
18376 	if(!persistent_keypad && 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"))) + 9;
18377 	if(do_show) {
18378 		gtk_widget_show(tabs);
18379 		gint a_h = gtk_widget_get_allocated_height(tabs);
18380 		if(a_h > 10) h += a_h + 9;
18381 		else h += history_height + 9;
18382 		if(!persistent_keypad) gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "buttons")));
18383 		gtk_window_resize(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), w, h);
18384 	} else {
18385 		h -= gtk_widget_get_allocated_height(tabs) + 9;
18386 		gtk_widget_hide(tabs);
18387 		set_result_size_request();
18388 		set_expression_size_request();
18389 		gtk_window_resize(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), w, h);
18390 	}
18391 	gtk_widget_set_vexpand(resultview, !gtk_widget_get_visible(tabs) && !gtk_widget_get_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "buttons"))));
18392 	gtk_widget_set_vexpand(GTK_WIDGET(gtk_builder_get_object(main_builder, "buttons")), !persistent_keypad || !gtk_widget_get_visible(tabs));
18393 }
show_keypad_widget(bool do_show)18394 void show_keypad_widget(bool do_show) {
18395 	if(do_show == gtk_widget_get_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "buttons")))) return;
18396 	gint w, h;
18397 	gtk_window_get_size(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), &w, &h);
18398 	if(!persistent_keypad && gtk_widget_get_visible(tabs)) h -= gtk_widget_get_allocated_height(tabs) + 9;
18399 	if(persistent_keypad && gtk_expander_get_expanded(GTK_EXPANDER(expander_convert))) {
18400 		if(do_show) h += 6;
18401 		else h -= 6;
18402 	}
18403 	if(do_show) {
18404 		gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(main_builder, "buttons")));
18405 		gint a_h = gtk_widget_get_allocated_height(GTK_WIDGET(gtk_builder_get_object(main_builder, "buttons")));
18406 		if(a_h > 10) h += a_h + 9;
18407 		else h += 9;
18408 		if(!persistent_keypad) gtk_widget_hide(tabs);
18409 		gtk_window_resize(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), w, h);
18410 	} else {
18411 		h -= gtk_widget_get_allocated_height(GTK_WIDGET(gtk_builder_get_object(main_builder, "buttons"))) + 9;
18412 		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "buttons")));
18413 		set_result_size_request();
18414 		set_expression_size_request();
18415 		gtk_window_resize(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), w, h);
18416 	}
18417 	gtk_widget_set_vexpand(resultview, !gtk_widget_get_visible(tabs) && !gtk_widget_get_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "buttons"))));
18418 	gtk_widget_set_vexpand(GTK_WIDGET(gtk_builder_get_object(main_builder, "buttons")), !persistent_keypad || !gtk_widget_get_visible(tabs));
18419 }
18420 
update_persistent_keypad(bool showhide_buttons=false)18421 void update_persistent_keypad(bool showhide_buttons = false) {
18422 	if(!persistent_keypad && gtk_widget_is_visible(tabs)) showhide_buttons = true;
18423 	gtk_widget_set_vexpand(GTK_WIDGET(gtk_builder_get_object(main_builder, "buttons")), !persistent_keypad || !gtk_widget_get_visible(tabs));
18424 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "box_rpnl")), !persistent_keypad || (rpn_mode && gtk_expander_get_expanded(GTK_EXPANDER(expander_stack))));
18425 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "box_rpnr")), !persistent_keypad || (rpn_mode && gtk_expander_get_expanded(GTK_EXPANDER(expander_stack))));
18426 	if(showhide_buttons && (persistent_keypad || gtk_widget_is_visible(tabs))) {
18427 		show_keypad = false;
18428 		g_signal_handlers_block_matched((gpointer) expander_keypad, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_expander_keypad_expanded, NULL);
18429 		gtk_expander_set_expanded(GTK_EXPANDER(expander_keypad), persistent_keypad);
18430 		g_signal_handlers_unblock_matched((gpointer) expander_keypad, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_expander_keypad_expanded, NULL);
18431 		if(persistent_keypad) gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(main_builder, "buttons")));
18432 		else show_keypad_widget(false);
18433 	}
18434 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "box_hi")), !persistent_keypad);
18435 	if(preferences_builder && gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(preferences_builder, "preferences_checkbutton_persistent_keypad"))) != persistent_keypad) {
18436 		g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(preferences_builder, "preferences_checkbutton_persistent_keypad"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_preferences_checkbutton_persistent_keypad_toggled, NULL);
18437 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(preferences_builder, "preferences_checkbutton_persistent_keypad")), persistent_keypad);
18438 		g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(preferences_builder, "preferences_checkbutton_persistent_keypad"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_preferences_checkbutton_persistent_keypad_toggled, NULL);
18439 	}
18440 	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_persistent_keypad"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_persistent_keypad_toggled, NULL);
18441 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_persistent_keypad")), persistent_keypad);
18442 	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_persistent_keypad"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_persistent_keypad_toggled, NULL);
18443 	GtkRequisition req;
18444 	gtk_widget_get_preferred_size(GTK_WIDGET(gtk_builder_get_object(main_builder, "label_keypad")), &req, NULL);
18445 	gtk_image_set_from_icon_name(GTK_IMAGE(gtk_builder_get_object(main_builder, "image_keypad_lock")), persistent_keypad ? "changes-prevent-symbolic" : "changes-allow-symbolic", GTK_ICON_SIZE_BUTTON);
18446 	if(req.height < 20) gtk_image_set_pixel_size(GTK_IMAGE(gtk_builder_get_object(main_builder, "image_keypad_lock")), req.height * 0.8);
18447 	if(showhide_buttons) gtk_widget_set_margin_bottom(GTK_WIDGET(gtk_builder_get_object(main_builder, "convert")), persistent_keypad && gtk_expander_get_expanded(GTK_EXPANDER(expander_convert)) ? 6 : 0);
18448 	if(persistent_keypad) gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(historyview)));
18449 }
on_expander_keypad_expanded(GObject * o,GParamSpec *,gpointer)18450 void on_expander_keypad_expanded(GObject *o, GParamSpec*, gpointer) {
18451 	if(gtk_expander_get_expanded(GTK_EXPANDER(o))) {
18452 		show_keypad_widget(true);
18453 		if(!persistent_keypad) {
18454 			if(gtk_expander_get_expanded(GTK_EXPANDER(expander_history))) {
18455 				gtk_expander_set_expanded(GTK_EXPANDER(expander_history), FALSE);
18456 			} else if(gtk_expander_get_expanded(GTK_EXPANDER(expander_stack))) {
18457 				gtk_expander_set_expanded(GTK_EXPANDER(expander_stack), FALSE);
18458 			} else if(gtk_expander_get_expanded(GTK_EXPANDER(expander_convert))) {
18459 				gtk_expander_set_expanded(GTK_EXPANDER(expander_convert), FALSE);
18460 			}
18461 		}
18462 	} else {
18463 		show_keypad_widget(false);
18464 	}
18465 	if(persistent_keypad) gtk_widget_set_margin_bottom(GTK_WIDGET(gtk_builder_get_object(main_builder, "convert")), gtk_expander_get_expanded(GTK_EXPANDER(o)) ? 6 : 0);
18466 }
on_expander_history_expanded(GObject * o,GParamSpec *,gpointer)18467 void on_expander_history_expanded(GObject *o, GParamSpec*, gpointer) {
18468 	if(gtk_expander_get_expanded(GTK_EXPANDER(o))) {
18469 		bool history_was_realized = gtk_widget_get_realized(historyview);
18470 		gtk_notebook_set_current_page(GTK_NOTEBOOK(tabs), 0);
18471 		show_tabs(true);
18472 		while(!history_was_realized && gtk_events_pending()) gtk_main_iteration();
18473 		if(!history_was_realized && nr_of_new_expressions > 0) {
18474 			GtkTreePath *path = gtk_tree_path_new_from_indices(0, -1);
18475 			gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(historyview), path, history_index_column, FALSE, 0, 0);
18476 			gtk_tree_view_scroll_to_point(GTK_TREE_VIEW(historyview), 0, 0);
18477 			gtk_tree_path_free(path);
18478 		}
18479 		if(!persistent_keypad && gtk_expander_get_expanded(GTK_EXPANDER(expander_keypad))) {
18480 			gtk_expander_set_expanded(GTK_EXPANDER(expander_keypad), FALSE);
18481 		} else if(gtk_expander_get_expanded(GTK_EXPANDER(expander_stack))) {
18482 			gtk_expander_set_expanded(GTK_EXPANDER(expander_stack), FALSE);
18483 		} else if(gtk_expander_get_expanded(GTK_EXPANDER(expander_convert))) {
18484 			gtk_expander_set_expanded(GTK_EXPANDER(expander_convert), FALSE);
18485 		}
18486 	} else if(!gtk_expander_get_expanded(GTK_EXPANDER(expander_stack)) && !gtk_expander_get_expanded(GTK_EXPANDER(expander_convert))) {
18487 		show_tabs(false);
18488 	}
18489 }
on_expander_stack_expanded(GObject * o,GParamSpec *,gpointer)18490 void on_expander_stack_expanded(GObject *o, GParamSpec*, gpointer) {
18491 	if(gtk_expander_get_expanded(GTK_EXPANDER(o))) {
18492 		gtk_notebook_set_current_page(GTK_NOTEBOOK(tabs), 1);
18493 		show_tabs(true);
18494 		if(!persistent_keypad && gtk_expander_get_expanded(GTK_EXPANDER(expander_keypad))) {
18495 			gtk_expander_set_expanded(GTK_EXPANDER(expander_keypad), FALSE);
18496 		} else if(gtk_expander_get_expanded(GTK_EXPANDER(expander_history))) {
18497 			gtk_expander_set_expanded(GTK_EXPANDER(expander_history), FALSE);
18498 		} else if(gtk_expander_get_expanded(GTK_EXPANDER(expander_convert))) {
18499 			gtk_expander_set_expanded(GTK_EXPANDER(expander_convert), FALSE);
18500 		}
18501 	} else if(!gtk_expander_get_expanded(GTK_EXPANDER(expander_history)) && !gtk_expander_get_expanded(GTK_EXPANDER(expander_convert))) {
18502 		show_tabs(false);
18503 	}
18504 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "box_rpnl")), !persistent_keypad || gtk_expander_get_expanded(GTK_EXPANDER(o)));
18505 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "box_rpnr")), !persistent_keypad || gtk_expander_get_expanded(GTK_EXPANDER(o)));
18506 }
on_expander_convert_expanded(GObject * o,GParamSpec *,gpointer)18507 void on_expander_convert_expanded(GObject *o, GParamSpec*, gpointer) {
18508 	if(gtk_expander_get_expanded(GTK_EXPANDER(o))) {
18509 		gtk_notebook_set_current_page(GTK_NOTEBOOK(tabs), 2);
18510 		show_tabs(true);
18511 		if(!persistent_keypad && gtk_expander_get_expanded(GTK_EXPANDER(expander_keypad))) {
18512 			gtk_expander_set_expanded(GTK_EXPANDER(expander_keypad), FALSE);
18513 		} else if(gtk_expander_get_expanded(GTK_EXPANDER(expander_history))) {
18514 			gtk_expander_set_expanded(GTK_EXPANDER(expander_history), FALSE);
18515 		} else if(gtk_expander_get_expanded(GTK_EXPANDER(expander_stack))) {
18516 			gtk_expander_set_expanded(GTK_EXPANDER(expander_stack), FALSE);
18517 		}
18518 	} else if(!gtk_expander_get_expanded(GTK_EXPANDER(expander_history)) && !gtk_expander_get_expanded(GTK_EXPANDER(expander_stack))) {
18519 		show_tabs(false);
18520 	}
18521 }
18522 
update_minimal_width()18523 void update_minimal_width() {
18524 	gint w;
18525 	gtk_window_get_size(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), &w, NULL);
18526 	if(w != win_width) minimal_width = w;
18527 }
18528 
18529 gint minimal_window_resized_timeout_id = 0;
minimal_window_resized_timeout(gpointer)18530 gboolean minimal_window_resized_timeout(gpointer) {
18531 	minimal_window_resized_timeout_id = 0;
18532 	if(minimal_mode) update_minimal_width();
18533 	return FALSE;
18534 }
do_minimal_mode_timeout(gpointer)18535 gboolean do_minimal_mode_timeout(gpointer) {
18536 	gtk_widget_set_size_request(tabs, -1, -1);
18537 	return FALSE;
18538 }
set_minimal_mode(bool b)18539 void set_minimal_mode(bool b) {
18540 	minimal_mode = b;
18541 	if(minimal_mode) {
18542 		if(gtk_expander_get_expanded(GTK_EXPANDER(expander_history)) || gtk_expander_get_expanded(GTK_EXPANDER(expander_convert)) || gtk_expander_get_expanded(GTK_EXPANDER(expander_stack))) {
18543 			gint h = gtk_widget_get_allocated_height(tabs);
18544 			if(h > 10) history_height = h;
18545 		}
18546 		gint w = 0;
18547 		gtk_window_get_size(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), &w, NULL);
18548 		win_width = w;
18549 		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "box_tabs")));
18550 		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "menubar")));
18551 		gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_minimal_mode")));
18552 		if(expression_is_empty() || !displayed_mstruct) {
18553 			clearresult();
18554 		}
18555 		gtk_window_resize(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), minimal_width > 0 ? minimal_width : win_width, 1);
18556 		gtk_widget_set_vexpand(GTK_WIDGET(gtk_builder_get_object(main_builder, "expressionscrolled")), TRUE);
18557 		gtk_widget_set_vexpand(resultview, FALSE);
18558 	} else {
18559 		if(minimal_window_resized_timeout_id) {
18560 			g_source_remove(minimal_window_resized_timeout_id);
18561 			minimal_window_resized_timeout_id = 0;
18562 			update_minimal_width();
18563 		}
18564 		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_minimal_mode")));
18565 		if(history_height > 0 && (gtk_expander_get_expanded(GTK_EXPANDER(expander_history)) || gtk_expander_get_expanded(GTK_EXPANDER(expander_convert)) || gtk_expander_get_expanded(GTK_EXPANDER(expander_stack)))) {
18566 			gtk_widget_set_size_request(tabs, -1, history_height);
18567 		}
18568 		gtk_widget_set_vexpand(GTK_WIDGET(gtk_builder_get_object(main_builder, "expressionscrolled")), FALSE);
18569 		gtk_widget_set_vexpand(resultview, !gtk_widget_get_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "buttons"))) && !gtk_widget_get_visible(tabs));
18570 		gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(main_builder, "box_tabs")));
18571 		gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(main_builder, "menubar")));
18572 		set_status_bottom_border_visible(true);
18573 		gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(main_builder, "resultoverlay")));
18574 		if(history_height > 0 && (gtk_expander_get_expanded(GTK_EXPANDER(expander_history)) || gtk_expander_get_expanded(GTK_EXPANDER(expander_convert)) || gtk_expander_get_expanded(GTK_EXPANDER(expander_stack)))) {
18575 			gdk_threads_add_timeout(500, do_minimal_mode_timeout, NULL);
18576 		}
18577 		gint h = 1;
18578 		if(gtk_widget_is_visible(tabs) || gtk_widget_is_visible(keypad)) {
18579 			gtk_window_get_size(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), NULL, &h);
18580 		}
18581 		gtk_window_resize(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), win_width < 0 ? 1 : win_width, h);
18582 	}
18583 	set_expression_size_request();
18584 }
18585 
18586 int mode_menu_i = 0;
18587 
on_popup_menu_mode_update_activate(GtkMenuItem *,gpointer data)18588 void on_popup_menu_mode_update_activate(GtkMenuItem*, gpointer data) {
18589 	size_t index = save_mode_as((const char*) data);
18590 	current_mode = modes[index].name;
18591 	update_window_title();
18592 	if(mode_menu_i == 1) {
18593 		gtk_menu_popdown(GTK_MENU(gtk_builder_get_object(main_builder, "mode_menu_menu")));
18594 		gtk_menu_shell_deselect(GTK_MENU_SHELL(gtk_builder_get_object(main_builder, "menubar")));
18595 	} else if(mode_menu_i == 2) {
18596 		gtk_menu_popdown(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_resultview")));
18597 	} else if(mode_menu_i == 3) {
18598 		gtk_menu_popdown(popup_menu_expressiontext);
18599 	}
18600 	focus_keeping_selection();
18601 }
on_popup_menu_mode_delete_activate(GtkMenuItem *,gpointer data)18602 void on_popup_menu_mode_delete_activate(GtkMenuItem*, gpointer data) {
18603 	size_t index = 2;
18604 	const char *name = (const char*) data;
18605 	for(; index < modes.size(); index++) {
18606 		if(modes[index].name == name) break;
18607 	}
18608 	if(index >= modes.size()) return;
18609 	gtk_widget_destroy(mode_items[index]);
18610 	gtk_widget_destroy(popup_result_mode_items[index]);
18611 	modes.erase(modes.begin() + index);
18612 	mode_items.erase(mode_items.begin() + index);
18613 	popup_result_mode_items.erase(popup_result_mode_items.begin() + index);
18614 	if(modes.size() < 3) gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "menu_item_meta_mode_delete")), FALSE);
18615 	if(mode_menu_i == 1) {
18616 		gtk_menu_popdown(GTK_MENU(gtk_builder_get_object(main_builder, "mode_menu_menu")));
18617 		gtk_menu_shell_deselect(GTK_MENU_SHELL(gtk_builder_get_object(main_builder, "menubar")));
18618 	} else if(mode_menu_i == 2) {
18619 		gtk_menu_popdown(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_resultview")));
18620 	} else if(mode_menu_i == 3) {
18621 		gtk_menu_popdown(popup_menu_expressiontext);
18622 	}
18623 	focus_keeping_selection();
18624 }
18625 
18626 gulong on_popup_menu_mode_update_activate_handler = 0, on_popup_menu_mode_delete_activate_handler = 0;
18627 
on_menu_item_meta_mode_popup_menu(GtkWidget * w,gpointer data)18628 gboolean on_menu_item_meta_mode_popup_menu(GtkWidget *w, gpointer data) {
18629 	size_t index = 0;
18630 	const char *name = (const char*) data;
18631 	for(; index < modes.size(); index++) {
18632 		if(modes[index].name == name) break;
18633 	}
18634 	if(index >= modes.size()) return TRUE;
18635 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_mode_update")), index > 0);
18636 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_mode_delete")), index > 1);
18637 	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);
18638 	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);
18639 	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);
18640 	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);
18641 	mode_menu_i = 0;
18642 	for(size_t i = 0; i < mode_items.size(); i++) {
18643 		if(mode_items[i] == w) {mode_menu_i = 1; break;}
18644 	}
18645 	if(mode_menu_i == 0) {
18646 		for(size_t i = 0; i < popup_result_mode_items.size(); i++) {
18647 			if(popup_result_mode_items[i] == w) {mode_menu_i = 2; break;}
18648 		}
18649 	}
18650 	if(mode_menu_i == 0) {
18651 		for(size_t i = 0; i < popup_expression_mode_items.size(); i++) {
18652 			if(popup_expression_mode_items[i] == w) {mode_menu_i = 3; break;}
18653 		}
18654 	}
18655 #if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 22
18656 	gtk_menu_popup_at_pointer(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_mode")), NULL);
18657 #else
18658 	gtk_menu_popup(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_mode")), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time());
18659 #endif
18660 	return TRUE;
18661 }
18662 
on_menu_item_meta_mode_button_press(GtkWidget * widget,GdkEventButton * event,gpointer data)18663 gboolean on_menu_item_meta_mode_button_press(GtkWidget *widget, GdkEventButton *event, gpointer data) {
18664 	/* Ignore double-clicks and triple-clicks */
18665 	if(gdk_event_triggers_context_menu((GdkEvent *) event) && event->type == GDK_BUTTON_PRESS) {
18666 		on_menu_item_meta_mode_popup_menu(widget, data);
18667 		return TRUE;
18668 	}
18669 	return FALSE;
18670 }
18671 
on_menu_item_meta_mode_activate(GtkMenuItem *,gpointer user_data)18672 void on_menu_item_meta_mode_activate(GtkMenuItem*, gpointer user_data) {
18673 	const char *name = (const char*) user_data;
18674 	load_mode(name);
18675 }
on_menu_item_meta_mode_save_activate(GtkMenuItem *,gpointer)18676 void on_menu_item_meta_mode_save_activate(GtkMenuItem*, gpointer) {
18677 	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), _("_Cancel"), GTK_RESPONSE_REJECT, _("_Save"), GTK_RESPONSE_ACCEPT, NULL);
18678 	gtk_container_set_border_width(GTK_CONTAINER(dialog), 6);
18679 	GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 12);
18680 	gtk_container_set_border_width(GTK_CONTAINER(hbox), 6);
18681 	gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), hbox);
18682 	gtk_widget_show(hbox);
18683 	GtkWidget *label = gtk_label_new(_("Name"));
18684 	gtk_widget_set_halign(label, GTK_ALIGN_START);
18685 	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 0);
18686 	gtk_widget_show(label);
18687 	GtkWidget *entry = gtk_combo_box_text_new_with_entry();
18688 	for(size_t i = 2; i < modes.size(); i++) {
18689 		gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(entry), modes[i].name.c_str());
18690 	}
18691 	gtk_box_pack_end(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
18692 	gtk_widget_show(entry);
18693 run_meta_mode_save_dialog:
18694 	gint response = gtk_dialog_run(GTK_DIALOG(dialog));
18695 	if(response == GTK_RESPONSE_ACCEPT) {
18696 		bool new_mode = true;
18697 		string name = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(entry));
18698 		remove_blank_ends(name);
18699 		if(name.empty()) {
18700 			show_message(_("Empty name field."), dialog);
18701 			goto run_meta_mode_save_dialog;
18702 		}
18703 		if(name == modes[0].name) {
18704 			show_message(_("Preset mode cannot be overwritten."), dialog);
18705 			goto run_meta_mode_save_dialog;
18706 		}
18707 		size_t index = save_mode_as(name, &new_mode);
18708 		current_mode = modes[index].name;
18709 		update_window_title();
18710 		if(new_mode) {
18711 			GtkWidget *item = gtk_menu_item_new_with_label(modes[index].name.c_str());
18712 			gtk_widget_show(item);
18713 			g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(on_menu_item_meta_mode_activate), (gpointer) modes[index].name.c_str());
18714 			g_signal_connect(G_OBJECT(item), "button-press-event", G_CALLBACK(on_menu_item_meta_mode_button_press), (gpointer) modes[index].name.c_str());
18715 			g_signal_connect(G_OBJECT(item), "popup-menu", G_CALLBACK(on_menu_item_meta_mode_popup_menu), (gpointer) modes[index].name.c_str());
18716 			gtk_menu_shell_insert(GTK_MENU_SHELL(gtk_builder_get_object(main_builder, "menu_meta_modes")), item, (gint) index);
18717 			mode_items.push_back(item);
18718 			item = gtk_menu_item_new_with_label(modes[index].name.c_str());
18719 			gtk_widget_show(item);
18720 			g_signal_connect(G_OBJECT(item), "button-press-event", G_CALLBACK(on_menu_item_meta_mode_button_press), (gpointer) modes[index].name.c_str());
18721 			g_signal_connect(G_OBJECT(item), "popup-menu", G_CALLBACK(on_menu_item_meta_mode_popup_menu), (gpointer) modes[index].name.c_str());
18722 			g_signal_connect(G_OBJECT(item), "popup-menu", G_CALLBACK(on_menu_item_meta_mode_popup_menu), (gpointer) modes[index].name.c_str());
18723 			gtk_menu_shell_insert(GTK_MENU_SHELL(gtk_builder_get_object(main_builder, "menu_result_popup_meta_modes")), item, (gint) index);
18724 			popup_result_mode_items.push_back(item);
18725 			if(modes.size() == 3) gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "menu_item_meta_mode_delete")), TRUE);
18726 		}
18727 	}
18728 	gtk_widget_destroy(dialog);
18729 }
18730 
on_menu_item_meta_mode_delete_activate(GtkMenuItem *,gpointer)18731 void on_menu_item_meta_mode_delete_activate(GtkMenuItem*, gpointer) {
18732 	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), _("_Cancel"), GTK_RESPONSE_REJECT, _("_Delete"), GTK_RESPONSE_ACCEPT, NULL);
18733 	gtk_container_set_border_width(GTK_CONTAINER(dialog), 6);
18734 	GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 12);
18735 	gtk_container_set_border_width(GTK_CONTAINER(hbox), 6);
18736 	gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), hbox);
18737 	gtk_widget_show(hbox);
18738 	GtkWidget *label = gtk_label_new(_("Mode"));
18739 	gtk_widget_set_halign(label, GTK_ALIGN_START);
18740 	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 0);
18741 	gtk_widget_show(label);
18742 	GtkWidget *menu = gtk_combo_box_text_new();
18743 	for(size_t i = 2; i < modes.size(); i++) {
18744 		gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(menu), modes[i].name.c_str());
18745 	}
18746 	gtk_combo_box_set_active(GTK_COMBO_BOX(menu), 0);
18747 	gtk_box_pack_end(GTK_BOX(hbox), menu, TRUE, TRUE, 0);
18748 	gtk_widget_show(menu);
18749 	gint response = gtk_dialog_run(GTK_DIALOG(dialog));
18750 	if(response == GTK_RESPONSE_ACCEPT && gtk_combo_box_get_active(GTK_COMBO_BOX(menu)) >= 0) {
18751 		size_t index = gtk_combo_box_get_active(GTK_COMBO_BOX(menu)) + 2;
18752 		gtk_widget_destroy(mode_items[index]);
18753 		gtk_widget_destroy(popup_result_mode_items[index]);
18754 		modes.erase(modes.begin() + index);
18755 		mode_items.erase(mode_items.begin() + index);
18756 		popup_result_mode_items.erase(popup_result_mode_items.begin() + index);
18757 		if(modes.size() < 3) gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "menu_item_meta_mode_delete")), FALSE);
18758 	}
18759 	gtk_widget_destroy(dialog);
18760 }
18761 
18762 /*
18763 	load preferences from ~/.conf/qalculate/qalculate-gtk.cfg
18764 */
load_preferences()18765 void load_preferences() {
18766 
18767 	default_plot_legend_placement = PLOT_LEGEND_TOP_RIGHT;
18768 	default_plot_display_grid = true;
18769 	default_plot_full_border = false;
18770 	default_plot_min = "0";
18771 	default_plot_max = "10";
18772 	default_plot_step = "1";
18773 	default_plot_sampling_rate = 1001;
18774 	default_plot_linewidth = 2;
18775 	default_plot_rows = false;
18776 	default_plot_type = 0;
18777 	default_plot_style = PLOT_STYLE_LINES;
18778 	default_plot_smoothing = PLOT_SMOOTHING_NONE;
18779 	default_plot_variable = "x";
18780 	default_plot_color = true;
18781 	default_plot_use_sampling_rate = true;
18782 	max_plot_time = 5;
18783 
18784 	printops.multiplication_sign = MULTIPLICATION_SIGN_X;
18785 	printops.division_sign = DIVISION_SIGN_DIVISION_SLASH;
18786 	printops.is_approximate = new bool(false);
18787 	printops.prefix = NULL;
18788 	printops.use_min_decimals = false;
18789 	printops.use_denominator_prefix = true;
18790 	printops.min_decimals = 0;
18791 	printops.use_max_decimals = false;
18792 	printops.max_decimals = 2;
18793 	printops.base = 10;
18794 	printops.min_exp = EXP_PRECISION;
18795 	printops.negative_exponents = false;
18796 	printops.sort_options.minus_last = true;
18797 	printops.indicate_infinite_series = false;
18798 	printops.show_ending_zeroes = true;
18799 	printops.round_halfway_to_even = false;
18800 	printops.number_fraction_format = FRACTION_DECIMAL;
18801 	printops.restrict_fraction_length = false;
18802 	printops.abbreviate_names = true;
18803 	printops.use_unicode_signs = true;
18804 	printops.digit_grouping = DIGIT_GROUPING_STANDARD;
18805 	printops.use_unit_prefixes = true;
18806 	printops.use_prefixes_for_currencies = false;
18807 	printops.use_prefixes_for_all_units = false;
18808 	printops.spacious = true;
18809 	printops.short_multiplication = true;
18810 	printops.place_units_separately = true;
18811 	printops.use_all_prefixes = false;
18812 	printops.excessive_parenthesis = false;
18813 	printops.allow_non_usable = false;
18814 	printops.lower_case_numbers = false;
18815 	printops.lower_case_e = false;
18816 	printops.base_display = BASE_DISPLAY_NORMAL;
18817 	printops.twos_complement = true;
18818 	printops.hexadecimal_twos_complement = false;
18819 	printops.limit_implicit_multiplication = false;
18820 	printops.can_display_unicode_string_function = &can_display_unicode_string_function;
18821 	printops.allow_factorization = false;
18822 	printops.spell_out_logical_operators = true;
18823 	printops.exp_to_root = true;
18824 	printops.interval_display = INTERVAL_DISPLAY_SIGNIFICANT_DIGITS;
18825 
18826 	evalops.approximation = APPROXIMATION_TRY_EXACT;
18827 	evalops.sync_units = true;
18828 	evalops.structuring = STRUCTURING_SIMPLIFY;
18829 	evalops.parse_options.unknowns_enabled = false;
18830 	evalops.parse_options.read_precision = DONT_READ_PRECISION;
18831 	evalops.parse_options.base = BASE_DECIMAL;
18832 	evalops.allow_complex = true;
18833 	evalops.allow_infinite = true;
18834 	evalops.auto_post_conversion = POST_CONVERSION_OPTIMAL;
18835 	evalops.assume_denominators_nonzero = true;
18836 	evalops.warn_about_denominators_assumed_nonzero = true;
18837 	evalops.parse_options.limit_implicit_multiplication = false;
18838 	evalops.parse_options.parsing_mode = PARSING_MODE_ADAPTIVE;
18839 	evalops.parse_options.angle_unit = ANGLE_UNIT_RADIANS;
18840 	evalops.parse_options.dot_as_separator = CALCULATOR->default_dot_as_separator;
18841 	evalops.parse_options.comma_as_separator = false;
18842 	evalops.mixed_units_conversion = MIXED_UNITS_CONVERSION_DEFAULT;
18843 	evalops.complex_number_form = COMPLEX_NUMBER_FORM_RECTANGULAR;
18844 	complex_angle_form = false;
18845 	evalops.local_currency_conversion = true;
18846 	evalops.interval_calculation = INTERVAL_CALCULATION_VARIANCE_FORMULA;
18847 	b_decimal_comma = -1;
18848 
18849 	use_systray_icon = false;
18850 	hide_on_startup = false;
18851 
18852 #ifdef _WIN32
18853 	check_version = true;
18854 #else
18855 	check_version = false;
18856 #endif
18857 
18858 	title_type = TITLE_APP;
18859 
18860 	auto_calculate = false;
18861 	chain_mode = false;
18862 	autocalc_history_delay = 2000;
18863 
18864 	default_signed = -1;
18865 	default_bits = -1;
18866 
18867 	programming_inbase = 0;
18868 	programming_outbase = 0;
18869 
18870 	visible_keypad = 0;
18871 
18872 	caret_as_xor = false;
18873 
18874 	ignore_locale = false;
18875 
18876 	automatic_fraction = false;
18877 	default_fraction_fraction = -1;
18878 	scientific_noprefix = true;
18879 	scientific_notminuslast = true;
18880 	scientific_negexp = true;
18881 	auto_prefix = 0;
18882 
18883 	keep_function_dialog_open = false;
18884 
18885 	copy_separator = true;
18886 
18887 	use_e_notation = false;
18888 
18889 	adaptive_interval_display = true;
18890 
18891 	CALCULATOR->useIntervalArithmetic(true);
18892 
18893 	CALCULATOR->setTemperatureCalculationMode(TEMPERATURE_CALCULATION_HYBRID);
18894 	tc_set = false;
18895 
18896 	CALCULATOR->useBinaryPrefixes(0);
18897 
18898 	rpn_mode = false;
18899 	rpn_keys = true;
18900 
18901 	save_mode_as(_("Preset"));
18902 	save_mode_as(_("Default"));
18903 	size_t mode_index = 1;
18904 
18905 	win_x = 0;
18906 	win_y = 0;
18907 	remember_position = false;
18908 	win_width = -1;
18909 	win_height = -1;
18910 	variables_width = -1;
18911 	variables_height = -1;
18912 	variables_position = -1;
18913 	units_width = -1;
18914 	units_height = -1;
18915 	units_position = -1;
18916 	functions_width = -1;
18917 	functions_height = -1;
18918 	functions_hposition = -1;
18919 	functions_vposition = -1;
18920 	datasets_width = -1;
18921 	datasets_height = -1;
18922 	datasets_hposition = -1;
18923 	datasets_vposition1 = -1;
18924 	datasets_vposition2 = -1;
18925 	help_width = -1;
18926 	help_height = -1;
18927 	help_zoom = -1.0;
18928 	minimal_width = 500;
18929 	history_height = 0;
18930 	save_mode_on_exit = true;
18931 	save_defs_on_exit = true;
18932 	clear_history_on_exit = false;
18933 	hyp_is_on = false;
18934 	inv_is_on = false;
18935 	use_custom_result_font = false;
18936 	use_custom_expression_font = false;
18937 	use_custom_status_font = false;
18938 	use_custom_keypad_font = false;
18939 	use_custom_app_font = false;
18940 	custom_result_font = "";
18941 	custom_expression_font = "";
18942 	custom_status_font = "";
18943 	custom_keypad_font = "";
18944 	custom_app_font = "";
18945 	status_error_color = "#FF0000";
18946 	status_warning_color = "#0000FF";
18947 	status_error_color_set = false;
18948 	status_warning_color_set = false;
18949 	show_keypad = true;
18950 	show_history = false;
18951 	show_stack = true;
18952 	show_convert = false;
18953 	persistent_keypad = false;
18954 	minimal_mode = false;
18955 	continuous_conversion = true;
18956 	set_missing_prefixes = false;
18957 	load_global_defs = true;
18958 	fetch_exchange_rates_at_startup = false;
18959 	auto_update_exchange_rates = -1;
18960 	display_expression_status = true;
18961 	enable_completion = true;
18962 	enable_completion2 = true;
18963 	completion_min = 1;
18964 	completion_min2 = 1;
18965 	completion_delay = 0;
18966 	first_time = false;
18967 	first_error = true;
18968 	expression_history.clear();
18969 	expression_history_index = -1;
18970 	hexadecimal_twos_complement_in = false;
18971 	twos_complement_in = false;
18972 	expression_lines = -1;
18973 	use_dark_theme = -1;
18974 
18975 	CALCULATOR->setPrecision(10);
18976 
18977 	default_shortcuts = true;
18978 	keyboard_shortcuts.clear();
18979 
18980 	custom_buttons.resize(34);
18981 	for(size_t i = 0; i < 34; i++) {
18982 		custom_buttons[i].type[0] = -1;
18983 		custom_buttons[i].type[1] = -1;
18984 		custom_buttons[i].type[2] = -1;
18985 		custom_buttons[i].value[0] = "";
18986 		custom_buttons[i].value[1] = "";
18987 		custom_buttons[i].value[2] = "";
18988 		custom_buttons[i].text = "";
18989 	}
18990 
18991 	last_version_check_date.setToCurrentDate();
18992 
18993 	latest_button_unit = NULL;
18994 	latest_button_currency = NULL;
18995 
18996 	FILE *file = NULL;
18997 	gchar *gstr_oldfile = NULL;
18998 	gchar *gstr_file = g_build_filename(getLocalDir().c_str(), "qalculate-gtk.cfg", NULL);
18999 	file = fopen(gstr_file, "r");
19000 	if(!file) {
19001 #ifndef _WIN32
19002 		gstr_oldfile = g_build_filename(getOldLocalDir().c_str(), "qalculate-gtk.cfg", NULL);
19003 		file = fopen(gstr_oldfile, "r");
19004 		if(!file) g_free(gstr_oldfile);
19005 #endif
19006 	}
19007 
19008 	size_t bookmark_index = 0;
19009 
19010 	int version_numbers[] = {3, 17, 0};
19011 	bool old_history_format = false;
19012 
19013 	if(file) {
19014 		char line[1000000L];
19015 		string stmp, svalue, svar;
19016 		size_t i;
19017 		int v;
19018 		while(true) {
19019 			if(fgets(line, 1000000L, file) == NULL) break;
19020 			stmp = line;
19021 			remove_blank_ends(stmp);
19022 			if((i = stmp.find_first_of("=")) != string::npos) {
19023 				svar = stmp.substr(0, i);
19024 				remove_blank_ends(svar);
19025 				svalue = stmp.substr(i + 1);
19026 				remove_blank_ends(svalue);
19027 				v = s2i(svalue);
19028 				if(svar == "version") {
19029 					parse_qalculate_version(svalue, version_numbers);
19030 					old_history_format = (version_numbers[0] == 0 && (version_numbers[1] < 9 || (version_numbers[1] == 9 && version_numbers[2] <= 4)));
19031 				} else if(svar == "allow_multiple_instances") {
19032 					if(v == 0 && version_numbers[0] < 3) v = -1;
19033 					allow_multiple_instances = v;
19034 				} else if(svar == "width") {
19035 					win_width = v;
19036 					if(version_numbers[0] < 3 || (version_numbers[0] == 3 && version_numbers[1] < 15)) win_width -= 6;
19037 				/*} else if(svar == "height") {
19038 					win_height = v;*/
19039 				} else if(svar == "x") {
19040 					win_x = v;
19041 					remember_position = true;
19042 				} else if(svar == "y") {
19043 					win_y = v;
19044 					remember_position = true;
19045 #ifdef _WIN32
19046 				} else if(svar == "use_system_tray_icon") {
19047 					use_systray_icon = v;
19048 #endif
19049 				} else if(svar == "hide_on_startup") {
19050 					hide_on_startup = v;
19051 				} else if(svar == "variables_width") {
19052 					variables_width = v;
19053 				} else if(svar == "variables_height") {
19054 					variables_height = v;
19055 				} else if(svar == "variables_panel_position") {
19056 					variables_position = v;
19057 				} else if(svar == "units_width") {
19058 					units_width = v;
19059 				} else if(svar == "units_height") {
19060 					units_height = v;
19061 				} else if(svar == "units_panel_position") {
19062 					units_position = v;
19063 				} else if(svar == "functions_width") {
19064 					functions_width = v;
19065 				} else if(svar == "functions_height") {
19066 					functions_height = v;
19067 				} else if(svar == "functions_hpanel_position") {
19068 					functions_hposition = v;
19069 				} else if(svar == "functions_vpanel_position") {
19070 					functions_vposition = v;
19071 				} else if(svar == "datasets_width") {
19072 					datasets_width = v;
19073 				} else if(svar == "datasets_height") {
19074 					datasets_height = v;
19075 				} else if(svar == "datasets_hpanel_position") {
19076 					datasets_hposition = v;
19077 				} else if(svar == "datasets_vpanel1_position") {
19078 					datasets_vposition1 = v;
19079 				} else if(svar == "datasets_vpanel2_position") {
19080 					datasets_vposition2 = v;
19081 				} else if(svar == "help_width") {
19082 					help_width = v;
19083 				} else if(svar == "help_height") {
19084 					help_height = v;
19085 				} else if(svar == "help_zoom") {
19086 					help_zoom = strtod(svalue.c_str(), NULL);
19087 				} else if(svar == "keep_function_dialog_open") {
19088 					keep_function_dialog_open = v;
19089 				} else if(svar == "error_info_shown") {
19090 					first_error = !v;
19091 				} else if(svar == "save_mode_on_exit") {
19092 					save_mode_on_exit = v;
19093 				} else if(svar == "save_definitions_on_exit") {
19094 					save_defs_on_exit = v;
19095 				} else if(svar == "clear_history_on_exit") {
19096 					clear_history_on_exit = v;
19097 				} else if(svar == "ignore_locale") {
19098 					ignore_locale = v;
19099 				} else if(svar == "window_title_mode") {
19100 					if(v >= 0 && v <= 4) title_type = v;
19101 				} else if(svar == "fetch_exchange_rates_at_startup") {
19102 					if(auto_update_exchange_rates < 0 && v) auto_update_exchange_rates = 1;
19103 					//fetch_exchange_rates_at_startup = v;
19104 				} else if(svar == "auto_update_exchange_rates") {
19105 					auto_update_exchange_rates = v;
19106 				} else if(svar == "check_version") {
19107 					check_version = v;
19108 				} else if(svar == "last_version_check") {
19109 					last_version_check_date.set(svalue);
19110 				} else if(svar == "last_found_version") {
19111 					last_found_version = svalue;
19112 				} else if(svar == "show_keypad") {
19113 					show_keypad = v;
19114 				} else if(svar == "show_history") {
19115 					show_history = v;
19116 				} else if(svar == "history_height") {
19117 					history_height = v;
19118 				} else if(svar == "minimal_width") {
19119 					if(v != 0 || version_numbers[0] > 3 || (version_numbers[0] == 3 && version_numbers[1] >= 15)) minimal_width = v;
19120 				} else if(svar == "show_stack") {
19121 					show_stack = v;
19122 				} else if(svar == "show_convert") {
19123 					show_convert = v;
19124 				} else if(svar == "persistent_keypad") {
19125 					persistent_keypad = v;
19126 				} else if(svar == "minimal_mode") {
19127 					minimal_mode = v;
19128 				} else if(svar == "continuous_conversion") {
19129 					continuous_conversion = v;
19130 				} else if(svar == "set_missing_prefixes") {
19131 					set_missing_prefixes = v;
19132 				} else if(svar == "expression_lines") {
19133 					expression_lines = v;
19134 				} else if(svar == "display_expression_status") {
19135 					display_expression_status = v;
19136 				} else if(svar == "enable_completion") {
19137 					enable_completion = v;
19138 				} else if(svar == "enable_completion2") {
19139 					enable_completion2 = v;
19140 				} else if(svar == "completion_min") {
19141 					if(v < 1) v = 1;
19142 					completion_min = v;
19143 				} else if(svar == "completion_min2") {
19144 					if(v < 1) v = 1;
19145 					completion_min2 = v;
19146 				} else if(svar == "completion_delay") {
19147 					if(v < 0) v = 0;
19148 					completion_delay = v;
19149 				} else if(svar == "calculate_as_you_type_history_delay") {
19150 					autocalc_history_delay = v;
19151 				} else if(svar == "programming_outbase") {
19152 					programming_outbase = v;
19153 				} else if(svar == "programming_inbase") {
19154 					programming_inbase = v;
19155 				} else if(svar == "general_exact") {
19156 					versatile_exact = v;
19157 				} else if(svar == "bit_width") {
19158 					default_bits = v;
19159 				} else if(svar == "signed_integer") {
19160 					default_signed = v;
19161 				} else if(svar == "min_deci") {
19162 					if(mode_index == 1) printops.min_decimals = v;
19163 					else modes[mode_index].po.min_decimals = v;
19164 				} else if(svar == "use_min_deci") {
19165 					if(mode_index == 1) printops.use_min_decimals = v;
19166 					else modes[mode_index].po.use_min_decimals = v;
19167 				} else if(svar == "max_deci") {
19168 					if(mode_index == 1) printops.max_decimals = v;
19169 					else modes[mode_index].po.max_decimals = v;
19170 				} else if(svar == "use_max_deci") {
19171 					if(mode_index == 1) printops.use_max_decimals = v;
19172 					else modes[mode_index].po.use_max_decimals = v;
19173 				} else if(svar == "precision") {
19174 					if(v == 8 && (version_numbers[0] < 3 || (version_numbers[0] == 3 && version_numbers[1] <= 12))) v = 10;
19175 					if(mode_index == 1) CALCULATOR->setPrecision(v);
19176 					else modes[mode_index].precision = v;
19177 				} else if(svar == "min_exp") {
19178 					if(mode_index == 1) printops.min_exp = v;
19179 					else modes[mode_index].po.min_exp = v;
19180 				} else if(svar == "interval_arithmetic") {
19181 					if(version_numbers[0] >= 3) {
19182 						if(mode_index == 1) CALCULATOR->useIntervalArithmetic(v);
19183 						else modes[mode_index].interval = v;
19184 					} else {
19185 						modes[mode_index].interval = true;
19186 					}
19187 				} else if(svar == "interval_display") {
19188 					if(v == 0) {
19189 						if(mode_index == 1) {printops.interval_display = INTERVAL_DISPLAY_SIGNIFICANT_DIGITS; adaptive_interval_display = true;}
19190 						else {modes[mode_index].po.interval_display = INTERVAL_DISPLAY_SIGNIFICANT_DIGITS; modes[mode_index].adaptive_interval_display = true;}
19191 					} else {
19192 						v--;
19193 						if(v >= INTERVAL_DISPLAY_SIGNIFICANT_DIGITS && v <= INTERVAL_DISPLAY_UPPER) {
19194 							if(mode_index == 1) {printops.interval_display = (IntervalDisplay) v; adaptive_interval_display = false;}
19195 							else {modes[mode_index].po.interval_display = (IntervalDisplay) v; modes[mode_index].adaptive_interval_display = false;}
19196 						}
19197 					}
19198 				} else if(svar == "negative_exponents") {
19199 					if(mode_index == 1) printops.negative_exponents = v;
19200 					else modes[mode_index].po.negative_exponents = v;
19201 				} else if(svar == "sort_minus_last") {
19202 					if(mode_index == 1) printops.sort_options.minus_last = v;
19203 					else modes[mode_index].po.sort_options.minus_last = v;
19204 				} else if(svar == "place_units_separately") {
19205 					if(mode_index == 1) printops.place_units_separately = v;
19206 					else modes[mode_index].po.place_units_separately = v;
19207 				} else if(svar == "display_mode") {	//obsolete
19208 					switch(v) {
19209 						case 1: {
19210 							if(mode_index == 1) {
19211 								printops.min_exp = EXP_PRECISION;
19212 								printops.negative_exponents = false;
19213 								printops.sort_options.minus_last = true;
19214 							} else {
19215 								modes[mode_index].po.min_exp = EXP_PRECISION;
19216 								modes[mode_index].po.negative_exponents = false;
19217 								modes[mode_index].po.sort_options.minus_last = true;
19218 							}
19219 							break;
19220 						}
19221 						case 2: {
19222 							if(mode_index == 1) {
19223 								printops.min_exp = EXP_SCIENTIFIC;
19224 								printops.negative_exponents = true;
19225 								printops.sort_options.minus_last = false;
19226 							} else {
19227 								modes[mode_index].po.min_exp = EXP_SCIENTIFIC;
19228 								modes[mode_index].po.negative_exponents = true;
19229 								modes[mode_index].po.sort_options.minus_last = false;
19230 							}
19231 							break;
19232 						}
19233 						case 3: {
19234 							if(mode_index == 1) {
19235 								printops.min_exp = EXP_PURE;
19236 								printops.negative_exponents = true;
19237 								printops.sort_options.minus_last = false;
19238 							} else {
19239 								modes[mode_index].po.min_exp = EXP_PURE;
19240 								modes[mode_index].po.negative_exponents = true;
19241 								modes[mode_index].po.sort_options.minus_last = false;
19242 							}
19243 							break;
19244 						}
19245 						case 4: {
19246 							if(mode_index == 1) {
19247 								printops.min_exp = EXP_NONE;
19248 								printops.negative_exponents = false;
19249 								printops.sort_options.minus_last = true;
19250 							} else {
19251 								modes[mode_index].po.min_exp = EXP_NONE;
19252 								modes[mode_index].po.negative_exponents = false;
19253 								modes[mode_index].po.sort_options.minus_last = true;
19254 							}
19255 							break;
19256 						}
19257 					}
19258 				} else if(svar == "use_prefixes") {
19259 					if(mode_index == 1) printops.use_unit_prefixes = v;
19260 					else modes[mode_index].po.use_unit_prefixes = v;
19261 				} else if(svar == "use_prefixes_for_all_units") {
19262 					if(mode_index == 1) printops.use_prefixes_for_all_units = v;
19263 					else modes[mode_index].po.use_prefixes_for_all_units = v;
19264 				} else if(svar == "use_prefixes_for_currencies") {
19265 					if(mode_index == 1) printops.use_prefixes_for_currencies = v;
19266 					else modes[mode_index].po.use_prefixes_for_currencies = v;
19267 				} else if(svar == "fractional_mode") {	//obsolete
19268 					switch(v) {
19269 						case 1: {
19270 							if(mode_index == 1) printops.number_fraction_format = FRACTION_DECIMAL;
19271 							else modes[mode_index].po.number_fraction_format = FRACTION_DECIMAL;
19272 							break;
19273 						}
19274 						case 2: {
19275 							if(mode_index == 1) printops.number_fraction_format = FRACTION_COMBINED;
19276 							else modes[mode_index].po.number_fraction_format = FRACTION_COMBINED;
19277 							break;
19278 						}
19279 						case 3: {
19280 							if(mode_index == 1) printops.number_fraction_format = FRACTION_FRACTIONAL;
19281 							else modes[mode_index].po.number_fraction_format = FRACTION_FRACTIONAL;
19282 							break;
19283 						}
19284 					}
19285 					if(mode_index == 1) printops.restrict_fraction_length = (printops.number_fraction_format >= FRACTION_FRACTIONAL);
19286 					else modes[mode_index].po.restrict_fraction_length = (modes[mode_index].po.number_fraction_format >= FRACTION_FRACTIONAL);
19287 				} else if(svar == "number_fraction_format") {
19288 					if(v >= FRACTION_DECIMAL && v <= FRACTION_COMBINED) {
19289 						if(mode_index == 1) printops.number_fraction_format = (NumberFractionFormat) v;
19290 						else modes[mode_index].po.number_fraction_format = (NumberFractionFormat) v;
19291 					}
19292 					if(mode_index == 1) printops.restrict_fraction_length = (printops.number_fraction_format >= FRACTION_FRACTIONAL);
19293 					else modes[mode_index].po.restrict_fraction_length = (modes[mode_index].po.number_fraction_format >= FRACTION_FRACTIONAL);
19294 				} else if(svar == "automatic_number_fraction_format") {
19295 					automatic_fraction = v;
19296 				} else if(svar == "default_number_fraction_fraction") {
19297 					if(v >= FRACTION_FRACTIONAL && v <= FRACTION_COMBINED) default_fraction_fraction = (NumberFractionFormat) v;
19298 				} else if(svar == "automatic_unit_prefixes") {
19299 					auto_prefix = v;
19300 				} else if(svar == "scientific_mode_unit_prefixes") {
19301 					scientific_noprefix = !v;
19302 				} else if(svar == "scientific_mode_sort_minus_last") {
19303 					scientific_notminuslast = !v;
19304 				} else if(svar == "scientific_mode_negative_exponents") {
19305 					scientific_negexp = v;
19306 				} else if(svar == "complex_number_form") {
19307 					if(v == COMPLEX_NUMBER_FORM_CIS + 1) {
19308 						if(mode_index == 1) {
19309 							evalops.complex_number_form = COMPLEX_NUMBER_FORM_CIS;
19310 							complex_angle_form = true;
19311 						} else {
19312 							modes[mode_index].eo.complex_number_form = COMPLEX_NUMBER_FORM_CIS;
19313 							modes[mode_index].complex_angle_form = true;
19314 						}
19315 					} else if(v >= COMPLEX_NUMBER_FORM_RECTANGULAR && v <= COMPLEX_NUMBER_FORM_CIS) {
19316 						if(mode_index == 1) {
19317 							evalops.complex_number_form = (ComplexNumberForm) v;
19318 							complex_angle_form = false;
19319 						} else {
19320 							modes[mode_index].eo.complex_number_form = (ComplexNumberForm) v;
19321 							modes[mode_index].complex_angle_form = false;
19322 						}
19323 					}
19324 				} else if(svar == "number_base") {
19325 					if(mode_index == 1) printops.base = v;
19326 					else modes[mode_index].po.base = v;
19327 				} else if(svar == "custom_number_base") {
19328 					CALCULATOR->beginTemporaryStopMessages();
19329 					MathStructure m;
19330 					CALCULATOR->calculate(&m, svalue, 500);
19331 					CALCULATOR->endTemporaryStopMessages();
19332 					if(mode_index == 1) CALCULATOR->setCustomOutputBase(m.number());
19333 					else modes[mode_index].custom_output_base = m.number();
19334 				} else if(svar == "number_base_expression") {
19335 					if(mode_index == 1) evalops.parse_options.base = v;
19336 					else modes[mode_index].eo.parse_options.base = v;
19337 				} else if(svar == "custom_number_base_expression") {
19338 					CALCULATOR->beginTemporaryStopMessages();
19339 					MathStructure m;
19340 					CALCULATOR->calculate(&m, svalue, 500);
19341 					CALCULATOR->endTemporaryStopMessages();
19342 					if(mode_index == 1) CALCULATOR->setCustomInputBase(m.number());
19343 					else modes[mode_index].custom_input_base = m.number();
19344 				} else if(svar == "read_precision") {
19345 					if(v >= DONT_READ_PRECISION && v <= READ_PRECISION_WHEN_DECIMALS) {
19346 						if(mode_index == 1) evalops.parse_options.read_precision = (ReadPrecisionMode) v;
19347 						else modes[mode_index].eo.parse_options.read_precision = (ReadPrecisionMode) v;
19348 					}
19349 				} else if(svar == "assume_denominators_nonzero") {
19350 					if(version_numbers[0] == 0 && (version_numbers[1] < 9 || (version_numbers[1] == 9 && version_numbers[2] == 0))) {
19351 						v = true;
19352 					}
19353 					if(mode_index == 1) evalops.assume_denominators_nonzero = v;
19354 					else modes[mode_index].eo.assume_denominators_nonzero = v;
19355 				} else if(svar == "warn_about_denominators_assumed_nonzero") {
19356 					if(mode_index == 1) evalops.warn_about_denominators_assumed_nonzero = v;
19357 					else modes[mode_index].eo.warn_about_denominators_assumed_nonzero = v;
19358 				} else if(svar == "structuring") {
19359 					if(v >= STRUCTURING_NONE && v <= STRUCTURING_FACTORIZE) {
19360 						if((v == STRUCTURING_NONE) && version_numbers[0] == 0 && (version_numbers[1] < 9 || (version_numbers[1] == 9 && version_numbers[2] <= 12))) {
19361 							v = STRUCTURING_SIMPLIFY;
19362 						}
19363 						if(mode_index == 1) {
19364 							evalops.structuring = (StructuringMode) v;
19365 							printops.allow_factorization = (evalops.structuring == STRUCTURING_FACTORIZE);
19366 						} else {
19367 							modes[mode_index].eo.structuring = (StructuringMode) v;
19368 							modes[mode_index].po.allow_factorization = (modes[mode_index].eo.structuring == STRUCTURING_FACTORIZE);
19369 						}
19370 					}
19371 				} else if(svar == "angle_unit") {
19372 					if(version_numbers[0] == 0 && (version_numbers[1] < 7 || (version_numbers[1] == 7 && version_numbers[2] == 0))) {
19373 						v++;
19374 					}
19375 					if(v >= ANGLE_UNIT_NONE && v <= ANGLE_UNIT_GRADIANS) {
19376 						if(mode_index == 1) evalops.parse_options.angle_unit = (AngleUnit) v;
19377 						else modes[mode_index].eo.parse_options.angle_unit = (AngleUnit) v;
19378 					}
19379 				} else if(svar == "functions_enabled") {
19380 					if(mode_index == 1) evalops.parse_options.functions_enabled = v;
19381 					else modes[mode_index].eo.parse_options.functions_enabled = v;
19382 				} else if(svar == "variables_enabled") {
19383 					if(mode_index == 1) evalops.parse_options.variables_enabled = v;
19384 					else modes[mode_index].eo.parse_options.variables_enabled = v;
19385 				} else if(svar == "donot_calculate_variables") {
19386 					if(mode_index == 1) evalops.calculate_variables = !v;
19387 					else modes[mode_index].eo.calculate_variables = !v;
19388 				} else if(svar == "calculate_variables") {
19389 					if(mode_index == 1) evalops.calculate_variables = v;
19390 					else modes[mode_index].eo.calculate_variables = v;
19391 				} else if(svar == "variable_units_enabled") {
19392 					if(mode_index == 1) CALCULATOR->setVariableUnitsEnabled(v);
19393 					else modes[mode_index].variable_units_enabled = v;
19394 				} else if(svar == "calculate_functions") {
19395 					if(mode_index == 1) evalops.calculate_functions = v;
19396 					else modes[mode_index].eo.calculate_functions = v;
19397 				} else if(svar == "sync_units") {
19398 					if(mode_index == 1) evalops.sync_units = v;
19399 					else modes[mode_index].eo.sync_units = v;
19400 				} else if(svar == "temperature_calculation") {
19401 					CALCULATOR->setTemperatureCalculationMode((TemperatureCalculationMode) v);
19402 					tc_set = true;
19403 				} else if(svar == "unknownvariables_enabled") {
19404 					if(mode_index == 1) evalops.parse_options.unknowns_enabled = v;
19405 					else modes[mode_index].eo.parse_options.unknowns_enabled = v;
19406 				} else if(svar == "units_enabled") {
19407 					if(mode_index == 1) evalops.parse_options.units_enabled = v;
19408 					else modes[mode_index].eo.parse_options.units_enabled = v;
19409 				} else if(svar == "allow_complex") {
19410 					if(mode_index == 1) evalops.allow_complex = v;
19411 					else modes[mode_index].eo.allow_complex = v;
19412 				} else if(svar == "allow_infinite") {
19413 					if(mode_index == 1) evalops.allow_infinite = v;
19414 					else modes[mode_index].eo.allow_infinite = v;
19415 				} else if(svar == "use_short_units") {
19416 					if(mode_index == 1) printops.abbreviate_names = v;
19417 					else modes[mode_index].po.abbreviate_names = v;
19418 				} else if(svar == "abbreviate_names") {
19419 					if(mode_index == 1) printops.abbreviate_names = v;
19420 					else modes[mode_index].po.abbreviate_names = v;
19421 				} else if(svar == "all_prefixes_enabled") {
19422 					if(mode_index == 1) printops.use_all_prefixes = v;
19423 					else modes[mode_index].po.use_all_prefixes = v;
19424 				} else if(svar == "denominator_prefix_enabled") {
19425 					if(mode_index == 1) printops.use_denominator_prefix = v;
19426 					else modes[mode_index].po.use_denominator_prefix = v;
19427 				} else if(svar == "auto_post_conversion") {
19428 					if(v >= POST_CONVERSION_NONE && v <= POST_CONVERSION_OPTIMAL) {
19429 						if(v == POST_CONVERSION_NONE && version_numbers[0] == 0 && (version_numbers[1] < 9 || (version_numbers[1] == 9 && version_numbers[2] <= 12))) {
19430 							v = POST_CONVERSION_OPTIMAL;
19431 						}
19432 						if(mode_index == 1) evalops.auto_post_conversion = (AutoPostConversion) v;
19433 						else modes[mode_index].eo.auto_post_conversion = (AutoPostConversion) v;
19434 					}
19435 				} else if(svar == "mixed_units_conversion") {
19436 					if(v >= MIXED_UNITS_CONVERSION_NONE || v <= MIXED_UNITS_CONVERSION_FORCE_ALL) {
19437 						if(mode_index == 1) evalops.mixed_units_conversion = (MixedUnitsConversion) v;
19438 						else modes[mode_index].eo.mixed_units_conversion = (MixedUnitsConversion) v;
19439 					}
19440 				} else if(svar == "local_currency_conversion") {
19441 					evalops.local_currency_conversion = v;
19442 				} else if(svar == "use_binary_prefixes") {
19443 					CALCULATOR->useBinaryPrefixes(v);
19444 				} else if(svar == "indicate_infinite_series") {
19445 					if(mode_index == 1) printops.indicate_infinite_series = v;
19446 					else modes[mode_index].po.indicate_infinite_series = v;
19447 				} else if(svar == "show_ending_zeroes") {
19448 					if(version_numbers[0] > 2 || (version_numbers[0] == 2 && version_numbers[1] >= 9)) {
19449 						if(mode_index == 1) printops.show_ending_zeroes = v;
19450 						else modes[mode_index].po.show_ending_zeroes = v;
19451 					}
19452 				} else if(svar == "digit_grouping") {
19453 					if(v >= DIGIT_GROUPING_NONE && v <= DIGIT_GROUPING_LOCALE) {
19454 						printops.digit_grouping = (DigitGrouping) v;
19455 					}
19456 				} else if(svar == "round_halfway_to_even") {
19457 					if(mode_index == 1) printops.round_halfway_to_even = v;
19458 					else modes[mode_index].po.round_halfway_to_even = v;
19459 				} else if(svar == "always_exact") {		//obsolete
19460 					if(mode_index == 1) {
19461 						evalops.approximation = APPROXIMATION_EXACT;
19462 					} else {
19463 						modes[mode_index].eo.approximation = APPROXIMATION_EXACT;
19464 						modes[mode_index].interval = false;
19465 					}
19466 				} else if(svar == "approximation") {
19467 					if(v >= APPROXIMATION_EXACT && v <= APPROXIMATION_APPROXIMATE) {
19468 						if(mode_index == 1) {
19469 							evalops.approximation = (ApproximationMode) v;
19470 						} else {
19471 							modes[mode_index].eo.approximation = (ApproximationMode) v;
19472 						}
19473 					}
19474 				} else if(svar == "interval_calculation") {
19475 					if(v >= INTERVAL_CALCULATION_NONE && v <= INTERVAL_CALCULATION_SIMPLE_INTERVAL_ARITHMETIC) {
19476 						if(mode_index == 1) evalops.interval_calculation = (IntervalCalculation) v;
19477 						else modes[mode_index].eo.interval_calculation = (IntervalCalculation) v;
19478 					}
19479 				} else if(svar == "calculate_as_you_type") {
19480 					if(mode_index == 1) auto_calculate = v;
19481 					else modes[mode_index].autocalc = v;
19482 				} else if(svar == "chain_mode") {
19483 					if(mode_index == 1) chain_mode = v;
19484 					else modes[mode_index].chain_mode = v;
19485 				} else if(svar == "in_rpn_mode") {
19486 					if(mode_index == 1) rpn_mode = v;
19487 					else modes[mode_index].rpn_mode = v;
19488 				} else if(svar == "rpn_keys") {
19489 					rpn_keys = v;
19490 				} else if(svar == "rpn_syntax") {
19491 					if(v) {
19492 						if(mode_index == 1) evalops.parse_options.parsing_mode = PARSING_MODE_RPN;
19493 						else modes[mode_index].eo.parse_options.parsing_mode = PARSING_MODE_RPN;
19494 					}
19495 				} else if(svar == "limit_implicit_multiplication") {
19496 					if(mode_index == 1) {
19497 						evalops.parse_options.limit_implicit_multiplication = v;
19498 						printops.limit_implicit_multiplication = v;
19499 					} else {
19500 						modes[mode_index].eo.parse_options.limit_implicit_multiplication = v;
19501 						modes[mode_index].po.limit_implicit_multiplication = v;
19502 					}
19503 				} else if(svar == "parsing_mode") {
19504 					if((evalops.parse_options.parsing_mode != PARSING_MODE_RPN || version_numbers[0] > 3 || (version_numbers[0] == 3 && version_numbers[1] > 15)) && v >= PARSING_MODE_ADAPTIVE && v <= PARSING_MODE_RPN) {
19505 						if(mode_index == 1) {
19506 							evalops.parse_options.parsing_mode = (ParsingMode) v;
19507 						} else {
19508 							modes[mode_index].eo.parse_options.parsing_mode = (ParsingMode) v;
19509 						}
19510 					}
19511 				} else if(svar == "default_assumption_type") {
19512 					if(v >= ASSUMPTION_TYPE_NONE && v <= ASSUMPTION_TYPE_INTEGER) {
19513 						if(v < ASSUMPTION_TYPE_NUMBER && version_numbers[0] < 1) v = ASSUMPTION_TYPE_NUMBER;
19514 						if(v == ASSUMPTION_TYPE_COMPLEX && version_numbers[0] < 2) v = ASSUMPTION_TYPE_NUMBER;
19515 						if(mode_index == 1) CALCULATOR->defaultAssumptions()->setType((AssumptionType) v);
19516 						else modes[mode_index].at = (AssumptionType) v;
19517 					}
19518 				} else if(svar == "default_assumption_sign") {
19519 					if(v >= ASSUMPTION_SIGN_UNKNOWN && v <= ASSUMPTION_SIGN_NONZERO) {
19520 						if(v == ASSUMPTION_SIGN_NONZERO && version_numbers[0] == 0 && (version_numbers[1] < 9 || (version_numbers[1] == 9 && version_numbers[2] == 0))) {
19521 							v = ASSUMPTION_SIGN_UNKNOWN;
19522 						}
19523 						if(mode_index == 1) CALCULATOR->defaultAssumptions()->setSign((AssumptionSign) v);
19524 						else modes[mode_index].as = (AssumptionSign) v;
19525 					}
19526 				} else if(svar == "spacious") {
19527 					if(mode_index == 1) printops.spacious = v;
19528 					else modes[mode_index].po.spacious = v;
19529 				} else if(svar == "excessive_parenthesis") {
19530 					if(mode_index == 1) printops.excessive_parenthesis = v;
19531 					else modes[mode_index].po.excessive_parenthesis = v;
19532 				} else if(svar == "short_multiplication") {
19533 					if(mode_index == 1) printops.short_multiplication = v;
19534 					else modes[mode_index].po.short_multiplication = v;
19535 				} else if(svar == "visible_keypad") {
19536 					if(mode_index == 1) visible_keypad = v;
19537 					else modes[mode_index].keypad = v;
19538 				} else if(svar == "use_unicode_signs" && (version_numbers[0] > 0 || version_numbers[1] > 7 || (version_numbers[1] == 7 && version_numbers[2] > 0))) {
19539 					printops.use_unicode_signs = v;
19540 				} else if(svar == "lower_case_numbers") {
19541 					printops.lower_case_numbers = v;
19542 				} else if(svar == "lower_case_e") {
19543 					printops.lower_case_e = v;
19544 				} else if(svar == "e_notation") {
19545 					use_e_notation = v;
19546 				} else if(svar == "imaginary_j") {
19547 					do_imaginary_j = v;
19548 				} else if(svar == "base_display") {
19549 					if(v >= BASE_DISPLAY_NONE && v <= BASE_DISPLAY_ALTERNATIVE) printops.base_display = (BaseDisplay) v;
19550 				} else if(svar == "twos_complement") {
19551 					printops.twos_complement = v;
19552 				} else if(svar == "hexadecimal_twos_complement") {
19553 					printops.hexadecimal_twos_complement = v;
19554 				} else if(svar == "twos_complement_input") {
19555 					twos_complement_in = v;
19556 				} else if(svar == "hexadecimal_twos_complement_input") {
19557 					hexadecimal_twos_complement_in = v;
19558 				} else if(svar == "spell_out_logical_operators") {
19559 					printops.spell_out_logical_operators = v;
19560 				} else if(svar == "caret_as_xor") {
19561 					caret_as_xor = v;
19562 				} else if(svar == "copy_separator") {
19563 					copy_separator = v;
19564 				} else if(svar == "decimal_comma") {
19565 					b_decimal_comma = v;
19566 					if(v == 0) CALCULATOR->useDecimalPoint(evalops.parse_options.comma_as_separator);
19567 					else if(v > 0) CALCULATOR->useDecimalComma();
19568 				} else if(svar == "dot_as_separator") {
19569 					evalops.parse_options.dot_as_separator = v;
19570 				} else if(svar == "comma_as_separator") {
19571 					evalops.parse_options.comma_as_separator = v;
19572 					if(CALCULATOR->getDecimalPoint() != COMMA) {
19573 						CALCULATOR->useDecimalPoint(evalops.parse_options.comma_as_separator);
19574 					}
19575 				} else if(svar == "use_dark_theme") {
19576 					use_dark_theme = v;
19577 				} else if(svar == "use_custom_result_font") {
19578 					use_custom_result_font = v;
19579 				} else if(svar == "use_custom_expression_font") {
19580 					use_custom_expression_font = v;
19581 				} else if(svar == "use_custom_status_font") {
19582 					use_custom_status_font = v;
19583 				} else if(svar == "use_custom_keypad_font") {
19584 					use_custom_keypad_font = v;
19585 				} else if(svar == "use_custom_application_font") {
19586 					use_custom_app_font = v;
19587 				} else if(svar == "custom_result_font") {
19588 					custom_result_font = svalue;
19589 					save_custom_result_font = true;
19590 				} else if(svar == "custom_expression_font") {
19591 					custom_expression_font = svalue;
19592 					save_custom_expression_font = true;
19593 				} else if(svar == "custom_status_font") {
19594 					custom_status_font = svalue;
19595 					save_custom_status_font = true;
19596 				} else if(svar == "custom_keypad_font") {
19597 					custom_keypad_font = svalue;
19598 					save_custom_keypad_font = true;
19599 				} else if(svar == "custom_application_font") {
19600 					custom_app_font = svalue;
19601 					save_custom_app_font = true;
19602 				} else if(svar == "status_error_color") {
19603 					status_error_color = svalue;
19604 					status_error_color_set = true;
19605 				} else if(svar == "status_warning_color") {
19606 					status_warning_color = svalue;
19607 					status_warning_color_set = true;
19608 				} else if(svar == "multiplication_sign") {
19609 					if(svalue == "*") {
19610 						printops.multiplication_sign = MULTIPLICATION_SIGN_ASTERISK;
19611 					} else if(svalue == SIGN_MULTIDOT) {
19612 						printops.multiplication_sign = MULTIPLICATION_SIGN_DOT;
19613 					} else if(svalue == SIGN_MIDDLEDOT) {
19614 						printops.multiplication_sign = MULTIPLICATION_SIGN_ALTDOT;
19615 					} else if(svalue == SIGN_MULTIPLICATION) {
19616 						printops.multiplication_sign = MULTIPLICATION_SIGN_X;
19617 					} else if(v >= MULTIPLICATION_SIGN_ASTERISK && v <= MULTIPLICATION_SIGN_ALTDOT) {
19618 						printops.multiplication_sign = (MultiplicationSign) v;
19619 					}
19620 					if(printops.multiplication_sign == MULTIPLICATION_SIGN_DOT && version_numbers[0] < 2) {
19621 						printops.multiplication_sign = MULTIPLICATION_SIGN_X;
19622 					}
19623 				} else if(svar == "division_sign") {
19624 					if(v >= DIVISION_SIGN_SLASH && v <= DIVISION_SIGN_DIVISION) printops.division_sign = (DivisionSign) v;
19625 				} else if(svar == "recent_functions") {
19626 					size_t v_i = 0;
19627 					while(true) {
19628 						v_i = svalue.find(',');
19629 						if(v_i == string::npos) {
19630 							svar = svalue.substr(0, svalue.length());
19631 							remove_blank_ends(svar);
19632 							if(!svar.empty()) {
19633 								recent_functions_pre.push_back(svar);
19634 							}
19635 							break;
19636 						} else {
19637 							svar = svalue.substr(0, v_i);
19638 							svalue = svalue.substr(v_i + 1, svalue.length() - (v_i + 1));
19639 							remove_blank_ends(svar);
19640 							if(!svar.empty()) {
19641 								recent_functions_pre.push_back(svar);
19642 							}
19643 						}
19644 					}
19645 				} else if(svar == "recent_variables") {
19646 					size_t v_i = 0;
19647 					while(true) {
19648 						v_i = svalue.find(',');
19649 						if(v_i == string::npos) {
19650 							svar = svalue.substr(0, svalue.length());
19651 							remove_blank_ends(svar);
19652 							if(!svar.empty()) {
19653 								recent_variables_pre.push_back(svar);
19654 							}
19655 							break;
19656 						} else {
19657 							svar = svalue.substr(0, v_i);
19658 							svalue = svalue.substr(v_i + 1, svalue.length() - (v_i + 1));
19659 							remove_blank_ends(svar);
19660 							if(!svar.empty()) {
19661 								recent_variables_pre.push_back(svar);
19662 							}
19663 						}
19664 					}
19665 				} else if(svar == "recent_units") {
19666 					size_t v_i = 0;
19667 					while(true) {
19668 						v_i = svalue.find(',');
19669 						if(v_i == string::npos) {
19670 							svar = svalue.substr(0, svalue.length());
19671 							remove_blank_ends(svar);
19672 							if(!svar.empty()) {
19673 								recent_units_pre.push_back(svar);
19674 							}
19675 							break;
19676 						} else {
19677 							svar = svalue.substr(0, v_i);
19678 							svalue = svalue.substr(v_i + 1, svalue.length() - (v_i + 1));
19679 							remove_blank_ends(svar);
19680 							if(!svar.empty()) {
19681 								recent_units_pre.push_back(svar);
19682 							}
19683 						}
19684 					}
19685 				} else if(svar == "latest_button_unit") {
19686 					latest_button_unit_pre = svalue;
19687 				} else if(svar == "latest_button_currency") {
19688 					latest_button_currency_pre = svalue;
19689 				} else if(svar == "plot_legend_placement") {
19690 					if(v >= PLOT_LEGEND_NONE && v <= PLOT_LEGEND_OUTSIDE) default_plot_legend_placement = (PlotLegendPlacement) v;
19691 				} else if(svar == "plot_style") {
19692 					if(v >= PLOT_STYLE_LINES && v <= PLOT_STYLE_DOTS) default_plot_style = (PlotStyle) v;
19693 				} else if(svar == "plot_smoothing") {
19694 					if(v >= PLOT_SMOOTHING_NONE && v <= PLOT_SMOOTHING_SBEZIER) default_plot_smoothing = (PlotSmoothing) v;
19695 				} else if(svar == "plot_display_grid") {
19696 					default_plot_display_grid = v;
19697 				} else if(svar == "plot_full_border") {
19698 					default_plot_full_border = v;
19699 				} else if(svar == "plot_min") {
19700 					default_plot_min = svalue;
19701 				} else if(svar == "plot_max") {
19702 					default_plot_max = svalue;
19703 				} else if(svar == "plot_step") {
19704 					default_plot_step = svalue;
19705 				} else if(svar == "plot_sampling_rate") {
19706 					default_plot_sampling_rate = v;
19707 				} else if(svar == "plot_use_sampling_rate") {
19708 					default_plot_use_sampling_rate = v;
19709 				} else if(svar == "plot_variable") {
19710 					default_plot_variable = svalue;
19711 				} else if(svar == "plot_rows") {
19712 					default_plot_rows = v;
19713 				} else if(svar == "plot_type") {
19714 					default_plot_type = v;
19715 				} else if(svar == "plot_color") {
19716 					if(version_numbers[0] > 2 || (version_numbers[0] == 2 && (version_numbers[1] > 2 || (version_numbers[1] == 2 && version_numbers[2] > 1)))) {
19717 						default_plot_color = v;
19718 					}
19719 				} else if(svar == "plot_linewidth") {
19720 					default_plot_linewidth = v;
19721 				} else if(svar == "max_plot_time") {
19722 					max_plot_time = v;
19723 				} else if(svar == "custom_button_label") {
19724 					unsigned int index = 0;
19725 					char str[svalue.length()];
19726 					int n = sscanf(svalue.c_str(), "%u:%s", &index, str);
19727 					if(n >= 2 && index < custom_buttons.size()) {
19728 						custom_buttons[index].text = str;
19729 					}
19730 				} else if(svar == "custom_button") {
19731 					unsigned int index = 0;
19732 					unsigned int bi = 0;
19733 					char str[svalue.length()];
19734 					int type = -1;
19735 					int n = sscanf(svalue.c_str(), "%u:%u:%i:%s", &index, &bi, &type, str);
19736 					if(n >= 3 && index < custom_buttons.size()) {
19737 						if(bi <= 2) {
19738 							custom_buttons[index].type[bi] = type;
19739 							if(n >= 4) custom_buttons[index].value[bi] = str;
19740 							else custom_buttons[index].value[bi] = "";
19741 						}
19742 					}
19743 				} else if(svar == "keyboard_shortcut") {
19744 					default_shortcuts = false;
19745 					char str[svalue.length()];
19746 					keyboard_shortcut ks;
19747 					int n = sscanf(svalue.c_str(), "%u:%u:%i:%s", &ks.key, &ks.modifier, &ks.type, str);
19748 					if(version_numbers[0] < 3 || (version_numbers[0] == 3 && version_numbers[1] < 9) || (version_numbers[0] == 3 && version_numbers[1] == 9 && version_numbers[2] < 1)) {
19749 						if(ks.type >= SHORTCUT_TYPE_DEGREES) ks.type += 3;
19750 					}
19751 					if(version_numbers[0] < 3 || (version_numbers[0] == 3 && version_numbers[1] < 9) || (version_numbers[0] == 3 && version_numbers[1] == 9 && version_numbers[2] < 2)) {
19752 						if(ks.type >= SHORTCUT_TYPE_HISTORY_SEARCH) ks.type++;
19753 					}
19754 					if(version_numbers[0] < 3 || (version_numbers[0] == 3 && version_numbers[1] < 9)) {
19755 						if(ks.type >= SHORTCUT_TYPE_MINIMAL) ks.type++;
19756 					}
19757 					if(version_numbers[0] < 3 || (version_numbers[0] == 3 && (version_numbers[1] < 13 || (version_numbers[1] == 13 && version_numbers[2] == 0)))) {
19758 						if(ks.type >= SHORTCUT_TYPE_MEMORY_CLEAR) ks.type += 5;
19759 					}
19760 					if(version_numbers[0] < 3 || (version_numbers[0] == 3 && version_numbers[1] < 8)) {
19761 						if(ks.type >= SHORTCUT_TYPE_FLOATING_POINT) ks.type++;
19762 					}
19763 					if(n >= 3 && ks.type >= SHORTCUT_TYPE_FUNCTION && ks.type <= SHORTCUT_TYPE_CHAIN_MODE) {
19764 						if(n == 4) ks.value = str;
19765 						keyboard_shortcuts[(guint64) ks.key + (guint64) G_MAXUINT32 * (guint64) ks.modifier] = ks;
19766 					}
19767 				} else if(svar == "expression_history") {
19768 					expression_history.push_back(svalue);
19769 				} else if(svar == "history") {
19770 					inhistory.push_front(svalue);
19771 					inhistory_type.push_front(QALCULATE_HISTORY_OLD);
19772 					inhistory_protected.push_front(false);
19773 					inhistory_value.push_front(0);
19774 				} else if(svar == "history_old") {
19775 					inhistory.push_front(svalue);
19776 					inhistory_type.push_front(QALCULATE_HISTORY_OLD);
19777 					inhistory_protected.push_front(false);
19778 					inhistory_value.push_front(0);
19779 				} else if(svar == "history_expression") {
19780 					inhistory.push_front(svalue);
19781 					inhistory_type.push_front(QALCULATE_HISTORY_EXPRESSION);
19782 					inhistory_protected.push_front(false);
19783 					inhistory_value.push_front(0);
19784 				} else if(svar == "history_expression*") {
19785 					inhistory.push_front(svalue);
19786 					inhistory_type.push_front(QALCULATE_HISTORY_EXPRESSION);
19787 					inhistory_protected.push_front(true);
19788 					inhistory_value.push_front(0);
19789 				} else if(svar == "history_transformation") {
19790 					inhistory.push_front(svalue);
19791 					inhistory_type.push_front(QALCULATE_HISTORY_TRANSFORMATION);
19792 					inhistory_protected.push_front(false);
19793 					inhistory_value.push_front(0);
19794 				} else if(svar == "history_result") {
19795 					inhistory.push_front(svalue);
19796 					inhistory_type.push_front(QALCULATE_HISTORY_RESULT);
19797 					inhistory_protected.push_front(false);
19798 					inhistory_value.push_front(0);
19799 				} else if(svar == "history_result_approximate") {
19800 					inhistory.push_front(svalue);
19801 					inhistory_type.push_front(QALCULATE_HISTORY_RESULT_APPROXIMATE);
19802 					inhistory_protected.push_front(false);
19803 					inhistory_value.push_front(0);
19804 				} else if(svar == "history_parse") {
19805 					inhistory.push_front(svalue);
19806 					if(old_history_format) inhistory_type.push_front(QALCULATE_HISTORY_PARSE_WITHEQUALS);
19807 					else inhistory_type.push_front(QALCULATE_HISTORY_PARSE);
19808 					inhistory_protected.push_front(false);
19809 					inhistory_value.push_front(0);
19810 				} else if(svar == "history_parse_withequals") {
19811 					inhistory.push_front(svalue);
19812 					inhistory_type.push_front(QALCULATE_HISTORY_PARSE_WITHEQUALS);
19813 					inhistory_protected.push_front(false);
19814 					inhistory_value.push_front(0);
19815 				} else if(svar == "history_parse_approximate") {
19816 					inhistory.push_front(svalue);
19817 					inhistory_type.push_front(QALCULATE_HISTORY_PARSE_APPROXIMATE);
19818 					inhistory_protected.push_front(false);
19819 					inhistory_value.push_front(0);
19820 				} else if(svar == "history_register_moved") {
19821 					inhistory.push_front(svalue);
19822 					inhistory_type.push_front(QALCULATE_HISTORY_REGISTER_MOVED);
19823 					inhistory_protected.push_front(false);
19824 					inhistory_value.push_front(0);
19825 				} else if(svar == "history_rpn_operation") {
19826 					inhistory.push_front(svalue);
19827 					inhistory_type.push_front(QALCULATE_HISTORY_RPN_OPERATION);
19828 					inhistory_protected.push_front(false);
19829 					inhistory_value.push_front(0);
19830 				} else if(svar == "history_register_moved*") {
19831 					inhistory.push_front(svalue);
19832 					inhistory_type.push_front(QALCULATE_HISTORY_REGISTER_MOVED);
19833 					inhistory_protected.push_front(true);
19834 					inhistory_value.push_front(0);
19835 				} else if(svar == "history_rpn_operation*") {
19836 					inhistory.push_front(svalue);
19837 					inhistory_type.push_front(QALCULATE_HISTORY_RPN_OPERATION);
19838 					inhistory_protected.push_front(true);
19839 					inhistory_value.push_front(0);
19840 				} else if(svar == "history_warning") {
19841 					inhistory.push_front(svalue);
19842 					inhistory_type.push_front(QALCULATE_HISTORY_WARNING);
19843 					inhistory_protected.push_front(false);
19844 					inhistory_value.push_front(0);
19845 				} else if(svar == "history_message") {
19846 					inhistory.push_front(svalue);
19847 					inhistory_type.push_front(QALCULATE_HISTORY_MESSAGE);
19848 					inhistory_protected.push_front(false);
19849 					inhistory_value.push_front(0);
19850 				} else if(svar == "history_error") {
19851 					inhistory.push_front(svalue);
19852 					inhistory_type.push_front(QALCULATE_HISTORY_ERROR);
19853 					inhistory_protected.push_front(false);
19854 					inhistory_value.push_front(0);
19855 				} else if(svar == "history_bookmark") {
19856 					inhistory.push_front(svalue);
19857 					inhistory_type.push_front(QALCULATE_HISTORY_BOOKMARK);
19858 					inhistory_protected.push_front(false);
19859 					inhistory_value.push_front(0);
19860 					bool b = false;
19861 					bookmark_index = 0;
19862 					for(vector<string>::iterator it = history_bookmarks.begin(); it != history_bookmarks.end(); ++it) {
19863 						if(string_is_less(svalue, *it)) {
19864 							history_bookmarks.insert(it, svalue);
19865 							b = true;
19866 							break;
19867 						}
19868 						bookmark_index++;
19869 					}
19870 					if(!b) history_bookmarks.push_back(svalue);
19871 				} else if(svar == "history_continued") {
19872 					if(inhistory.size() > 0) {
19873 						inhistory[0] += "\n";
19874 						inhistory[0] += svalue;
19875 						if(inhistory_type[0] == QALCULATE_HISTORY_BOOKMARK) {
19876 							history_bookmarks[bookmark_index] += "\n";
19877 							history_bookmarks[bookmark_index] += svalue;
19878 						}
19879 					}
19880 				}
19881 			} else if(stmp.length() > 2 && stmp[0] == '[' && stmp[stmp.length() - 1] == ']') {
19882 				stmp = stmp.substr(1, stmp.length() - 2);
19883 				remove_blank_ends(stmp);
19884 				if(stmp == "Mode") {
19885 					mode_index = 1;
19886 				} else if(stmp.length() > 5 && stmp.substr(0, 4) == "Mode") {
19887 					mode_index = save_mode_as(stmp.substr(5, stmp.length() - 5));
19888 				}
19889 			}
19890 		}
19891 		fclose(file);
19892 		if(gstr_oldfile) {
19893 			recursiveMakeDir(getLocalDir());
19894 			move_file(gstr_oldfile, gstr_file);
19895 			g_free(gstr_oldfile);
19896 		}
19897 	} else {
19898 		first_time = true;
19899 	}
19900 	if(default_shortcuts) {
19901 		keyboard_shortcut ks;
19902 #define ADD_SHORTCUT(k, m, t, v) ks.key = k; ks.modifier = m; ks.type = t; ks.value = v; keyboard_shortcuts[(guint64) ks.key + (guint64) G_MAXUINT32 * (guint64) ks.modifier] = ks;
19903 		ADD_SHORTCUT(GDK_KEY_b, GDK_CONTROL_MASK, SHORTCUT_TYPE_NUMBER_BASES, "")
19904 		ADD_SHORTCUT(GDK_KEY_q, GDK_CONTROL_MASK, SHORTCUT_TYPE_QUIT, "")
19905 		ADD_SHORTCUT(GDK_KEY_F1, 0, SHORTCUT_TYPE_HELP, "")
19906 		ADD_SHORTCUT(GDK_KEY_c, GDK_CONTROL_MASK | GDK_MOD1_MASK, SHORTCUT_TYPE_COPY_RESULT, "")
19907 		ADD_SHORTCUT(GDK_KEY_s, GDK_CONTROL_MASK, SHORTCUT_TYPE_STORE, "")
19908 		ADD_SHORTCUT(GDK_KEY_m, GDK_CONTROL_MASK, SHORTCUT_TYPE_MANAGE_VARIABLES, "")
19909 		ADD_SHORTCUT(GDK_KEY_f, GDK_CONTROL_MASK, SHORTCUT_TYPE_MANAGE_FUNCTIONS, "")
19910 		ADD_SHORTCUT(GDK_KEY_u, GDK_CONTROL_MASK, SHORTCUT_TYPE_MANAGE_UNITS, "")
19911 		ADD_SHORTCUT(GDK_KEY_k, GDK_CONTROL_MASK, SHORTCUT_TYPE_KEYPAD, "")
19912 		ADD_SHORTCUT(GDK_KEY_k, GDK_MOD1_MASK, SHORTCUT_TYPE_KEYPAD, "")
19913 		ADD_SHORTCUT(GDK_KEY_h, GDK_CONTROL_MASK, SHORTCUT_TYPE_HISTORY, "")
19914 		ADD_SHORTCUT(GDK_KEY_h, GDK_MOD1_MASK, SHORTCUT_TYPE_HISTORY, "")
19915 		ADD_SHORTCUT(GDK_KEY_space, GDK_CONTROL_MASK, SHORTCUT_TYPE_MINIMAL, "")
19916 		ADD_SHORTCUT(GDK_KEY_o, GDK_CONTROL_MASK, SHORTCUT_TYPE_CONVERSION, "")
19917 		ADD_SHORTCUT(GDK_KEY_o, GDK_MOD1_MASK, SHORTCUT_TYPE_CONVERSION, "")
19918 		ADD_SHORTCUT(GDK_KEY_t, GDK_CONTROL_MASK, SHORTCUT_TYPE_CONVERT_ENTRY, "")
19919 		ADD_SHORTCUT(GDK_KEY_p, GDK_CONTROL_MASK, SHORTCUT_TYPE_PROGRAMMING, "")
19920 		ADD_SHORTCUT(GDK_KEY_r, GDK_CONTROL_MASK, SHORTCUT_TYPE_RPN_MODE, "")
19921 		ADD_SHORTCUT(GDK_KEY_parenright, GDK_CONTROL_MASK | GDK_SHIFT_MASK, SHORTCUT_TYPE_SMART_PARENTHESES, "")
19922 		ADD_SHORTCUT(GDK_KEY_parenleft, GDK_CONTROL_MASK | GDK_SHIFT_MASK, SHORTCUT_TYPE_SMART_PARENTHESES, "")
19923 		ADD_SHORTCUT(GDK_KEY_Up, GDK_CONTROL_MASK, SHORTCUT_TYPE_RPN_UP, "")
19924 		ADD_SHORTCUT(GDK_KEY_Down, GDK_CONTROL_MASK, SHORTCUT_TYPE_RPN_DOWN, "")
19925 		ADD_SHORTCUT(GDK_KEY_Right, GDK_CONTROL_MASK, SHORTCUT_TYPE_RPN_SWAP, "")
19926 		ADD_SHORTCUT(GDK_KEY_Left, GDK_CONTROL_MASK, SHORTCUT_TYPE_RPN_LASTX, "")
19927 		ADD_SHORTCUT(GDK_KEY_c, GDK_CONTROL_MASK | GDK_SHIFT_MASK, SHORTCUT_TYPE_RPN_COPY, "")
19928 		ADD_SHORTCUT(GDK_KEY_Delete, GDK_CONTROL_MASK, SHORTCUT_TYPE_RPN_DELETE, "")
19929 		ADD_SHORTCUT(GDK_KEY_Delete, GDK_CONTROL_MASK | GDK_SHIFT_MASK, SHORTCUT_TYPE_RPN_CLEAR, "")
19930 	} else if(version_numbers[0] < 3 || (version_numbers[0] == 3 && version_numbers[1] < 9)) {
19931 		keyboard_shortcut ks;
19932 		ks.key = GDK_KEY_space; ks.modifier = GDK_CONTROL_MASK; ks.type = SHORTCUT_TYPE_MINIMAL; ks.value = "";
19933 		if(keyboard_shortcuts.find((guint64) ks.key + (guint64) G_MAXUINT32 * (guint64) ks.modifier) == keyboard_shortcuts.end()) {
19934 			keyboard_shortcuts[(guint64) ks.key + (guint64) G_MAXUINT32 * (guint64) ks.modifier] = ks;
19935 		}
19936 	}
19937 	if(show_keypad && !(visible_keypad & HIDE_RIGHT_KEYPAD) && !(visible_keypad & HIDE_LEFT_KEYPAD) && (version_numbers[0] < 3 || (version_numbers[0] == 3 && version_numbers[1] < 15))) win_width = -1;
19938 	update_message_print_options();
19939 	displayed_printops = printops;
19940 	displayed_printops.allow_non_usable = true;
19941 	displayed_caf = complex_angle_form;
19942 	initial_inhistory_index = inhistory.size() - 1;
19943 	g_free(gstr_file);
19944 	show_history = show_history && (persistent_keypad || !show_keypad);
19945 	show_convert = show_convert && !show_history && (persistent_keypad || !show_keypad);
19946 	set_saved_mode();
19947 
19948 }
19949 
19950 /*
19951 	save preferences to ~/.config/qalculate/qalculate-gtk.cfg
19952 	set mode to true to save current calculator mode
19953 */
19954 
save_preferences(bool mode)19955 void save_preferences(bool mode) {
19956 	FILE *file = NULL;
19957 	string homedir = getLocalDir();
19958 	recursiveMakeDir(homedir);
19959 	gchar *gstr2 = g_build_filename(homedir.c_str(), "qalculate-gtk.cfg", NULL);
19960 	file = fopen(gstr2, "w+");
19961 	if(file == NULL) {
19962 		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);
19963 		gtk_dialog_run(GTK_DIALOG(edialog));
19964 		gtk_widget_destroy(edialog);
19965 		g_free(gstr2);
19966 		return;
19967 	}
19968 	g_free(gstr2);
19969 	gtk_revealer_set_reveal_child(GTK_REVEALER(gtk_builder_get_object(main_builder, "message_revealer")), FALSE);
19970 	gint w, h;
19971 	if(variables_builder) {
19972 		gtk_window_get_size(GTK_WINDOW(gtk_builder_get_object(variables_builder, "variables_dialog")), &w, &h);
19973 		variables_width = w;
19974 		variables_height = h;
19975 		variables_position = gtk_paned_get_position(GTK_PANED(gtk_builder_get_object(variables_builder, "variables_hpaned")));
19976 	}
19977 	if(units_builder) {
19978 		gtk_window_get_size(GTK_WINDOW(gtk_builder_get_object(units_builder, "units_dialog")), &w, &h);
19979 		units_width = w;
19980 		units_height = h;
19981 		units_position = gtk_paned_get_position(GTK_PANED(gtk_builder_get_object(units_builder, "units_hpaned")));
19982 	}
19983 	if(functions_builder) {
19984 		gtk_window_get_size(GTK_WINDOW(gtk_builder_get_object(functions_builder, "functions_dialog")), &w, &h);
19985 		functions_width = w;
19986 		functions_height = h;
19987 		functions_hposition = gtk_paned_get_position(GTK_PANED(gtk_builder_get_object(functions_builder, "functions_hpaned")));
19988 		functions_vposition = gtk_paned_get_position(GTK_PANED(gtk_builder_get_object(functions_builder, "functions_vpaned")));
19989 	}
19990 	if(datasets_builder) {
19991 		gtk_window_get_size(GTK_WINDOW(gtk_builder_get_object(datasets_builder, "datasets_dialog")), &w, &h);
19992 		datasets_width = w;
19993 		datasets_height = h;
19994 		datasets_hposition = gtk_paned_get_position(GTK_PANED(gtk_builder_get_object(datasets_builder, "datasets_hpaned")));
19995 		datasets_vposition1 = gtk_paned_get_position(GTK_PANED(gtk_builder_get_object(datasets_builder, "datasets_vpaned1")));
19996 		datasets_vposition2 = gtk_paned_get_position(GTK_PANED(gtk_builder_get_object(datasets_builder, "datasets_vpaned2")));
19997 	}
19998 	fprintf(file, "\n[General]\n");
19999 	fprintf(file, "version=%s\n", VERSION);
20000 	fprintf(file, "allow_multiple_instances=%i\n", allow_multiple_instances);
20001 	if(title_type != TITLE_APP) fprintf(file, "window_title_mode=%i\n", title_type);
20002 	if(minimal_width > 0 && minimal_mode) {
20003 		fprintf(file, "width=%i\n", win_width);
20004 	} else {
20005 		gtk_window_get_size(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), &w, &h);
20006 		fprintf(file, "width=%i\n", w);
20007 	}
20008 	//fprintf(file, "height=%i\n", h);
20009 	if(remember_position) {
20010 		gtk_window_get_position(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), &win_x, &win_y);
20011 		fprintf(file, "x=%i\n", win_x);
20012 		fprintf(file, "y=%i\n", win_y);
20013 	}
20014 #ifdef _WIN32
20015 	fprintf(file, "use_system_tray_icon=%i\n", use_systray_icon);
20016 	fprintf(file, "hide_on_startup=%i\n", hide_on_startup);
20017 #else
20018 	if(hide_on_startup) fprintf(file, "hide_on_startup=%i\n", hide_on_startup);
20019 #endif
20020 	if(variables_height > -1) fprintf(file, "variables_height=%i\n", variables_height);
20021 	if(variables_width > -1) fprintf(file, "variables_width=%i\n", variables_width);
20022 	if(variables_height > -1) fprintf(file, "variables_height=%i\n", variables_height);
20023 	if(variables_position > -1) fprintf(file, "variables_panel_position=%i\n", variables_position);
20024 	if(units_width > -1) fprintf(file, "units_width=%i\n", units_width);
20025 	if(units_height > -1) fprintf(file, "units_height=%i\n", units_height);
20026 	if(units_position > -1) fprintf(file, "units_panel_position=%i\n", units_position);
20027 	if(functions_width > -1) fprintf(file, "functions_width=%i\n", functions_width);
20028 	if(functions_height > -1) fprintf(file, "functions_height=%i\n", functions_height);
20029 	if(functions_hposition > -1) fprintf(file, "functions_hpanel_position=%i\n", functions_hposition);
20030 	if(functions_vposition > -1) fprintf(file, "functions_vpanel_position=%i\n", functions_vposition);
20031 	if(datasets_width > -1) fprintf(file, "datasets_width=%i\n", datasets_width);
20032 	if(datasets_height > -1) fprintf(file, "datasets_height=%i\n", datasets_height);
20033 	if(datasets_hposition > -1) fprintf(file, "datasets_hpanel_position=%i\n", datasets_hposition);
20034 	if(datasets_vposition1 > -1) fprintf(file, "datasets_vpanel1_position=%i\n", datasets_vposition1);
20035 	if(datasets_vposition2 > -1) fprintf(file, "datasets_vpanel2_position=%i\n", datasets_vposition2);
20036 	if(help_width != -1) fprintf(file, "help_width=%i\n", help_width);
20037 	if(help_height != -1) fprintf(file, "help_height=%i\n", help_height);
20038 	if(help_zoom >= 0.0) fprintf(file, "help_zoom=%f\n", help_zoom);
20039 	fprintf(file, "keep_function_dialog_open=%i\n", keep_function_dialog_open);
20040 	fprintf(file, "error_info_shown=%i\n", !first_error);
20041 	fprintf(file, "save_mode_on_exit=%i\n", save_mode_on_exit);
20042 	fprintf(file, "save_definitions_on_exit=%i\n", save_defs_on_exit);
20043 	fprintf(file, "clear_history_on_exit=%i\n", clear_history_on_exit);
20044 	fprintf(file, "ignore_locale=%i\n", ignore_locale);
20045 	fprintf(file, "load_global_definitions=%i\n", load_global_defs);
20046 	//fprintf(file, "fetch_exchange_rates_at_startup=%i\n", fetch_exchange_rates_at_startup);
20047 	fprintf(file, "auto_update_exchange_rates=%i\n", auto_update_exchange_rates);
20048 	fprintf(file, "local_currency_conversion=%i\n", evalops.local_currency_conversion);
20049 	fprintf(file, "use_binary_prefixes=%i\n", CALCULATOR->usesBinaryPrefixes());
20050 	fprintf(file, "check_version=%i\n", check_version);
20051 	if(check_version) {
20052 		fprintf(file, "last_version_check=%s\n", last_version_check_date.toISOString().c_str());
20053 		if(!last_found_version.empty()) fprintf(file, "last_found_version=%s\n", last_found_version.c_str());
20054 	}
20055 	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)));
20056 	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)));
20057 	h = gtk_widget_get_allocated_height(tabs);
20058 	fprintf(file, "history_height=%i\n", h > 10 ? h : history_height);
20059 	if(minimal_window_resized_timeout_id) {
20060 		g_source_remove(minimal_window_resized_timeout_id);
20061 		minimal_window_resized_timeout_id = 0;
20062 		update_minimal_width();
20063 	}
20064 	if(minimal_width > 0) fprintf(file, "minimal_width=%i\n", minimal_width);
20065 	fprintf(file, "show_stack=%i\n", rpn_mode ? gtk_expander_get_expanded(GTK_EXPANDER(expander_stack)) : show_stack);
20066 	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)));
20067 	fprintf(file, "persistent_keypad=%i\n", persistent_keypad);
20068 	fprintf(file, "minimal_mode=%i\n", minimal_mode);
20069 	fprintf(file, "continuous_conversion=%i\n", gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "convert_button_continuous_conversion"))));
20070 	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"))));
20071 	fprintf(file, "rpn_keys=%i\n", rpn_keys);
20072 	if(expression_lines > 0) fprintf(file, "expression_lines=%i\n", expression_lines);
20073 	fprintf(file, "display_expression_status=%i\n", display_expression_status);
20074 	fprintf(file, "enable_completion=%i\n", enable_completion);
20075 	fprintf(file, "enable_completion2=%i\n", enable_completion2);
20076 	fprintf(file, "completion_min=%i\n", completion_min);
20077 	fprintf(file, "completion_min2=%i\n", completion_min2);
20078 	fprintf(file, "completion_delay=%i\n", completion_delay);
20079 	fprintf(file, "calculate_as_you_type_history_delay=%i\n", autocalc_history_delay);
20080 	fprintf(file, "use_unicode_signs=%i\n", printops.use_unicode_signs);
20081 	fprintf(file, "lower_case_numbers=%i\n", printops.lower_case_numbers);
20082 	fprintf(file, "lower_case_e=%i\n", printops.lower_case_e);
20083 	fprintf(file, "e_notation=%i\n", use_e_notation);
20084 	fprintf(file, "imaginary_j=%i\n", CALCULATOR->v_i->hasName("j") > 0);
20085 	fprintf(file, "base_display=%i\n", printops.base_display);
20086 	fprintf(file, "twos_complement=%i\n", printops.twos_complement);
20087 	fprintf(file, "hexadecimal_twos_complement=%i\n", printops.hexadecimal_twos_complement);
20088 	fprintf(file, "twos_complement_input=%i\n", twos_complement_in);
20089 	fprintf(file, "hexadecimal_twos_complement_input=%i\n", hexadecimal_twos_complement_in);
20090 	if(~visible_keypad & PROGRAMMING_KEYPAD && programming_outbase != 0 && programming_inbase != 0) {
20091 		fprintf(file, "programming_outbase=%i\n", programming_outbase);
20092 		fprintf(file, "programming_inbase=%i\n", programming_inbase);
20093 	}
20094 	if(visible_keypad & PROGRAMMING_KEYPAD && versatile_exact) {
20095 		fprintf(file, "general_exact=%i\n", versatile_exact);
20096 	}
20097 	if(default_bits >= 0) fprintf(file, "bit_width=%i\n", default_bits);
20098 	if(default_signed >= 0) fprintf(file, "signed_integer=%i\n", default_signed);
20099 	fprintf(file, "spell_out_logical_operators=%i\n", printops.spell_out_logical_operators);
20100 	fprintf(file, "caret_as_xor=%i\n", caret_as_xor);
20101 	fprintf(file, "digit_grouping=%i\n", printops.digit_grouping);
20102 	fprintf(file, "copy_separator=%i\n", copy_separator);
20103 	fprintf(file, "decimal_comma=%i\n", b_decimal_comma);
20104 	fprintf(file, "dot_as_separator=%i\n", evalops.parse_options.dot_as_separator);
20105 	fprintf(file, "comma_as_separator=%i\n", evalops.parse_options.comma_as_separator);
20106 	if(use_dark_theme >= 0) fprintf(file, "use_dark_theme=%i\n", use_dark_theme);
20107 	fprintf(file, "use_custom_result_font=%i\n", use_custom_result_font);
20108 	fprintf(file, "use_custom_expression_font=%i\n", use_custom_expression_font);
20109 	fprintf(file, "use_custom_status_font=%i\n", use_custom_status_font);
20110 	fprintf(file, "use_custom_keypad_font=%i\n", use_custom_keypad_font);
20111 	fprintf(file, "use_custom_application_font=%i\n", use_custom_app_font);
20112 	if(use_custom_result_font || save_custom_result_font) fprintf(file, "custom_result_font=%s\n", custom_result_font.c_str());
20113 	if(use_custom_expression_font || save_custom_expression_font) fprintf(file, "custom_expression_font=%s\n", custom_expression_font.c_str());
20114 	if(use_custom_status_font || save_custom_status_font) fprintf(file, "custom_status_font=%s\n", custom_status_font.c_str());
20115 	if(use_custom_keypad_font || save_custom_keypad_font) fprintf(file, "custom_keypad_font=%s\n", custom_keypad_font.c_str());
20116 	if(use_custom_app_font || save_custom_app_font) fprintf(file, "custom_application_font=%s\n", custom_app_font.c_str());
20117 	if(status_error_color_set) fprintf(file, "status_error_color=%s\n", status_error_color.c_str());
20118 	if(status_warning_color_set) fprintf(file, "status_warning_color=%s\n", status_warning_color.c_str());
20119 	fprintf(file, "multiplication_sign=%i\n", printops.multiplication_sign);
20120 	fprintf(file, "division_sign=%i\n", printops.division_sign);
20121 	if(automatic_fraction) fprintf(file, "automatic_number_fraction_format=%i\n", automatic_fraction);
20122 	if(default_fraction_fraction >= 0) fprintf(file, "default_number_fraction_fraction=%i\n", default_fraction_fraction);
20123 	if(auto_prefix > 0) fprintf(file, "automatic_unit_prefixes=%i\n", auto_prefix);
20124 	if(!scientific_noprefix) fprintf(file, "scientific_mode_unit_prefixes=%i\n", true);
20125 	if(!scientific_notminuslast) fprintf(file, "scientific_mode_sort_minus_last=%i\n", true);
20126 	if(!scientific_negexp) fprintf(file, "scientific_mode_negative_exponents=%i\n", false);
20127 	if(tc_set) fprintf(file, "temperature_calculation=%i\n", CALCULATOR->getTemperatureCalculationMode());
20128 	for(unsigned int i = 0; i < custom_buttons.size(); i++) {
20129 		if(!custom_buttons[i].text.empty()) fprintf(file, "custom_button_label=%u:%s\n", i, custom_buttons[i].text.c_str());
20130 		for(unsigned int bi = 0; bi <= 2; bi++) {
20131 			if(custom_buttons[i].type[bi] != -1) {
20132 				if(custom_buttons[i].value[bi].empty()) fprintf(file, "custom_button=%u:%u:%i\n", i, bi, custom_buttons[i].type[bi]);
20133 				else fprintf(file, "custom_button=%u:%u:%i:%s\n", i, bi, custom_buttons[i].type[bi], custom_buttons[i].value[bi].c_str());
20134 			}
20135 		}
20136 	}
20137 	if(!default_shortcuts) {
20138 		std::vector<guint64> ksv;
20139 		ksv.reserve(keyboard_shortcuts.size());
20140 		for(unordered_map<guint64, keyboard_shortcut>::iterator it = keyboard_shortcuts.begin(); it != keyboard_shortcuts.end(); ++it) {
20141 			if(ksv.empty() || it->first > ksv.back()) {
20142 				ksv.push_back(it->first);
20143 			} else {
20144 				for(vector<guint64>::iterator it2 = ksv.begin(); it2 != ksv.end(); ++it2) {
20145 					if(it->first <= *it2) {ksv.insert(it2, it->first); break;}
20146 				}
20147 			}
20148 		}
20149 		for(size_t i = 0; i < ksv.size(); i++) {
20150 			unordered_map<guint64, keyboard_shortcut>::iterator it = keyboard_shortcuts.find(ksv[i]);
20151 			if(it->second.value.empty()) fprintf(file, "keyboard_shortcut=%u:%u:%i\n", it->second.key, it->second.modifier, it->second.type);
20152 			else fprintf(file, "keyboard_shortcut=%u:%u:%i:%s\n", it->second.key, it->second.modifier, it->second.type, it->second.value.c_str());
20153 		}
20154 	}
20155 	if(!clear_history_on_exit) {
20156 		for(size_t i = 0; i < expression_history.size(); i++) {
20157 			gsub("\n", " ", expression_history[i]);
20158 			fprintf(file, "expression_history=%s\n", expression_history[i].c_str());
20159 		}
20160 	}
20161 
20162 	int lines = 300;
20163 	bool end_after_result = false, end_before_expression = false;
20164 	bool is_protected = false;
20165 	bool is_bookmarked = false;
20166 	bool doend = false;
20167 	size_t hi = inhistory.size();
20168 	while(!doend && hi > 0) {
20169 		hi--;
20170 		switch(inhistory_type[hi]) {
20171 			case QALCULATE_HISTORY_EXPRESSION: {
20172 				if(end_before_expression) {
20173 					doend = true;
20174 				} else {
20175 					if(inhistory_protected[hi]) fprintf(file, "history_expression*=");
20176 					else if(!clear_history_on_exit || is_bookmarked) fprintf(file, "history_expression=");
20177 					is_protected = inhistory_protected[hi] || is_bookmarked;
20178 					is_bookmarked = false;
20179 				}
20180 				break;
20181 			}
20182 			case QALCULATE_HISTORY_TRANSFORMATION: {
20183 				if(clear_history_on_exit && !is_protected) break;
20184 				fprintf(file, "history_transformation=");
20185 				break;
20186 			}
20187 			case QALCULATE_HISTORY_RESULT: {
20188 				if(end_after_result) doend = true;
20189 				if(clear_history_on_exit && !is_protected) break;
20190 				fprintf(file, "history_result=");
20191 				lines--;
20192 				break;
20193 			}
20194 			case QALCULATE_HISTORY_RESULT_APPROXIMATE: {
20195 				if(end_after_result) doend = true;
20196 				if(clear_history_on_exit && !is_protected) break;
20197 				fprintf(file, "history_result_approximate=");
20198 				lines--;
20199 				break;
20200 			}
20201 			case QALCULATE_HISTORY_PARSE: {}
20202 			case QALCULATE_HISTORY_PARSE_WITHEQUALS: {}
20203 			case QALCULATE_HISTORY_PARSE_APPROXIMATE: {
20204 				if(clear_history_on_exit && !is_protected) break;
20205 				if(inhistory_type[hi] == QALCULATE_HISTORY_PARSE) fprintf(file, "history_parse=");
20206 				else if(inhistory_type[hi] == QALCULATE_HISTORY_PARSE_WITHEQUALS) fprintf(file, "history_parse_withequals=");
20207 				else fprintf(file, "history_parse_approximate=");
20208 				lines--;
20209 				if(lines < 0) {
20210 					if(hi + 1 < inhistory_protected.size() && inhistory_protected[hi + 1]) {
20211 						end_before_expression = true;
20212 					} else if(hi + 2 < inhistory_type.size() && inhistory_type[hi + 2] == QALCULATE_HISTORY_BOOKMARK) {
20213 						end_before_expression = true;
20214 					}
20215 					if(!end_before_expression) end_after_result = true;
20216 				}
20217 				break;
20218 			}
20219 			case QALCULATE_HISTORY_REGISTER_MOVED: {
20220 				if(end_before_expression) {
20221 					doend = true;
20222 				} else {
20223 					if(inhistory_protected[hi]) fprintf(file, "history_register_moved*=");
20224 					else if(!clear_history_on_exit || is_bookmarked) fprintf(file, "history_register_moved=");
20225 					is_protected = inhistory_protected[hi] || is_bookmarked;
20226 					is_bookmarked = false;
20227 				}
20228 				break;
20229 			}
20230 			case QALCULATE_HISTORY_RPN_OPERATION: {
20231 				if(end_before_expression) {
20232 					doend = true;
20233 				} else {
20234 					if(inhistory_protected[hi]) fprintf(file, "history_rpn_operation*=");
20235 					else if(!clear_history_on_exit || is_bookmarked) fprintf(file, "history_rpn_operation=");
20236 					is_protected = inhistory_protected[hi] || is_bookmarked;
20237 					is_bookmarked = false;
20238 				}
20239 				break;
20240 			}
20241 			case QALCULATE_HISTORY_WARNING: {
20242 				if(clear_history_on_exit && !is_protected) break;
20243 				fprintf(file, "history_warning=");
20244 				lines--;
20245 				break;
20246 			}
20247 			case QALCULATE_HISTORY_MESSAGE: {
20248 				if(clear_history_on_exit && !is_protected) break;
20249 				fprintf(file, "history_message=");
20250 				lines--;
20251 				break;
20252 			}
20253 			case QALCULATE_HISTORY_ERROR: {
20254 				if(clear_history_on_exit && !is_protected) break;
20255 				fprintf(file, "history_error=");
20256 				lines--;
20257 				break;
20258 			}
20259 			case QALCULATE_HISTORY_BOOKMARK: {
20260 				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)) {
20261 					doend = true;
20262 				} else {
20263 					fprintf(file, "history_bookmark=");
20264 					is_bookmarked = true;
20265 					is_protected = true;
20266 					lines--;
20267 					break;
20268 				}
20269 			}
20270 			case QALCULATE_HISTORY_OLD: {
20271 				if(clear_history_on_exit && !is_protected) break;
20272 				fprintf(file, "history_old=");
20273 				lines--;
20274 				if(lines < 0) doend = true;
20275 				break;
20276 			}
20277 		}
20278 		if(doend && end_before_expression) break;
20279 		if(!clear_history_on_exit || is_protected) {
20280 			size_t i3 = inhistory[hi].find('\n');
20281 			if(i3 == string::npos) {
20282 				if(!is_protected && inhistory[hi].length() > 5000) {
20283 					int index = 50;
20284 					while(index >= 0 && inhistory[hi][index] < 0) index--;
20285 					fprintf(file, "%s …\n", inhistory[hi].substr(0, index + 1).c_str());
20286 				} else {
20287 					fprintf(file, "%s\n", inhistory[hi].c_str());
20288 					if(inhistory[hi].length() > 300) {
20289 						if(inhistory[hi].length() > 9000) lines -= 30;
20290 						else lines -= inhistory[hi].length() / 300;
20291 					}
20292 				}
20293 			} else {
20294 				fprintf(file, "%s\n", inhistory[hi].substr(0, i3).c_str());
20295 				i3++;
20296 				size_t i2 = inhistory[hi].find('\n', i3);
20297 				while(i2 != string::npos) {
20298 					fprintf(file, "history_continued=%s\n", inhistory[hi].substr(i3, i2 - i3).c_str());
20299 					lines--;
20300 					i3 = i2 + 1;
20301 					i2 = inhistory[hi].find('\n', i3);
20302 				}
20303 				fprintf(file, "history_continued=%s\n", inhistory[hi].substr(i3, inhistory[hi].length() - i3).c_str());
20304 				lines--;
20305 			}
20306 		}
20307 	}
20308 	while(hi >= 0 && inhistory.size() > 0) {
20309 		if(inhistory_protected[hi] || (inhistory_type[hi] == QALCULATE_HISTORY_BOOKMARK && hi != 0 && inhistory_type[hi - 1] != QALCULATE_HISTORY_OLD)) {
20310 			bool b_first = true;
20311 			while(hi >= 0) {
20312 				bool do_end = false;
20313 				switch(inhistory_type[hi]) {
20314 					case QALCULATE_HISTORY_EXPRESSION: {
20315 						if(!b_first) {
20316 							do_end = true;
20317 						} else {
20318 							if(inhistory_protected[hi]) fprintf(file, "history_expression*=");
20319 							else fprintf(file, "history_expression=");
20320 							b_first = false;
20321 						}
20322 						break;
20323 					}
20324 					case QALCULATE_HISTORY_TRANSFORMATION: {
20325 						fprintf(file, "history_transformation=");
20326 						break;
20327 					}
20328 					case QALCULATE_HISTORY_RESULT: {
20329 						fprintf(file, "history_result=");
20330 						break;
20331 					}
20332 					case QALCULATE_HISTORY_RESULT_APPROXIMATE: {
20333 						fprintf(file, "history_result_approximate=");
20334 						break;
20335 					}
20336 					case QALCULATE_HISTORY_PARSE: {
20337 						fprintf(file, "history_parse=");
20338 						break;
20339 					}
20340 					case QALCULATE_HISTORY_PARSE_WITHEQUALS: {
20341 						fprintf(file, "history_parse_withequals=");
20342 						break;
20343 					}
20344 					case QALCULATE_HISTORY_PARSE_APPROXIMATE: {
20345 						fprintf(file, "history_parse_approximate=");
20346 						break;
20347 					}
20348 					case QALCULATE_HISTORY_REGISTER_MOVED: {
20349 						if(!b_first) {
20350 							do_end = true;
20351 						} else {
20352 							if(inhistory_protected[hi]) fprintf(file, "history_register_moved*=");
20353 							else fprintf(file, "history_register_moved=");
20354 							b_first = false;
20355 						}
20356 						break;
20357 					}
20358 					case QALCULATE_HISTORY_RPN_OPERATION: {
20359 						if(!b_first) {
20360 							do_end = true;
20361 						} else {
20362 							if(inhistory_protected[hi]) fprintf(file, "history_rpn_operation*=");
20363 							else fprintf(file, "history_rpn_operation=");
20364 							b_first = false;
20365 						}
20366 						break;
20367 					}
20368 					case QALCULATE_HISTORY_WARNING: {
20369 						fprintf(file, "history_warning=");
20370 						break;
20371 					}
20372 					case QALCULATE_HISTORY_MESSAGE: {
20373 						fprintf(file, "history_message=");
20374 						break;
20375 					}
20376 					case QALCULATE_HISTORY_ERROR: {
20377 						fprintf(file, "history_error=");
20378 						break;
20379 					}
20380 					case QALCULATE_HISTORY_BOOKMARK: {
20381 						if(!b_first) {
20382 							do_end = true;
20383 							break;
20384 						}
20385 						fprintf(file, "history_bookmark=");
20386 						break;
20387 					}
20388 					case QALCULATE_HISTORY_OLD: {
20389 						do_end = true;
20390 						break;
20391 					}
20392 				}
20393 				if(do_end) {
20394 					hi++;
20395 					break;
20396 				}
20397 				size_t i3 = inhistory[hi].find('\n');
20398 				if(i3 == string::npos) {
20399 					fprintf(file, "%s\n", inhistory[hi].c_str());
20400 				} else {
20401 					fprintf(file, "%s\n", inhistory[hi].substr(0, i3).c_str());
20402 					i3++;
20403 					size_t i2 = inhistory[hi].find('\n', i3);
20404 					while(i2 != string::npos) {
20405 						fprintf(file, "history_continued=%s\n", inhistory[hi].substr(i3, i2 - i3).c_str());
20406 						i3 = i2 + 1;
20407 						i2 = inhistory[hi].find('\n', i3);
20408 					}
20409 					fprintf(file, "history_continued=%s\n", inhistory[hi].substr(i3, inhistory[hi].length() - i3).c_str());
20410 				}
20411 				if(hi == 0) break;
20412 				hi--;
20413 			}
20414 			if(hi > inhistory_type.size()) break;
20415 		}
20416 		if(hi == 0) break;
20417 		hi--;
20418 	}
20419 
20420 	fprintf(file, "recent_functions=");
20421 	for(int i = (int) (recent_functions.size()) - 1; i >= 0; i--) {
20422 		fprintf(file, "%s", recent_functions[i]->referenceName().c_str());
20423 		if(i != 0) fprintf(file, ",");
20424 	}
20425 	fprintf(file, "\n");
20426 	fprintf(file, "recent_variables=");
20427 	for(int i = (int) (recent_variables.size()) - 1; i >= 0; i--) {
20428 		fprintf(file, "%s", recent_variables[i]->referenceName().c_str());
20429 		if(i != 0) fprintf(file, ",");
20430 	}
20431 	fprintf(file, "\n");
20432 	fprintf(file, "recent_units=");
20433 	for(int i = (int) (recent_units.size()) - 1; i >= 0; i--) {
20434 		fprintf(file, "%s", recent_units[i]->referenceName().c_str());
20435 		if(i != 0) fprintf(file, ",");
20436 	}
20437 	fprintf(file, "\n");
20438 	if(latest_button_unit) fprintf(file, "latest_button_unit=%s\n", latest_button_unit->referenceName().c_str());
20439 	if(latest_button_currency) fprintf(file, "latest_button_currency=%s\n", latest_button_currency->referenceName().c_str());
20440 	if(mode) set_saved_mode();
20441 	for(size_t i = 1; i < modes.size(); i++) {
20442 		if(i == 1) {
20443 			fprintf(file, "\n[Mode]\n");
20444 		} else {
20445 			fprintf(file, "\n[Mode %s]\n", modes[i].name.c_str());
20446 		}
20447 		fprintf(file, "min_deci=%i\n", modes[i].po.min_decimals);
20448 		fprintf(file, "use_min_deci=%i\n", modes[i].po.use_min_decimals);
20449 		fprintf(file, "max_deci=%i\n", modes[i].po.max_decimals);
20450 		fprintf(file, "use_max_deci=%i\n", modes[i].po.use_max_decimals);
20451 		fprintf(file, "precision=%i\n", modes[i].precision);
20452 		fprintf(file, "interval_arithmetic=%i\n", modes[i].interval);
20453 		fprintf(file, "interval_display=%i\n", modes[i].adaptive_interval_display ? 0 : modes[i].po.interval_display + 1);
20454 		fprintf(file, "min_exp=%i\n", modes[i].po.min_exp);
20455 		fprintf(file, "negative_exponents=%i\n", modes[i].po.negative_exponents);
20456 		fprintf(file, "sort_minus_last=%i\n", modes[i].po.sort_options.minus_last);
20457 		fprintf(file, "number_fraction_format=%i\n", modes[i].po.number_fraction_format);
20458 		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);
20459 		fprintf(file, "use_prefixes=%i\n", modes[i].po.use_unit_prefixes);
20460 		fprintf(file, "use_prefixes_for_all_units=%i\n", modes[i].po.use_prefixes_for_all_units);
20461 		fprintf(file, "use_prefixes_for_currencies=%i\n", modes[i].po.use_prefixes_for_currencies);
20462 		fprintf(file, "abbreviate_names=%i\n", modes[i].po.abbreviate_names);
20463 		fprintf(file, "all_prefixes_enabled=%i\n", modes[i].po.use_all_prefixes);
20464 		fprintf(file, "denominator_prefix_enabled=%i\n", modes[i].po.use_denominator_prefix);
20465 		fprintf(file, "place_units_separately=%i\n", modes[i].po.place_units_separately);
20466 		fprintf(file, "auto_post_conversion=%i\n", modes[i].eo.auto_post_conversion);
20467 		fprintf(file, "mixed_units_conversion=%i\n", modes[i].eo.mixed_units_conversion);
20468 		fprintf(file, "number_base=%i\n", modes[i].po.base);
20469 		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());
20470 		fprintf(file, "number_base_expression=%i\n", modes[i].eo.parse_options.base);
20471 		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());
20472 		fprintf(file, "read_precision=%i\n", modes[i].eo.parse_options.read_precision);
20473 		fprintf(file, "assume_denominators_nonzero=%i\n", modes[i].eo.assume_denominators_nonzero);
20474 		fprintf(file, "warn_about_denominators_assumed_nonzero=%i\n", modes[i].eo.warn_about_denominators_assumed_nonzero);
20475 		fprintf(file, "structuring=%i\n", modes[i].eo.structuring);
20476 		fprintf(file, "angle_unit=%i\n", modes[i].eo.parse_options.angle_unit);
20477 		fprintf(file, "functions_enabled=%i\n", modes[i].eo.parse_options.functions_enabled);
20478 		fprintf(file, "variables_enabled=%i\n", modes[i].eo.parse_options.variables_enabled);
20479 		fprintf(file, "calculate_functions=%i\n", modes[i].eo.calculate_functions);
20480 		fprintf(file, "calculate_variables=%i\n", modes[i].eo.calculate_variables);
20481 		fprintf(file, "variable_units_enabled=%i\n", modes[i].variable_units_enabled);
20482 		fprintf(file, "sync_units=%i\n", modes[i].eo.sync_units);
20483 		fprintf(file, "unknownvariables_enabled=%i\n", modes[i].eo.parse_options.unknowns_enabled);
20484 		fprintf(file, "units_enabled=%i\n", modes[i].eo.parse_options.units_enabled);
20485 		fprintf(file, "allow_complex=%i\n", modes[i].eo.allow_complex);
20486 		fprintf(file, "allow_infinite=%i\n", modes[i].eo.allow_infinite);
20487 		fprintf(file, "indicate_infinite_series=%i\n", modes[i].po.indicate_infinite_series);
20488 		fprintf(file, "show_ending_zeroes=%i\n", modes[i].po.show_ending_zeroes);
20489 		fprintf(file, "round_halfway_to_even=%i\n", modes[i].po.round_halfway_to_even);
20490 		fprintf(file, "approximation=%i\n", modes[i].eo.approximation);
20491 		fprintf(file, "interval_calculation=%i\n", modes[i].eo.interval_calculation);
20492 		fprintf(file, "calculate_as_you_type=%i\n", modes[i].autocalc);
20493 		fprintf(file, "in_rpn_mode=%i\n", modes[i].rpn_mode);
20494 		fprintf(file, "chain_mode=%i\n", modes[i].chain_mode);
20495 		fprintf(file, "limit_implicit_multiplication=%i\n", modes[i].eo.parse_options.limit_implicit_multiplication);
20496 		fprintf(file, "parsing_mode=%i\n", modes[i].eo.parse_options.parsing_mode);
20497 		fprintf(file, "spacious=%i\n", modes[i].po.spacious);
20498 		fprintf(file, "excessive_parenthesis=%i\n", modes[i].po.excessive_parenthesis);
20499 		fprintf(file, "visible_keypad=%i\n", modes[i].keypad);
20500 		fprintf(file, "short_multiplication=%i\n", modes[i].po.short_multiplication);
20501 		fprintf(file, "default_assumption_type=%i\n", modes[i].at);
20502 		fprintf(file, "default_assumption_sign=%i\n", modes[i].as);
20503 	}
20504 	fprintf(file, "\n[Plotting]\n");
20505 	fprintf(file, "plot_legend_placement=%i\n", default_plot_legend_placement);
20506 	fprintf(file, "plot_style=%i\n", default_plot_style);
20507 	fprintf(file, "plot_smoothing=%i\n", default_plot_smoothing);
20508 	fprintf(file, "plot_display_grid=%i\n", default_plot_display_grid);
20509 	fprintf(file, "plot_full_border=%i\n", default_plot_full_border);
20510 	fprintf(file, "plot_min=%s\n", default_plot_min.c_str());
20511 	fprintf(file, "plot_max=%s\n", default_plot_max.c_str());
20512 	fprintf(file, "plot_step=%s\n", default_plot_step.c_str());
20513 	fprintf(file, "plot_sampling_rate=%i\n", default_plot_sampling_rate);
20514 	fprintf(file, "plot_use_sampling_rate=%i\n", default_plot_use_sampling_rate);
20515 	fprintf(file, "plot_variable=%s\n", default_plot_variable.c_str());
20516 	fprintf(file, "plot_rows=%i\n", default_plot_rows);
20517 	fprintf(file, "plot_type=%i\n", default_plot_type);
20518 	fprintf(file, "plot_color=%i\n", default_plot_color);
20519 	fprintf(file, "plot_linewidth=%i\n", default_plot_linewidth);
20520 	if(max_plot_time != 5) fprintf(file, "max_plot_time=%i\n", max_plot_time);
20521 
20522 	fclose(file);
20523 
20524 }
20525 
20526 /*
20527 	tree text sort function
20528 */
string_sort_func(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,gpointer user_data)20529 gint string_sort_func(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data) {
20530 	gint cid = GPOINTER_TO_INT(user_data);
20531 	gchar *gstr1, *gstr2;
20532 	gint retval;
20533 	gtk_tree_model_get(model, a, cid, &gstr1, -1);
20534 	gtk_tree_model_get(model, b, cid, &gstr2, -1);
20535 	retval = g_ascii_strcasecmp(gstr1, gstr2);
20536 	g_free(gstr1);
20537 	g_free(gstr2);
20538 	return retval;
20539 }
20540 
20541 /*
20542 	completion sort function
20543 */
completion_sort_func(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,gpointer user_data)20544 gint completion_sort_func(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data) {
20545 	gint i1 = 0, i2 = 0;
20546 	gtk_tree_model_get(model, a, 4, &i1, -1);
20547 	gtk_tree_model_get(model, b, 4, &i2, -1);
20548 	if(i1 < i2) return -1;
20549 	if(i1 > i2) return 1;
20550 	gchar *gstr1, *gstr2;
20551 	gint retval;
20552 	gint cid = GPOINTER_TO_INT(user_data);
20553 	gtk_tree_model_get(model, a, cid, &gstr1, -1);
20554 	gtk_tree_model_get(model, b, cid, &gstr2, -1);
20555 	retval = g_ascii_strcasecmp(gstr1, gstr2);
20556 	g_free(gstr1);
20557 	g_free(gstr2);
20558 	return retval;
20559 }
20560 
20561 /*
20562 	tree sort function for number strings
20563 */
int_string_sort_func(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,gpointer user_data)20564 gint int_string_sort_func(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data) {
20565 	gint cid = GPOINTER_TO_INT(user_data);
20566 	gchar *gstr1, *gstr2;
20567 	bool b1 = false, b2 = false;
20568 	gint retval;
20569 	gtk_tree_model_get(model, a, cid, &gstr1, -1);
20570 	gtk_tree_model_get(model, b, cid, &gstr2, -1);
20571 	if(gstr1[0] == '-') {
20572 		b1 = true;
20573 	}
20574 	if(gstr2[0] == '-') {
20575 		b2 = true;
20576 	}
20577 	if(b1 == b2)
20578 		retval = g_ascii_strcasecmp(gstr1, gstr2);
20579 	else if(b1)
20580 		retval = -1;
20581 	else
20582 		retval = 1;
20583 	g_free(gstr1);
20584 	g_free(gstr2);
20585 	return retval;
20586 }
20587 /*
20588 	display preferences dialog
20589 */
edit_preferences()20590 void edit_preferences() {
20591 	GtkWidget *dialog = get_preferences_dialog();
20592 	gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")));
20593 	gtk_widget_show(dialog);
20594 }
20595 
font_name_to_css(const char * font_name,const char * w)20596 gchar *font_name_to_css(const char *font_name, const char *w) {
20597 	gchar *gstr = NULL;
20598 	PangoFontDescription *font_desc = pango_font_description_from_string(font_name);
20599 	gint size = pango_font_description_get_size(font_desc) / PANGO_SCALE;
20600 	switch(pango_font_description_get_style(font_desc)) {
20601 		case PANGO_STYLE_NORMAL: {
20602 			gstr = g_strdup_printf("%s {font-family: %s; font-weight: %i; font-size: %ipt;}", w, pango_font_description_get_family(font_desc), pango_font_description_get_weight(font_desc), size);
20603 			break;
20604 		}
20605 		case PANGO_STYLE_OBLIQUE: {
20606 			gstr = g_strdup_printf("%s {font-family: %s; font-weight: %i; font-size: %ipt; font-style: oblique;}", w, pango_font_description_get_family(font_desc), pango_font_description_get_weight(font_desc), size);
20607 			break;
20608 		}
20609 		case PANGO_STYLE_ITALIC: {
20610 			gstr = g_strdup_printf("%s {font-family: %s; font-weight: %i; font-size: %ipt; font-style: italic;}", w, pango_font_description_get_family(font_desc), pango_font_description_get_weight(font_desc), size);
20611 			break;
20612 		}
20613 	}
20614 	pango_font_description_free(font_desc);
20615 	return gstr;
20616 }
20617 
20618 #ifdef __cplusplus
20619 extern "C" {
20620 #endif
20621 
20622 bool do_shortcut(int type, string value);
20623 
on_button_minimal_mode_button_press_event(GtkWidget *,GdkEventButton * event,gpointer)20624 gboolean on_button_minimal_mode_button_press_event(GtkWidget*, GdkEventButton *event, gpointer) {
20625 	if(event->button != 1) return FALSE;
20626 	set_minimal_mode(false);
20627 	return TRUE;
20628 }
on_menu_item_minimal_mode_activate(GtkMenuItem *,gpointer)20629 void on_menu_item_minimal_mode_activate(GtkMenuItem*, gpointer) {
20630 	set_minimal_mode(true);
20631 }
20632 
20633 void on_button_bin_toggled(GtkToggleButton *w, gpointer);
20634 void on_button_oct_toggled(GtkToggleButton *w, gpointer);
20635 void on_button_dec_toggled(GtkToggleButton *w, gpointer);
20636 void on_button_hex_toggled(GtkToggleButton *w, gpointer);
20637 
on_button_twos_out_toggled(GtkToggleButton * w,gpointer)20638 void on_button_twos_out_toggled(GtkToggleButton *w, gpointer) {
20639 	if(printops.base == 16) printops.hexadecimal_twos_complement = gtk_toggle_button_get_active(w);
20640 	else if(printops.base == 2) printops.twos_complement = gtk_toggle_button_get_active(w);
20641 	result_format_updated();
20642 	focus_keeping_selection();
20643 }
on_button_twos_in_toggled(GtkToggleButton * w,gpointer)20644 void on_button_twos_in_toggled(GtkToggleButton *w, gpointer) {
20645 	if(evalops.parse_options.base == 16) {
20646 		hexadecimal_twos_complement_in = gtk_toggle_button_get_active(w);
20647 		evalops.parse_options.hexadecimal_twos_complement = hexadecimal_twos_complement_in;
20648 	} else if(evalops.parse_options.base == 2) {
20649 		twos_complement_in = gtk_toggle_button_get_active(w);
20650 		evalops.parse_options.twos_complement = twos_complement_in;
20651 	}
20652 	expression_format_updated(true);
20653 	focus_keeping_selection();
20654 }
20655 
update_keypad_bases()20656 void update_keypad_bases() {
20657 	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);
20658 	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);
20659 	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);
20660 	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);
20661 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "button_bin")), printops.base == 2 && evalops.parse_options.base == 2);
20662 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "button_oct")), printops.base == 8 && evalops.parse_options.base == 8);
20663 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "button_dec")), printops.base == 10 && evalops.parse_options.base == 10);
20664 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "button_hex")), printops.base == 16 && evalops.parse_options.base == 16);
20665 	gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "button_bin")), (printops.base == 2) != (evalops.parse_options.base == 2));
20666 	gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "button_oct")), (printops.base == 8) != (evalops.parse_options.base == 8));
20667 	gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "button_dec")), (printops.base == 10) != (evalops.parse_options.base == 10));
20668 	gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "button_hex")), (printops.base == 16) != (evalops.parse_options.base == 16));
20669 	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);
20670 	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);
20671 	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);
20672 	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);
20673 
20674 	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);
20675 	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));
20676 	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);
20677 
20678 	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);
20679 	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));
20680 	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);
20681 
20682 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_a")), evalops.parse_options.base >= 13 || evalops.parse_options.base == 11);
20683 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_b")), evalops.parse_options.base >= 13);
20684 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_c")), evalops.parse_options.base >= 13);
20685 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_d")), evalops.parse_options.base >= 14);
20686 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_e")), evalops.parse_options.base >= 15);
20687 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_f")), evalops.parse_options.base >= 16);
20688 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_twos_out")), printops.base == 2 || printops.base == 16);
20689 	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);
20690 
20691 	evalops.parse_options.hexadecimal_twos_complement = hexadecimal_twos_complement_in && evalops.parse_options.base == 16;
20692 	evalops.parse_options.twos_complement = twos_complement_in && evalops.parse_options.base == 2;
20693 
20694 }
20695 
update_menu_base()20696 void update_menu_base() {
20697 	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);
20698 	switch(printops.base) {
20699 		case 2: {
20700 			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);
20701 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_binary")), TRUE);
20702 			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);
20703 			gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_base")), 0);
20704 			break;
20705 		}
20706 		case 8: {
20707 			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);
20708 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_octal")), TRUE);
20709 			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);
20710 			gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_base")), 1);
20711 			break;
20712 		}
20713 		case 10: {
20714 			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);
20715 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_decimal")), TRUE);
20716 			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);
20717 			gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_base")), 2);
20718 			break;
20719 		}
20720 		case 16: {
20721 			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);
20722 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_hexadecimal")), TRUE);
20723 			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);
20724 			gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_base")), 4);
20725 			break;
20726 		}
20727 		default: {
20728 			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);
20729 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_custom_base")), TRUE);
20730 			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);
20731 			if(printops.base == BASE_DUODECIMAL) gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_base")), 3);
20732 			else if(printops.base == BASE_SEXAGESIMAL) gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_base")), 5);
20733 			else if(printops.base == BASE_TIME) gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_base")), 6);
20734 			else if(printops.base == BASE_ROMAN_NUMERALS) gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_base")), 7);
20735 			else gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_base")), 8);
20736 		}
20737 	}
20738 	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);
20739 }
20740 
base_button_alternative(int base)20741 void base_button_alternative(int base) {
20742 	to_base = 0;
20743 	to_bits = 0;
20744 	if(printops.base != base) {
20745 		printops.base = base;
20746 	} else if(evalops.parse_options.base != base) {
20747 		printops.base = evalops.parse_options.base;
20748 	} else {
20749 		printops.base = 10;
20750 	}
20751 	update_menu_base();
20752 	output_base_updated_from_menu();
20753 	update_keypad_bases();
20754 	result_format_updated();
20755 	focus_keeping_selection();
20756 }
20757 
on_button_bin_toggled(GtkToggleButton * w,gpointer)20758 void on_button_bin_toggled(GtkToggleButton *w, gpointer) {
20759 	if(!gtk_toggle_button_get_active(w)) {
20760 		update_keypad_bases();
20761 		return;
20762 	}
20763 	if(printops.base != 2) {
20764 		to_base = 0;
20765 		to_bits = 0;
20766 		printops.base = 2;
20767 		update_menu_base();
20768 		output_base_updated_from_menu();
20769 		if(evalops.parse_options.base == 2) {update_keypad_bases(); result_format_updated();}
20770 	}
20771 	if(evalops.parse_options.base != 2) {
20772 		evalops.parse_options.base = 2;
20773 		input_base_updated_from_menu();
20774 		update_keypad_bases();
20775 		expression_format_updated(false);
20776 	}
20777 	focus_keeping_selection();
20778 }
on_button_oct_toggled(GtkToggleButton * w,gpointer)20779 void on_button_oct_toggled(GtkToggleButton *w, gpointer) {
20780 	if(!gtk_toggle_button_get_active(w)) {
20781 		update_keypad_bases();
20782 		return;
20783 	}
20784 	if(printops.base != 8) {
20785 		to_base = 0;
20786 		to_bits = 0;
20787 		printops.base = 8;
20788 		update_menu_base();
20789 		output_base_updated_from_menu();
20790 		if(evalops.parse_options.base == 8) {update_keypad_bases(); result_format_updated();}
20791 	}
20792 	if(evalops.parse_options.base != 8) {
20793 		evalops.parse_options.base = 8;
20794 		input_base_updated_from_menu();
20795 		update_keypad_bases();
20796 		expression_format_updated(false);
20797 	}
20798 	focus_keeping_selection();
20799 }
on_button_dec_toggled(GtkToggleButton * w,gpointer)20800 void on_button_dec_toggled(GtkToggleButton *w, gpointer) {
20801 	if(!gtk_toggle_button_get_active(w)) {
20802 		update_keypad_bases();
20803 		return;
20804 	}
20805 	if(printops.base != 10) {
20806 		to_base = 0;
20807 		to_bits = 0;
20808 		printops.base = 10;
20809 		update_menu_base();
20810 		output_base_updated_from_menu();
20811 		if(evalops.parse_options.base == 10) {update_keypad_bases(); result_format_updated();}
20812 	}
20813 	if(evalops.parse_options.base != 10) {
20814 		evalops.parse_options.base = 10;
20815 		input_base_updated_from_menu();
20816 		update_keypad_bases();
20817 		expression_format_updated(false);
20818 	}
20819 	focus_keeping_selection();
20820 }
on_button_hex_toggled(GtkToggleButton * w,gpointer)20821 void on_button_hex_toggled(GtkToggleButton *w, gpointer) {
20822 	if(!gtk_toggle_button_get_active(w)) {
20823 		update_keypad_bases();
20824 		return;
20825 	}
20826 	if(printops.base != 16) {
20827 		to_base = 0;
20828 		to_bits = 0;
20829 		printops.base = 16;
20830 		update_menu_base();
20831 		output_base_updated_from_menu();
20832 		if(evalops.parse_options.base == 16) {update_keypad_bases(); result_format_updated();}
20833 	}
20834 	if(evalops.parse_options.base != 16) {
20835 		evalops.parse_options.base = 16;
20836 		input_base_updated_from_menu();
20837 		update_keypad_bases();
20838 		expression_format_updated(false);
20839 	}
20840 	focus_keeping_selection();
20841 }
20842 
on_convert_treeview_category_row_expanded(GtkTreeView * tree_view,GtkTreeIter *,GtkTreePath * path,gpointer)20843 void on_convert_treeview_category_row_expanded(GtkTreeView *tree_view, GtkTreeIter*, GtkTreePath *path, gpointer) {
20844 	if(gtk_tree_path_get_depth(path) != 2) return;
20845 	GtkTreeModel *model = gtk_tree_view_get_model(tree_view);
20846 	GtkTreeIter iter2, iter3;
20847 	gtk_tree_model_get_iter_first(model, &iter3);
20848 	if(gtk_tree_model_iter_children(model, &iter2, &iter3)) {
20849 		do {
20850 			GtkTreePath *path2 = gtk_tree_model_get_path(model, &iter2);
20851 			if(gtk_tree_path_compare(path, path2) != 0) gtk_tree_view_collapse_row(GTK_TREE_VIEW(tUnitSelectorCategories), path2);
20852 			gtk_tree_path_free(path2);
20853 		} while(gtk_tree_model_iter_next(model, &iter2));
20854 	}
20855 	gtk_tree_view_scroll_to_cell(tree_view, path, NULL, FALSE, 0, 0);
20856 }
20857 
on_message_bar_response(GtkInfoBar * w,gint response_id,gpointer)20858 void on_message_bar_response(GtkInfoBar *w, gint response_id, gpointer) {
20859 	if(response_id == GTK_RESPONSE_CLOSE) {
20860 		gint w, h, dur;
20861 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(main_builder, "message_label")), "");
20862 		gtk_window_get_size(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), &w, &h);
20863 		h -= gtk_widget_get_allocated_height(GTK_WIDGET(gtk_builder_get_object(main_builder, "message_bar")));
20864 		dur = gtk_revealer_get_transition_duration(GTK_REVEALER(gtk_builder_get_object(main_builder, "message_revealer")));
20865 		gtk_revealer_set_transition_duration(GTK_REVEALER(gtk_builder_get_object(main_builder, "message_revealer")), 0);
20866 		gtk_revealer_set_reveal_child(GTK_REVEALER(gtk_builder_get_object(main_builder, "message_revealer")), FALSE);
20867 		gtk_window_resize(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), w, h);
20868 		gtk_revealer_set_transition_duration(GTK_REVEALER(gtk_builder_get_object(main_builder, "message_revealer")), dur);
20869 	}
20870 }
20871 
set_current_object()20872 void set_current_object() {
20873 	if(!current_object_has_changed) return;
20874 	while(gtk_events_pending()) gtk_main_iteration();
20875 	GtkTextIter ipos, istart, iend;
20876 	gint pos, pos2;
20877 	g_object_get(expressionbuffer, "cursor-position", &pos, NULL);
20878 	pos2 = pos;
20879 	if(pos == 0) {
20880 		current_object_start = -1;
20881 		current_object_end = -1;
20882 		editing_to_expression = false;
20883 		return;
20884 	}
20885 	gtk_text_buffer_get_start_iter(expressionbuffer, &istart);
20886 	gtk_text_buffer_get_iter_at_offset(expressionbuffer, &ipos, pos);
20887 	gchar *gstr = gtk_text_buffer_get_text(expressionbuffer, &istart, &ipos, FALSE);
20888 	gchar *p = gstr + strlen(gstr);
20889 	size_t l_to = strlen(gstr);
20890 	if(l_to > 0) {
20891 		if(gstr[0] == '/') {
20892 			g_free(gstr);
20893 			current_object_start = -1;
20894 			current_object_end = -1;
20895 			editing_to_expression = false;
20896 			return;
20897 		}
20898 		for(size_t i = 0; i < l_to; i++) {
20899 			if(gstr[i] == '#') {
20900 				g_free(gstr);
20901 				current_object_start = -1;
20902 				current_object_end = -1;
20903 				editing_to_expression = false;
20904 				return;
20905 			}
20906 		}
20907 	}
20908 	editing_to_expression = CALCULATOR->hasToExpression(gstr, !auto_calculate, evalops);
20909 	if(editing_to_expression) {
20910 		string str = gstr, str_to;
20911 		bool b_space = is_in(SPACES, str[str.length() - 1]);
20912 		bool b_first = true;
20913 		do {
20914 			CALCULATOR->separateToExpression(str, str_to, evalops, true, !auto_calculate);
20915 			if(b_first && str.empty()) {
20916 				current_from_struct = mstruct;
20917 				if(current_from_struct) {
20918 					current_from_struct->ref();
20919 					current_from_unit = CALCULATOR->findMatchingUnit(*current_from_struct);
20920 				}
20921 			}
20922 			b_first = false;
20923 			str = str_to;
20924 			if(!str_to.empty() && b_space) str += " ";
20925 		} while(CALCULATOR->hasToExpression(str, !auto_calculate, evalops));
20926 		l_to = str_to.length();
20927 	}
20928 	bool non_number_before = false;
20929 	while(pos2 > 0 && l_to > 0) {
20930 		pos2--;
20931 		l_to--;
20932 		p = g_utf8_prev_char(p);
20933 		if(!CALCULATOR->utf8_pos_is_valid_in_name(p)) {
20934 			pos2++;
20935 			break;
20936 		} else if(is_in(NUMBERS, p[0])) {
20937 			if(non_number_before) {
20938 				pos2++;
20939 				break;
20940 			}
20941 		} else {
20942 			non_number_before = true;
20943 		}
20944 	}
20945 	editing_to_expression1 = (l_to == 0);
20946 	if(pos2 > pos) {
20947 		current_object_start = -1;
20948 		current_object_end = -1;
20949 	} else {
20950 		gtk_text_buffer_get_iter_at_offset(expressionbuffer, &ipos, pos);
20951 		gtk_text_buffer_get_end_iter(expressionbuffer, &iend);
20952 		gchar *gstr2 = gtk_text_buffer_get_text(expressionbuffer, &ipos, &iend, FALSE);
20953 		p = gstr2;
20954 		while(p[0] != '\0') {
20955 			if(!CALCULATOR->utf8_pos_is_valid_in_name(p)) {
20956 				break;
20957 			}
20958 			pos++;
20959 			p = g_utf8_next_char(p);
20960 		}
20961 		if(pos2 >= gtk_text_buffer_get_char_count(expressionbuffer)) {
20962 			current_object_start = -1;
20963 			current_object_end = -1;
20964 		} else {
20965 			current_object_start = pos2;
20966 			current_object_end = pos;
20967 		}
20968 		g_free(gstr2);
20969 	}
20970 	g_free(gstr);
20971 	current_object_has_changed = false;
20972 }
on_units_convert_view_row_activated(GtkTreeView *,GtkTreePath * path,GtkTreeViewColumn *,gpointer)20973 void on_units_convert_view_row_activated(GtkTreeView*, GtkTreePath *path, GtkTreeViewColumn*, gpointer) {
20974 	GtkTreeIter iter;
20975 	gtk_tree_model_get_iter(units_convert_filter, &iter, path);
20976 	Unit *u = NULL;
20977 	gtk_tree_model_get(units_convert_filter, &iter, UNITS_POINTER_COLUMN, &u, -1);
20978 	if(u) {
20979 		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());
20980 		selected_to_unit = u;
20981 		convert_in_wUnits();
20982 	}
20983 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(units_builder, "units_convert_to_button")), FALSE);
20984 	gtk_widget_hide(units_convert_window);
20985 }
20986 
on_completion_match_selected(GtkTreeView *,GtkTreePath * path,GtkTreeViewColumn *,gpointer)20987 void on_completion_match_selected(GtkTreeView*, GtkTreePath *path, GtkTreeViewColumn*, gpointer) {
20988 	GtkTreeIter iter;
20989 	gtk_tree_model_get_iter(completion_sort, &iter, path);
20990 	string str;
20991 	ExpressionItem *item = NULL;
20992 	Prefix *prefix = NULL;
20993 	int p_type = 0;
20994 	int exp = 1;
20995 	void *p = NULL;
20996 	const ExpressionName *ename = NULL, *ename_r = NULL, *ename_r2;
20997 	gint i_type = 0;
20998 	guint i_match = 0;
20999 	gtk_tree_model_get(completion_sort, &iter, 2, &p, 4, &i_type, 7, &i_match, 8, &p_type, -1);
21000 	if(i_type == 3) return;
21001 	if(p_type == 1) item = (ExpressionItem*) p;
21002 	else if(p_type == 2) prefix = (Prefix*) p;
21003 	else if(p_type >= 100) p_type = 0;
21004 	GtkTextIter object_start, object_end;
21005 	gtk_text_buffer_get_iter_at_offset(expressionbuffer, &object_start, current_object_start);
21006 	gtk_text_buffer_get_iter_at_offset(expressionbuffer, &object_end, current_object_end);
21007 	if(item && item->type() == TYPE_UNIT && ((Unit*) item)->subtype() == SUBTYPE_COMPOSITE_UNIT && (((CompositeUnit*) item)->countUnits() > 1 || !((CompositeUnit*) item)->get(1, &exp, &prefix) || exp != 1)) {
21008 		str = ((Unit*) item)->print(false, true, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) expressiontext);
21009 	} else if(item) {
21010 		CompositeUnit *cu = NULL;
21011 		if(item->type() == TYPE_UNIT && ((Unit*) item)->subtype() == SUBTYPE_COMPOSITE_UNIT) {
21012 			cu = (CompositeUnit*) item;
21013 			item = cu->get(1);
21014 		}
21015 		if(i_type > 2) {
21016 			if(i_match > 0) ename = &item->getName(i_match);
21017 			else ename = &item->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext);
21018 			if(!ename) return;
21019 			if(cu && prefix) {
21020 				str = prefix->name(ename->abbreviation, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) expressiontext);
21021 				str += ename->name;
21022 			} else {
21023 				str = ename->name;
21024 			}
21025 		} else if(cu && prefix) {
21026 			gchar *gstr2 = gtk_text_buffer_get_text(expressionbuffer, &object_start, &object_end, FALSE);
21027 			for(size_t name_i = 0; name_i < 3; name_i++) {
21028 				const string *pname;
21029 				if(name_i == 0) pname = &prefix->shortName(false);
21030 				else if(name_i == 1) pname = &prefix->longName(false);
21031 				else pname = &prefix->unicodeName(false);
21032 				if(!pname->empty() && (!((Unit*)item)->useWithPrefixesByDefault() || pname->length() >= strlen(gstr2))) {
21033 					bool pmatch = true;
21034 					for(size_t i = 0; i < strlen(gstr2) && i < pname->length(); i++) {
21035 						if((*pname)[i] != gstr2[i]) {
21036 							pmatch = false;
21037 							break;
21038 						}
21039 					}
21040 					if(pmatch) {
21041 						str = *pname;
21042 						ename = &item->preferredInputName(printops.abbreviate_names && name_i != 1, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext);
21043 						if(pname->length() >= strlen(gstr2)) break;
21044 					}
21045 				}
21046 			}
21047 			g_free(gstr2);
21048 			if(!ename) return;
21049 			str += ename->name;
21050 		} else {
21051 			gchar *gstr_pre = gtk_text_buffer_get_text(expressionbuffer, &object_start, &object_end, FALSE);
21052 			gchar *gstr2 = gstr_pre;
21053 			while(i_match > 0) {
21054 				gtk_text_iter_forward_char(&object_start);
21055 				gstr2 = g_utf8_next_char(gstr2);
21056 				if(strlen(gstr_pre) - strlen(gstr2) >= i_match) break;
21057 			}
21058 			ename_r = &item->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext);
21059 			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);
21060 			else ename_r2 = NULL;
21061 			if(ename_r2 == ename_r) ename_r2 = NULL;
21062 			for(size_t name_i = 0; name_i <= (ename_r2 ? item->countNames() + 1 : item->countNames()) && !ename; name_i++) {
21063 				if(name_i == 0) {
21064 					ename = ename_r;
21065 				} else if(name_i == 1 && ename_r2) {
21066 					ename = ename_r2;
21067 				} else {
21068 					ename = &item->getName(ename_r2 ? name_i - 1 : name_i);
21069 					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)))) {
21070 						ename = NULL;
21071 					}
21072 				}
21073 				if(ename) {
21074 					if(strlen(gstr2) <= ename->name.length()) {
21075 						for(size_t i = 0; i < strlen(gstr2); i++) {
21076 							if(ename->name[i] != gstr2[i]) {
21077 								if(i_type != 1 || !equalsIgnoreCase(ename->name, gstr2)) {
21078 									ename = NULL;
21079 								}
21080 								break;
21081 							}
21082 						}
21083 					} else {
21084 						ename = NULL;
21085 					}
21086 				}
21087 			}
21088 			for(size_t name_i = 1; name_i <= item->countNames() && !ename; name_i++) {
21089 				ename = &item->getName(name_i);
21090 				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))))) {
21091 					ename = NULL;
21092 				}
21093 				if(ename) {
21094 					if(strlen(gstr2) <= ename->name.length()) {
21095 						for(size_t i = 0; i < strlen(gstr2); i++) {
21096 							if(ename->name[i] != gstr2[i] && (ename->name[i] < 'A' || ename->name[i] > 'Z' || ename->name[i] != gstr2[i] + 32) && (ename->name[i] < 'a' || ename->name[i] > '<' || ename->name[i] != gstr2[i] - 32)) {
21097 								if(i_type != 1 || !equalsIgnoreCase(ename->name, gstr2)) {
21098 									ename = NULL;
21099 								}
21100 								break;
21101 							}
21102 						}
21103 					} else {
21104 						ename = NULL;
21105 					}
21106 				}
21107 			}
21108 			if(ename && ename->completion_only) {
21109 				ename = &item->preferredInputName(ename->abbreviation, printops.use_unicode_signs, ename->plural, false, &can_display_unicode_string_function, (void*) expressiontext);
21110 			}
21111 			if(!ename) ename = ename_r;
21112 			g_free(gstr_pre);
21113 			if(!ename) return;
21114 			str = ename->name;
21115 		}
21116 	} else if(prefix) {
21117 		gchar *gstr2 = gtk_text_buffer_get_text(expressionbuffer, &object_start, &object_end, FALSE);
21118 		for(size_t name_i = (printops.abbreviate_names ? 1 : 0); name_i < 3; name_i++) {
21119 			const string *pname;
21120 			if(name_i == 0) pname = &prefix->longName(false);
21121 			else if(name_i == 1) pname = &prefix->shortName(false);
21122 			else pname = &prefix->unicodeName(false);
21123 			if(!pname->empty() && strlen(gstr2) <= pname->length()) {
21124 				bool b = true;
21125 				for(size_t i = 0; i < strlen(gstr2); i++) {
21126 					if(gstr2[i] != (*pname)[i]) {
21127 						b = false;
21128 						break;
21129 					}
21130 				}
21131 				if(b) {
21132 					if(name_i == 1 && printops.use_unicode_signs) str = prefix->unicodeName();
21133 					else str = *pname;
21134 					break;
21135 				}
21136 			}
21137 		}
21138 		if(str.empty()) str = prefix->longName();
21139 		g_free(gstr2);
21140 	} else {
21141 		gchar *gstr;
21142 		gtk_tree_model_get(completion_sort, &iter, 0, &gstr, -1);
21143 		str = gstr;
21144 		size_t i = 0;
21145 		size_t i2 = str.find(" <i>");
21146 		while(i_match > 0) {
21147 			if(i == 0) i = i2 + 4;
21148 			else i = i2 + 8;
21149 			if(i >= str.length()) break;
21150 			i2 = str.find("</i>", i);
21151 			if(i2 == string::npos) break;
21152 			i_match--;
21153 			if(i == string::npos) break;
21154 		}
21155 		if(i2 == string::npos) i2 = str.length();
21156 		if(i == string::npos) i = 0;
21157 		str = str.substr(i, i2 - i);
21158 		g_free(gstr);
21159 	}
21160 	block_completion();
21161 	block_add_to_undo++;
21162 	gtk_text_buffer_delete(expressionbuffer, &object_start, &object_end);
21163 	block_add_to_undo--;
21164 	GtkTextIter ipos = object_start;
21165 	if(item && item->type() == TYPE_FUNCTION) {
21166 		GtkTextIter ipos2 = ipos;
21167 		gtk_text_iter_forward_char(&ipos2);
21168 		gchar *gstr = gtk_text_buffer_get_text(expressionbuffer, &ipos, &ipos2, FALSE);
21169 		if(strlen(gstr) > 0 && gstr[0] == '(') {
21170 			gtk_text_buffer_insert(expressionbuffer, &ipos, str.c_str(), -1);
21171 			gtk_text_buffer_place_cursor(expressionbuffer, &ipos);
21172 		} else {
21173 			str += "()";
21174 			gtk_text_buffer_insert(expressionbuffer, &ipos, str.c_str(), -1);
21175 			gtk_text_iter_backward_char(&ipos);
21176 			gtk_text_buffer_place_cursor(expressionbuffer, &ipos);
21177 		}
21178 		g_free(gstr);
21179 	} else {
21180 		gtk_text_buffer_insert(expressionbuffer, &ipos, str.c_str(), -1);
21181 		gtk_text_buffer_place_cursor(expressionbuffer, &ipos);
21182 	}
21183 	gtk_widget_hide(completion_window);
21184 	unblock_completion();
21185 	if(!item && !prefix && editing_to_expression && gtk_text_iter_is_end(&ipos)) {
21186 		execute_expression();
21187 	}
21188 }
21189 
on_menu_item_quit_activate(GtkMenuItem *,gpointer user_data)21190 void on_menu_item_quit_activate(GtkMenuItem*, gpointer user_data) {
21191 	on_gcalc_exit(NULL, NULL, user_data);
21192 }
21193 
21194 extern gint hidden_x, hidden_y;
on_main_window_close(GtkWidget * w,GdkEvent * event,gpointer user_data)21195 void on_main_window_close(GtkWidget *w, GdkEvent *event, gpointer user_data) {
21196 	if(has_systray_icon()) {
21197 		if(save_mode_on_exit) save_mode();
21198 		else save_preferences();
21199 		if(save_defs_on_exit) save_defs();
21200 		gtk_window_get_position(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), &hidden_x, &hidden_y);
21201 		gtk_widget_hide(w);
21202 	} else {
21203 		on_gcalc_exit(w, event, user_data);
21204 	}
21205 }
21206 
21207 /*
21208 	change preferences
21209 */
on_colorbutton_status_error_color_color_set(GtkColorButton * w,gpointer)21210 void on_colorbutton_status_error_color_color_set(GtkColorButton *w, gpointer) {
21211 	GdkRGBA c;
21212 	gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(w), &c);
21213 	gchar color_str[8];
21214 	g_snprintf(color_str, 8, "#%02x%02x%02x", (int) (c.red * 255), (int) (c.green * 255), (int) (c.blue * 255));
21215 	status_error_color = color_str;
21216 	status_error_color_set = true;
21217 	display_parse_status();
21218 }
on_colorbutton_status_warning_color_color_set(GtkColorButton * w,gpointer)21219 void on_colorbutton_status_warning_color_color_set(GtkColorButton *w, gpointer) {
21220 	GdkRGBA c;
21221 	gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(w), &c);
21222 	gchar color_str[8];
21223 	g_snprintf(color_str, 8, "#%02x%02x%02x", (int) (c.red * 255), (int) (c.green * 255), (int) (c.blue * 255));
21224 	status_warning_color = color_str;
21225 	status_warning_color_set = true;
21226 	display_parse_status();
21227 }
on_preferences_expression_lines_spin_button_value_changed(GtkSpinButton * spin,gpointer)21228 void on_preferences_expression_lines_spin_button_value_changed(GtkSpinButton *spin, gpointer) {
21229 	expression_lines = gtk_spin_button_get_value_as_int(spin);
21230 	gint h_old = gtk_widget_get_allocated_height(expressiontext);
21231 	gint winw = 0, winh = 0;
21232 	gtk_window_get_size(GTK_WINDOW(mainwindow), &winw, &winh);
21233 	set_expression_size_request();
21234 	while(gtk_events_pending()) gtk_main_iteration();
21235 	gint h_new = gtk_widget_get_allocated_height(expressiontext);
21236 	winh += (h_new - h_old);
21237 	gtk_window_resize(GTK_WINDOW(mainwindow), winw, winh);
21238 }
on_preferences_update_exchange_rates_spin_button_value_changed(GtkSpinButton * spin,gpointer)21239 void on_preferences_update_exchange_rates_spin_button_value_changed(GtkSpinButton *spin, gpointer) {
21240 	auto_update_exchange_rates = gtk_spin_button_get_value_as_int(spin);
21241 }
on_preferences_update_exchange_rates_spin_button_input(GtkSpinButton * spin,gdouble * new_value,gpointer)21242 gint on_preferences_update_exchange_rates_spin_button_input(GtkSpinButton *spin, gdouble *new_value, gpointer) {
21243 	const gchar *text = gtk_entry_get_text(GTK_ENTRY(spin));
21244 	if(g_strcmp0(text, _("never")) == 0) *new_value = 0.0;
21245 	else if(g_strcmp0(text, _("ask")) == 0) *new_value = -1.0;
21246 	else *new_value = g_strtod(text, NULL);
21247 	return TRUE;
21248 }
on_preferences_update_exchange_rates_spin_button_output(GtkSpinButton * spin,gpointer)21249 gboolean on_preferences_update_exchange_rates_spin_button_output(GtkSpinButton *spin, gpointer) {
21250 	int value = gtk_spin_button_get_value_as_int(spin);
21251 	if(value > 0) {
21252 		gchar *text;
21253 		text = g_strdup_printf(_("%i days"), value);
21254 		gtk_entry_set_text(GTK_ENTRY(spin), text);
21255 		g_free(text);
21256 	} else if(value == 0) {
21257 		gtk_entry_set_text(GTK_ENTRY(spin), _("never"));
21258 	} else {
21259 		gtk_entry_set_text(GTK_ENTRY(spin), _("ask"));
21260 	}
21261 	return TRUE;
21262 }
on_preferences_scale_plot_time_value_changed(GtkRange * w,gpointer)21263 void on_preferences_scale_plot_time_value_changed(GtkRange *w, gpointer) {
21264 	Number nr; nr.setFloat(gtk_range_get_value(w) + 0.322); nr.exp2(); nr.round();
21265 	max_plot_time = nr.intValue();
21266 }
on_preferences_checkbutton_persistent_keypad_toggled(GtkToggleButton * w,gpointer)21267 void on_preferences_checkbutton_persistent_keypad_toggled(GtkToggleButton *w, gpointer) {
21268 	persistent_keypad = gtk_toggle_button_get_active(w);
21269 	update_persistent_keypad(true);
21270 }
on_preferences_checkbutton_clear_history_toggled(GtkToggleButton * w,gpointer)21271 void on_preferences_checkbutton_clear_history_toggled(GtkToggleButton *w, gpointer) {
21272 	clear_history_on_exit = gtk_toggle_button_get_active(w);
21273 }
on_status_right_button_release_event(GtkWidget *,GdkEventButton * event,gpointer)21274 gboolean on_status_right_button_release_event(GtkWidget*, GdkEventButton *event, gpointer) {
21275 	if(event->type == GDK_BUTTON_RELEASE && event->button == 1) {
21276 #if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 22
21277 		gtk_menu_popup_at_pointer(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_status_right")), (GdkEvent*) event);
21278 #else
21279 		gtk_menu_popup(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_status_right")), NULL, NULL, NULL, NULL, event->button, event->time);
21280 #endif
21281 		return TRUE;
21282 	}
21283 	return FALSE;
21284 }
on_status_right_button_press_event(GtkWidget *,GdkEventButton * event,gpointer)21285 gboolean on_status_right_button_press_event(GtkWidget*, GdkEventButton *event, gpointer) {
21286 	if(gdk_event_triggers_context_menu((GdkEvent*) event) && event->type == GDK_BUTTON_PRESS && event->button != 1) {
21287 #if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 22
21288 		gtk_menu_popup_at_pointer(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_status_right")), (GdkEvent*) event);
21289 #else
21290 		gtk_menu_popup(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_status_right")), NULL, NULL, NULL, NULL, event->button, event->time);
21291 #endif
21292 		return TRUE;
21293 	}
21294 	return FALSE;
21295 }
on_image_keypad_lock_button_release_event(GtkWidget *,GdkEvent *,gpointer)21296 gboolean on_image_keypad_lock_button_release_event(GtkWidget*, GdkEvent*, gpointer) {
21297 	persistent_keypad = !persistent_keypad;
21298 	update_persistent_keypad(false);
21299 	return TRUE;
21300 }
on_popup_menu_item_persistent_keypad_toggled(GtkCheckMenuItem * w,gpointer)21301 void on_popup_menu_item_persistent_keypad_toggled(GtkCheckMenuItem *w, gpointer) {
21302 	persistent_keypad = gtk_check_menu_item_get_active(w);
21303 	update_persistent_keypad(true);
21304 }
on_image_keypad_lock_button_press_event(GtkWidget *,GdkEventButton * event,gpointer)21305 gboolean on_image_keypad_lock_button_press_event(GtkWidget*, GdkEventButton *event, gpointer) {
21306 	if(gdk_event_triggers_context_menu((GdkEvent*) event) && event->type == GDK_BUTTON_PRESS && event->button != 1) {
21307 #if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 22
21308 		gtk_menu_popup_at_pointer(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_expander_keypad")), (GdkEvent*) event);
21309 #else
21310 		gtk_menu_popup(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_expander_keypad")), NULL, NULL, NULL, NULL, event->button, event->time);
21311 #endif
21312 		return TRUE;
21313 	}
21314 	return FALSE;
21315 }
on_expander_keypad_button_press_event(GtkWidget *,GdkEventButton * event,gpointer)21316 gboolean on_expander_keypad_button_press_event(GtkWidget*, GdkEventButton *event, gpointer) {
21317 	if(gdk_event_triggers_context_menu((GdkEvent*) event) && event->type == GDK_BUTTON_PRESS) {
21318 #if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 22
21319 		gtk_menu_popup_at_pointer(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_expander_keypad")), (GdkEvent*) event);
21320 #else
21321 		gtk_menu_popup(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_expander_keypad")), NULL, NULL, NULL, NULL, event->button, event->time);
21322 #endif
21323 		return TRUE;
21324 	}
21325 	return FALSE;
21326 }
on_preferences_checkbutton_check_version_toggled(GtkToggleButton * w,gpointer)21327 void on_preferences_checkbutton_check_version_toggled(GtkToggleButton *w, gpointer) {
21328 	check_version = gtk_toggle_button_get_active(w);
21329 	if(check_version) on_check_version_idle(NULL);
21330 }
on_preferences_checkbutton_remember_position_toggled(GtkToggleButton * w,gpointer)21331 void on_preferences_checkbutton_remember_position_toggled(GtkToggleButton *w, gpointer) {
21332 	remember_position = gtk_toggle_button_get_active(w);
21333 }
on_preferences_checkbutton_local_currency_conversion_toggled(GtkToggleButton * w,gpointer)21334 void on_preferences_checkbutton_local_currency_conversion_toggled(GtkToggleButton *w, gpointer) {
21335 	evalops.local_currency_conversion = gtk_toggle_button_get_active(w);
21336 	expression_calculation_updated();
21337 }
on_preferences_checkbutton_binary_prefixes_toggled(GtkToggleButton * w,gpointer)21338 void on_preferences_checkbutton_binary_prefixes_toggled(GtkToggleButton *w, gpointer) {
21339 	CALCULATOR->useBinaryPrefixes(gtk_toggle_button_get_active(w) ? 1 : 0);
21340 	result_format_updated();
21341 }
on_preferences_radiobutton_temp_rel_toggled(GtkToggleButton * w,gpointer)21342 void on_preferences_radiobutton_temp_rel_toggled(GtkToggleButton *w, gpointer) {
21343 	if(!gtk_toggle_button_get_active(w)) return;
21344 	CALCULATOR->setTemperatureCalculationMode(TEMPERATURE_CALCULATION_RELATIVE);
21345 	tc_set = true;
21346 	expression_calculation_updated();
21347 }
on_preferences_radiobutton_temp_abs_toggled(GtkToggleButton * w,gpointer)21348 void on_preferences_radiobutton_temp_abs_toggled(GtkToggleButton *w, gpointer) {
21349 	if(!gtk_toggle_button_get_active(w)) return;
21350 	CALCULATOR->setTemperatureCalculationMode(TEMPERATURE_CALCULATION_ABSOLUTE);
21351 	tc_set = true;
21352 	expression_calculation_updated();
21353 }
on_preferences_radiobutton_temp_hybrid_toggled(GtkToggleButton * w,gpointer)21354 void on_preferences_radiobutton_temp_hybrid_toggled(GtkToggleButton *w, gpointer) {
21355 	if(!gtk_toggle_button_get_active(w)) return;
21356 	CALCULATOR->setTemperatureCalculationMode(TEMPERATURE_CALCULATION_HYBRID);
21357 	tc_set = true;
21358 	expression_calculation_updated();
21359 }
on_preferences_checkbutton_ignore_locale_toggled(GtkToggleButton * w,gpointer)21360 void on_preferences_checkbutton_ignore_locale_toggled(GtkToggleButton *w, gpointer) {
21361 	ignore_locale = gtk_toggle_button_get_active(w);
21362 }
on_preferences_combo_title_changed(GtkComboBox * w,gpointer)21363 void on_preferences_combo_title_changed(GtkComboBox *w, gpointer) {
21364 	title_type = gtk_combo_box_get_active(w);
21365 	title_modified = false;
21366 	update_window_title();
21367 }
on_preferences_checkbutton_copy_separator_toggled(GtkToggleButton * w,gpointer)21368 void on_preferences_checkbutton_copy_separator_toggled(GtkToggleButton *w, gpointer) {
21369 	copy_separator = gtk_toggle_button_get_active(w);
21370 }
on_preferences_checkbutton_lower_case_numbers_toggled(GtkToggleButton * w,gpointer)21371 void on_preferences_checkbutton_lower_case_numbers_toggled(GtkToggleButton *w, gpointer) {
21372 	printops.lower_case_numbers = gtk_toggle_button_get_active(w);
21373 	result_format_updated();
21374 }
on_preferences_checkbutton_lower_case_e_toggled(GtkToggleButton * w,gpointer)21375 void on_preferences_checkbutton_lower_case_e_toggled(GtkToggleButton *w, gpointer) {
21376 	printops.lower_case_e = gtk_toggle_button_get_active(w);
21377 	result_format_updated();
21378 }
on_preferences_checkbutton_imaginary_j_toggled(GtkToggleButton * w,gpointer)21379 void on_preferences_checkbutton_imaginary_j_toggled(GtkToggleButton *w, gpointer) {
21380 	if(gtk_toggle_button_get_active(w) != (CALCULATOR->v_i->hasName("j") > 0)) {
21381 		if(gtk_toggle_button_get_active(w)) {
21382 			ExpressionName ename = CALCULATOR->v_i->getName(1);
21383 			ename.name = "j";
21384 			ename.reference = false;
21385 			CALCULATOR->v_i->addName(ename, 1, true);
21386 			CALCULATOR->v_i->setChanged(false);
21387 		} else {
21388 			CALCULATOR->v_i->clearNonReferenceNames();
21389 			CALCULATOR->v_i->setChanged(false);
21390 		}
21391 		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());
21392 		expression_format_updated();
21393 	}
21394 }
on_preferences_checkbutton_e_notation_toggled(GtkToggleButton * w,gpointer)21395 void on_preferences_checkbutton_e_notation_toggled(GtkToggleButton *w, gpointer) {
21396 	use_e_notation = gtk_toggle_button_get_active(w);
21397 	result_format_updated();
21398 }
on_preferences_checkbutton_alternative_base_prefixes_toggled(GtkToggleButton * w,gpointer)21399 void on_preferences_checkbutton_alternative_base_prefixes_toggled(GtkToggleButton *w, gpointer) {
21400 	if(gtk_toggle_button_get_active(w)) printops.base_display = BASE_DISPLAY_ALTERNATIVE;
21401 	else printops.base_display = BASE_DISPLAY_NORMAL;
21402 	result_format_updated();
21403 }
on_preferences_checkbutton_twos_complement_toggled(GtkToggleButton * w,gpointer)21404 void on_preferences_checkbutton_twos_complement_toggled(GtkToggleButton *w, gpointer) {
21405 	printops.twos_complement = gtk_toggle_button_get_active(w);
21406 	if(printops.base == 2) {
21407 		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);
21408 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "button_twos_out")), printops.twos_complement);
21409 		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);
21410 	}
21411 	result_format_updated();
21412 }
on_preferences_checkbutton_hexadecimal_twos_complement_toggled(GtkToggleButton * w,gpointer)21413 void on_preferences_checkbutton_hexadecimal_twos_complement_toggled(GtkToggleButton *w, gpointer) {
21414 	printops.hexadecimal_twos_complement = gtk_toggle_button_get_active(w);
21415 	if(printops.base == 16) {
21416 		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);
21417 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "button_twos_out")), printops.twos_complement);
21418 		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);
21419 	}
21420 	result_format_updated();
21421 }
on_preferences_checkbutton_spell_out_logical_operators_toggled(GtkToggleButton * w,gpointer)21422 void on_preferences_checkbutton_spell_out_logical_operators_toggled(GtkToggleButton *w, gpointer) {
21423 	printops.spell_out_logical_operators = gtk_toggle_button_get_active(w);
21424 	result_display_updated();
21425 }
on_preferences_checkbutton_caret_as_xor_toggled(GtkToggleButton * w,gpointer)21426 void on_preferences_checkbutton_caret_as_xor_toggled(GtkToggleButton *w, gpointer) {
21427 	caret_as_xor = gtk_toggle_button_get_active(w);
21428 	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());
21429 	else gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_xor")), _("Bitwise Exclusive OR"));
21430 }
on_preferences_checkbutton_unicode_signs_toggled(GtkToggleButton * w,gpointer)21431 void on_preferences_checkbutton_unicode_signs_toggled(GtkToggleButton *w, gpointer) {
21432 	printops.use_unicode_signs = gtk_toggle_button_get_active(w);
21433 	set_operator_symbols();
21434 	set_unicode_buttons();
21435 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_radiobutton_asterisk")), printops.use_unicode_signs);
21436 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_radiobutton_ex")), printops.use_unicode_signs);
21437 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_radiobutton_dot")), printops.use_unicode_signs);
21438 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_radiobutton_altdot")), printops.use_unicode_signs);
21439 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_radiobutton_slash")), printops.use_unicode_signs);
21440 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_radiobutton_division_slash")), printops.use_unicode_signs);
21441 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_radiobutton_division")), printops.use_unicode_signs);
21442 	result_display_updated();
21443 }
21444 
on_preferences_checkbutton_save_defs_toggled(GtkToggleButton * w,gpointer)21445 void on_preferences_checkbutton_save_defs_toggled(GtkToggleButton *w, gpointer) {
21446 	save_defs_on_exit = gtk_toggle_button_get_active(w);
21447 }
on_preferences_checkbutton_save_mode_toggled(GtkToggleButton * w,gpointer)21448 void on_preferences_checkbutton_save_mode_toggled(GtkToggleButton *w, gpointer) {
21449 	save_mode_on_exit = gtk_toggle_button_get_active(w);
21450 }
on_preferences_checkbutton_allow_multiple_instances_toggled(GtkToggleButton * w,gpointer)21451 void on_preferences_checkbutton_allow_multiple_instances_toggled(GtkToggleButton *w, gpointer) {
21452 	allow_multiple_instances = gtk_toggle_button_get_active(w);
21453 	save_preferences(false);
21454 }
on_preferences_checkbutton_rpn_keys_toggled(GtkToggleButton * w,gpointer)21455 void on_preferences_checkbutton_rpn_keys_toggled(GtkToggleButton *w, gpointer) {
21456 	rpn_keys = gtk_toggle_button_get_active(w);
21457 }
on_preferences_checkbutton_decimal_comma_toggled(GtkToggleButton * w,gpointer)21458 void on_preferences_checkbutton_decimal_comma_toggled(GtkToggleButton *w, gpointer) {
21459 	b_decimal_comma = gtk_toggle_button_get_active(w);
21460 	if(b_decimal_comma) {
21461 		CALCULATOR->useDecimalComma();
21462 		gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_checkbutton_dot_as_separator")));
21463 		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_checkbutton_comma_as_separator")));
21464 	} else {
21465 		CALCULATOR->useDecimalPoint(evalops.parse_options.comma_as_separator);
21466 		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_checkbutton_dot_as_separator")));
21467 		gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_checkbutton_comma_as_separator")));
21468 	}
21469 	expression_format_updated(false);
21470 	result_display_updated();
21471 	set_unicode_buttons();
21472 }
on_preferences_checkbutton_dot_as_separator_toggled(GtkToggleButton * w,gpointer)21473 void on_preferences_checkbutton_dot_as_separator_toggled(GtkToggleButton *w, gpointer) {
21474 	evalops.parse_options.dot_as_separator = gtk_toggle_button_get_active(w);
21475 	expression_format_updated(false);
21476 }
on_preferences_checkbutton_comma_as_separator_toggled(GtkToggleButton * w,gpointer)21477 void on_preferences_checkbutton_comma_as_separator_toggled(GtkToggleButton *w, gpointer) {
21478 	evalops.parse_options.comma_as_separator = gtk_toggle_button_get_active(w);
21479 	CALCULATOR->useDecimalPoint(evalops.parse_options.comma_as_separator);
21480 	set_unicode_buttons();
21481 	expression_format_updated(false);
21482 }
on_preferences_checkbutton_load_defs_toggled(GtkToggleButton * w,gpointer)21483 void on_preferences_checkbutton_load_defs_toggled(GtkToggleButton *w, gpointer) {
21484 	load_global_defs = gtk_toggle_button_get_active(w);
21485 }
on_preferences_checkbutton_fetch_exchange_rates_toggled(GtkToggleButton * w,gpointer)21486 void on_preferences_checkbutton_fetch_exchange_rates_toggled(GtkToggleButton *w, gpointer) {
21487 	fetch_exchange_rates_at_startup = gtk_toggle_button_get_active(w);
21488 }
on_preferences_checkbutton_display_expression_status_toggled(GtkToggleButton * w,gpointer)21489 void on_preferences_checkbutton_display_expression_status_toggled(GtkToggleButton *w, gpointer) {
21490 	if(gtk_toggle_button_get_active(w)) {
21491 		display_expression_status = true;
21492 		display_parse_status();
21493 	} else {
21494 		display_expression_status = false;
21495 		set_status_text("");
21496 	}
21497 }
on_preferences_checkbutton_dark_theme_toggled(GtkToggleButton * w,gpointer)21498 void on_preferences_checkbutton_dark_theme_toggled(GtkToggleButton *w, gpointer) {
21499 #if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 16
21500 	use_dark_theme = gtk_toggle_button_get_active(w);
21501 	if(use_dark_theme) gtk_css_provider_load_from_resource(app_provider_theme, "/org/gtk/libgtk/theme/Adwaita/gtk-contained-dark.css");
21502 	else gtk_css_provider_load_from_resource(app_provider_theme, "/org/gtk/libgtk/theme/Adwaita/gtk-contained.css");
21503 #endif
21504 }
on_preferences_checkbutton_use_systray_icon_toggled(GtkToggleButton * w,gpointer)21505 void on_preferences_checkbutton_use_systray_icon_toggled(GtkToggleButton *w, gpointer) {
21506 #ifdef _WIN32
21507 	use_systray_icon = gtk_toggle_button_get_active(w);
21508 	if(use_systray_icon) create_systray_icon();
21509 	else destroy_systray_icon();
21510 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_checkbutton_hide_on_startup")), use_systray_icon);
21511 #endif
21512 }
on_preferences_checkbutton_hide_on_startup_toggled(GtkToggleButton * w,gpointer)21513 void on_preferences_checkbutton_hide_on_startup_toggled(GtkToggleButton *w, gpointer) {
21514 	hide_on_startup = gtk_toggle_button_get_active(w);
21515 }
on_preferences_checkbutton_custom_result_font_toggled(GtkToggleButton * w,gpointer)21516 void on_preferences_checkbutton_custom_result_font_toggled(GtkToggleButton *w, gpointer) {
21517 	use_custom_result_font = gtk_toggle_button_get_active(w);
21518 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_button_result_font")), use_custom_result_font);
21519 	gint h_old, h_new;
21520 	gtk_widget_get_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "scrolled_result")), NULL, &h_old);
21521 	if(use_custom_result_font) {
21522 		gchar *gstr = font_name_to_css(custom_result_font.c_str());
21523 		gtk_css_provider_load_from_data(resultview_provider, gstr, -1, NULL);
21524 		g_free(gstr);
21525 	} else {
21526 		gtk_css_provider_load_from_data(resultview_provider, "* {font-size: larger;}", -1, NULL);
21527 	}
21528 	result_font_modified();
21529 	gtk_widget_get_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "scrolled_result")), NULL, &h_new);
21530 	gint winh, winw;
21531 	gtk_window_get_size(GTK_WINDOW(mainwindow), &winw, &winh);
21532 	winh += (h_new - h_old);
21533 	gtk_window_resize(GTK_WINDOW(mainwindow), winw, winh);
21534 }
on_preferences_checkbutton_custom_expression_font_toggled(GtkToggleButton * w,gpointer)21535 void on_preferences_checkbutton_custom_expression_font_toggled(GtkToggleButton *w, gpointer) {
21536 	use_custom_expression_font = gtk_toggle_button_get_active(w);
21537 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_button_expression_font")), use_custom_expression_font);
21538 	gint h_old, h_new;
21539 	gtk_widget_get_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "expressionscrolled")), NULL, &h_old);
21540 	if(use_custom_expression_font) {
21541 #if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 20
21542 		gchar *gstr = font_name_to_css(custom_expression_font.c_str(), "textview.view");
21543 #else
21544 		gchar *gstr = font_name_to_css(custom_expression_font.c_str());
21545 #endif
21546 		gtk_css_provider_load_from_data(expression_provider, gstr, -1, NULL);
21547 		g_free(gstr);
21548 	} else {
21549 #if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 20
21550 		gtk_css_provider_load_from_data(expression_provider, "textview.view {font-size: larger;}", -1, NULL);
21551 #else
21552 		gtk_css_provider_load_from_data(expression_provider, "* {font-size: larger;}", -1, NULL);
21553 #endif
21554 	}
21555 	expression_font_modified();
21556 	gtk_widget_get_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "expressionscrolled")), NULL, &h_new);
21557 	gint winh, winw;
21558 	gtk_window_get_size(GTK_WINDOW(mainwindow), &winw, &winh);
21559 	winh += (h_new - h_old);
21560 	gtk_window_resize(GTK_WINDOW(mainwindow), winw, winh);
21561 }
on_preferences_checkbutton_custom_status_font_toggled(GtkToggleButton * w,gpointer)21562 void on_preferences_checkbutton_custom_status_font_toggled(GtkToggleButton *w, gpointer) {
21563 	use_custom_status_font = gtk_toggle_button_get_active(w);
21564 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_button_status_font")), use_custom_status_font);
21565 	gint h_old = gtk_widget_get_allocated_height(GTK_WIDGET(gtk_builder_get_object(main_builder, "statusbox")));
21566 	if(use_custom_status_font) {
21567 		gchar *gstr = font_name_to_css(custom_status_font.c_str());
21568 		gtk_css_provider_load_from_data(statuslabel_l_provider, gstr, -1, NULL);
21569 		gtk_css_provider_load_from_data(statuslabel_r_provider, gstr, -1, NULL);
21570 		g_free(gstr);
21571 	} else {
21572 		gtk_css_provider_load_from_data(statuslabel_l_provider, "* {font-size: 90%;}", -1, NULL);
21573 		gtk_css_provider_load_from_data(statuslabel_r_provider, "* {font-size: 90%;}", -1, NULL);
21574 	}
21575 	set_operator_symbols();
21576 	while(gtk_events_pending()) gtk_main_iteration();
21577 	gint h_new = gtk_widget_get_allocated_height(GTK_WIDGET(gtk_builder_get_object(main_builder, "statusbox")));
21578 	gint winh, winw;
21579 	gtk_window_get_size(GTK_WINDOW(mainwindow), &winw, &winh);
21580 	winh += (h_new - h_old);
21581 	gtk_window_resize(GTK_WINDOW(mainwindow), winw, winh);
21582 }
keypad_font_changed()21583 void keypad_font_changed() {
21584 	set_unicode_buttons();
21585 	while(gtk_events_pending()) gtk_main_iteration();
21586 	gint winh, winw;
21587 	gtk_window_get_size(GTK_WINDOW(mainwindow), &winw, &winh);
21588 	if(minimal_mode) {
21589 		gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(main_builder, "menubar")));
21590 		gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(main_builder, "box_tabs")));
21591 	}
21592 	while(gtk_events_pending()) gtk_main_iteration();
21593 	bool b_buttons = gtk_expander_get_expanded(GTK_EXPANDER(expander_keypad));
21594 	if(!b_buttons) gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(main_builder, "buttons")));
21595 	while(gtk_events_pending()) gtk_main_iteration();
21596 	for(size_t i = 0; i < 5 && (!b_buttons || minimal_mode); i++) {
21597 		sleep_ms(10);
21598 		while(gtk_events_pending()) gtk_main_iteration();
21599 	}
21600 	GtkRequisition req;
21601 	gtk_widget_get_preferred_size(GTK_WIDGET(gtk_builder_get_object(main_builder, "menubar")), &req, NULL);
21602 	gtk_window_resize(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), req.width + 24, 1);
21603 	if(!b_buttons || minimal_mode) {
21604 		while(gtk_events_pending()) gtk_main_iteration();
21605 		for(size_t i = 0; i < 5; i++) {
21606 			sleep_ms(10);
21607 			while(gtk_events_pending()) gtk_main_iteration();
21608 		}
21609 		if(minimal_mode) {
21610 			gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "menubar")));
21611 			gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "box_tabs")));
21612 			if(winw < req.width + 24) winw = req.width + 24;
21613 		}
21614 		gtk_window_get_size(GTK_WINDOW(mainwindow), &win_width, NULL);
21615 		if(!minimal_mode) winw = win_width;
21616 		if(!b_buttons) gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "buttons")));
21617 		while(gtk_events_pending()) gtk_main_iteration();
21618 		gtk_window_resize(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), winw, winh);
21619 	}
21620 }
on_preferences_checkbutton_custom_keypad_font_toggled(GtkToggleButton * w,gpointer)21621 void on_preferences_checkbutton_custom_keypad_font_toggled(GtkToggleButton *w, gpointer) {
21622 	use_custom_keypad_font = gtk_toggle_button_get_active(w);
21623 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_button_keypad_font")), use_custom_keypad_font);
21624 	if(use_custom_keypad_font) {
21625 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(preferences_builder, "preferences_checkbutton_custom_app_font")), FALSE);
21626 		gchar *gstr = font_name_to_css(custom_keypad_font.c_str());
21627 		gtk_css_provider_load_from_data(keypad_provider, gstr, -1, NULL);
21628 		gtk_css_provider_load_from_data(box_rpnl_provider, gstr, -1, NULL);
21629 		g_free(gstr);
21630 	} else {
21631 		gtk_css_provider_load_from_data(keypad_provider, "", -1, NULL);
21632 		gtk_css_provider_load_from_data(box_rpnl_provider, "", -1, NULL);
21633 	}
21634 	keypad_font_changed();
21635 }
on_preferences_checkbutton_custom_app_font_toggled(GtkToggleButton * w,gpointer)21636 void on_preferences_checkbutton_custom_app_font_toggled(GtkToggleButton *w, gpointer) {
21637 	use_custom_app_font = gtk_toggle_button_get_active(w);
21638 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_button_app_font")), use_custom_app_font);
21639 	if(use_custom_app_font) {
21640 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(preferences_builder, "preferences_checkbutton_custom_keypad_font")), FALSE);
21641 		gchar *gstr = font_name_to_css(custom_app_font.c_str());
21642 		gtk_css_provider_load_from_data(app_provider, gstr, -1, NULL);
21643 		g_free(gstr);
21644 	} else {
21645 		gtk_css_provider_load_from_data(app_provider, "", -1, NULL);
21646 	}
21647 	expression_font_modified();
21648 	result_font_modified();
21649 	keypad_font_changed();
21650 }
on_preferences_radiobutton_dot_toggled(GtkToggleButton * w,gpointer)21651 void on_preferences_radiobutton_dot_toggled(GtkToggleButton *w, gpointer) {
21652 	if(gtk_toggle_button_get_active(w)) {
21653 		printops.multiplication_sign = MULTIPLICATION_SIGN_DOT;
21654 		result_display_updated();
21655 	}
21656 }
on_preferences_radiobutton_altdot_toggled(GtkToggleButton * w,gpointer)21657 void on_preferences_radiobutton_altdot_toggled(GtkToggleButton *w, gpointer) {
21658 	if(gtk_toggle_button_get_active(w)) {
21659 		printops.multiplication_sign = MULTIPLICATION_SIGN_ALTDOT;
21660 		result_display_updated();
21661 	}
21662 }
on_preferences_radiobutton_ex_toggled(GtkToggleButton * w,gpointer)21663 void on_preferences_radiobutton_ex_toggled(GtkToggleButton *w, gpointer) {
21664 	if(gtk_toggle_button_get_active(w)) {
21665 		printops.multiplication_sign = MULTIPLICATION_SIGN_X;
21666 		result_display_updated();
21667 	}
21668 }
on_preferences_radiobutton_asterisk_toggled(GtkToggleButton * w,gpointer)21669 void on_preferences_radiobutton_asterisk_toggled(GtkToggleButton *w, gpointer) {
21670 	if(gtk_toggle_button_get_active(w)) {
21671 		printops.multiplication_sign = MULTIPLICATION_SIGN_ASTERISK;
21672 		result_display_updated();
21673 	}
21674 }
on_preferences_radiobutton_slash_toggled(GtkToggleButton * w,gpointer)21675 void on_preferences_radiobutton_slash_toggled(GtkToggleButton *w, gpointer) {
21676 	if(gtk_toggle_button_get_active(w)) {
21677 		printops.division_sign = DIVISION_SIGN_SLASH;
21678 		result_display_updated();
21679 	}
21680 }
on_preferences_radiobutton_division_slash_toggled(GtkToggleButton * w,gpointer)21681 void on_preferences_radiobutton_division_slash_toggled(GtkToggleButton *w, gpointer) {
21682 	if(gtk_toggle_button_get_active(w)) {
21683 		printops.division_sign = DIVISION_SIGN_DIVISION_SLASH;
21684 		result_display_updated();
21685 	}
21686 }
on_preferences_radiobutton_division_toggled(GtkToggleButton * w,gpointer)21687 void on_preferences_radiobutton_division_toggled(GtkToggleButton *w, gpointer) {
21688 	if(gtk_toggle_button_get_active(w)) {
21689 		printops.division_sign = DIVISION_SIGN_DIVISION;
21690 		result_display_updated();
21691 	}
21692 }
on_preferences_radiobutton_digit_grouping_none_toggled(GtkToggleButton * w,gpointer)21693 void on_preferences_radiobutton_digit_grouping_none_toggled(GtkToggleButton *w, gpointer) {
21694 	if(gtk_toggle_button_get_active(w)) {
21695 		printops.digit_grouping = DIGIT_GROUPING_NONE;
21696 		result_format_updated();
21697 	}
21698 }
on_preferences_radiobutton_digit_grouping_standard_toggled(GtkToggleButton * w,gpointer)21699 void on_preferences_radiobutton_digit_grouping_standard_toggled(GtkToggleButton *w, gpointer) {
21700 	if(gtk_toggle_button_get_active(w)) {
21701 		printops.digit_grouping = DIGIT_GROUPING_STANDARD;
21702 		result_format_updated();
21703 	}
21704 }
on_preferences_radiobutton_digit_grouping_locale_toggled(GtkToggleButton * w,gpointer)21705 void on_preferences_radiobutton_digit_grouping_locale_toggled(GtkToggleButton *w, gpointer) {
21706 	if(gtk_toggle_button_get_active(w)) {
21707 		printops.digit_grouping = DIGIT_GROUPING_LOCALE;
21708 		result_format_updated();
21709 	}
21710 }
21711 
on_preferences_checkbutton_enable_completion_toggled(GtkToggleButton * w,gpointer)21712 void on_preferences_checkbutton_enable_completion_toggled(GtkToggleButton *w, gpointer) {
21713 	enable_completion = gtk_toggle_button_get_active(w);
21714 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_label_completion_min")), enable_completion);
21715 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_spin_completion_min")), enable_completion);
21716 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_checkbutton_enable_completion2")), enable_completion);
21717 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_label_completion_min2")), enable_completion && enable_completion2);
21718 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_spin_completion_min2")), enable_completion && enable_completion2);
21719 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_label_completion_delay")), enable_completion);
21720 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_spin_completion_delay")), enable_completion);
21721 }
on_preferences_checkbutton_enable_completion2_toggled(GtkToggleButton * w,gpointer)21722 void on_preferences_checkbutton_enable_completion2_toggled(GtkToggleButton *w, gpointer) {
21723 	enable_completion2 = gtk_toggle_button_get_active(w);
21724 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_label_completion_min2")), enable_completion && enable_completion2);
21725 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_spin_completion_min2")), enable_completion && enable_completion2);
21726 }
on_preferences_spin_completion_min_value_changed(GtkSpinButton * spin,gpointer)21727 void on_preferences_spin_completion_min_value_changed(GtkSpinButton *spin, gpointer) {
21728 	completion_min = gtk_spin_button_get_value_as_int(spin);
21729 	if(completion_min2 < completion_min) {
21730 		completion_min2 = completion_min;
21731 		gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(preferences_builder, "preferences_spin_completion_min2")), (double) completion_min2);
21732 	}
21733 }
on_preferences_spin_completion_min2_value_changed(GtkSpinButton * spin,gpointer)21734 void on_preferences_spin_completion_min2_value_changed(GtkSpinButton *spin, gpointer) {
21735 	completion_min2 = gtk_spin_button_get_value_as_int(spin);
21736 	if(completion_min2 < completion_min) {
21737 		completion_min = completion_min2;
21738 		gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(preferences_builder, "preferences_spin_completion_min")), (double) completion_min);
21739 	}
21740 }
on_preferences_spin_completion_delay_value_changed(GtkSpinButton * spin,gpointer)21741 void on_preferences_spin_completion_delay_value_changed(GtkSpinButton *spin, gpointer) {
21742 	completion_delay = gtk_spin_button_get_value_as_int(spin);
21743 }
21744 
on_preferences_scale_autocalc_history_value_changed(GtkRange * w,gpointer)21745 void on_preferences_scale_autocalc_history_value_changed(GtkRange *w, gpointer) {
21746 	autocalc_history_delay = (gint) ::round(::pow(gtk_range_get_value(GTK_RANGE(gtk_builder_get_object(preferences_builder, "preferences_scale_autocalc_history"))), 3.0));
21747 }
on_preferences_checkbutton_autocalc_history_toggled(GtkToggleButton * w,gpointer)21748 void on_preferences_checkbutton_autocalc_history_toggled(GtkToggleButton *w, gpointer) {
21749 	if(gtk_toggle_button_get_active(w)) {
21750 		autocalc_history_delay = (gint) ::round(::pow(gtk_range_get_value(GTK_RANGE(gtk_builder_get_object(preferences_builder, "preferences_scale_autocalc_history"))), 3.0));
21751 	} else {
21752 		autocalc_history_delay = -1;
21753 		if(autocalc_history_timeout_id) {
21754 			g_source_remove(autocalc_history_timeout_id);
21755 			autocalc_history_timeout_id = 0;
21756 		}
21757 	}
21758 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "preferences_scale_autocalc_history")), autocalc_history_delay >= 0);
21759 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(preferences_builder, "label_autocalc_history")), autocalc_history_delay >= 0);
21760 }
21761 
on_preferences_button_result_font_font_set(GtkFontButton * w,gpointer)21762 void on_preferences_button_result_font_font_set(GtkFontButton *w, gpointer) {
21763 	save_custom_result_font = true;
21764 	custom_result_font = gtk_font_chooser_get_font(GTK_FONT_CHOOSER(w));
21765 	gint h_old, h_new;
21766 	gtk_widget_get_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "scrolled_result")), NULL, &h_old);
21767 	gchar *gstr = font_name_to_css(custom_result_font.c_str());
21768 	gtk_css_provider_load_from_data(resultview_provider, gstr, -1, NULL);
21769 	g_free(gstr);
21770 	result_font_modified();
21771 	gtk_widget_get_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "scrolled_result")), NULL, &h_new);
21772 	gint winh, winw;
21773 	gtk_window_get_size(GTK_WINDOW(mainwindow), &winw, &winh);
21774 	winh += (h_new - h_old);
21775 	gtk_window_resize(GTK_WINDOW(mainwindow), winw, winh);
21776 }
on_preferences_button_expression_font_font_set(GtkFontButton * w,gpointer)21777 void on_preferences_button_expression_font_font_set(GtkFontButton *w, gpointer) {
21778 	save_custom_expression_font = true;
21779 	custom_expression_font = gtk_font_chooser_get_font(GTK_FONT_CHOOSER(w));
21780 	gint h_old, h_new;
21781 	gtk_widget_get_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "expressionscrolled")), NULL, &h_old);
21782 	gchar *gstr = font_name_to_css(custom_expression_font.c_str());
21783 	gtk_css_provider_load_from_data(expression_provider, gstr, -1, NULL);
21784 	g_free(gstr);
21785 	expression_font_modified();
21786 	gtk_widget_get_size_request(GTK_WIDGET(gtk_builder_get_object(main_builder, "expressionscrolled")), NULL, &h_new);
21787 	gint winh, winw;
21788 	gtk_window_get_size(GTK_WINDOW(mainwindow), &winw, &winh);
21789 	winh += (h_new - h_old);
21790 	gtk_window_resize(GTK_WINDOW(mainwindow), winw, winh);
21791 }
on_preferences_button_status_font_font_set(GtkFontButton * w,gpointer)21792 void on_preferences_button_status_font_font_set(GtkFontButton *w, gpointer) {
21793 	save_custom_status_font = true;
21794 	custom_status_font = gtk_font_chooser_get_font(GTK_FONT_CHOOSER(w));
21795 	gint h_old = gtk_widget_get_allocated_height(GTK_WIDGET(gtk_builder_get_object(main_builder, "statusbox")));
21796 	gchar *gstr = font_name_to_css(custom_status_font.c_str());
21797 	gtk_css_provider_load_from_data(statuslabel_l_provider, gstr, -1, NULL);
21798 	gtk_css_provider_load_from_data(statuslabel_r_provider, gstr, -1, NULL);
21799 	g_free(gstr);
21800 	set_operator_symbols();
21801 	while(gtk_events_pending()) gtk_main_iteration();
21802 	gint h_new = gtk_widget_get_allocated_height(GTK_WIDGET(gtk_builder_get_object(main_builder, "statusbox")));
21803 	gint winh, winw;
21804 	gtk_window_get_size(GTK_WINDOW(mainwindow), &winw, &winh);
21805 	winh += (h_new - h_old);
21806 	gtk_window_resize(GTK_WINDOW(mainwindow), winw, winh);
21807 }
on_preferences_button_keypad_font_font_set(GtkFontButton * w,gpointer)21808 void on_preferences_button_keypad_font_font_set(GtkFontButton *w, gpointer) {
21809 	save_custom_keypad_font = true;
21810 	custom_keypad_font = gtk_font_chooser_get_font(GTK_FONT_CHOOSER(w));
21811 	gchar *gstr = font_name_to_css(custom_keypad_font.c_str());
21812 	gtk_css_provider_load_from_data(keypad_provider, gstr, -1, NULL);
21813 	gtk_css_provider_load_from_data(box_rpnl_provider, gstr, -1, NULL);
21814 	g_free(gstr);
21815 	keypad_font_changed();
21816 }
on_preferences_button_app_font_font_set(GtkFontButton * w,gpointer)21817 void on_preferences_button_app_font_font_set(GtkFontButton *w, gpointer) {
21818 	save_custom_app_font = true;
21819 	custom_app_font = gtk_font_chooser_get_font(GTK_FONT_CHOOSER(w));
21820 	gchar *gstr = font_name_to_css(custom_app_font.c_str());
21821 	gtk_css_provider_load_from_data(app_provider, gstr, -1, NULL);
21822 	expression_font_modified();
21823 	result_font_modified();
21824 	g_free(gstr);
21825 	keypad_font_changed();
21826 }
21827 
21828 /*
21829 	hide unit manager when "Close" clicked
21830 */
on_units_button_close_clicked(GtkButton *,gpointer)21831 void on_units_button_close_clicked(GtkButton*, gpointer) {
21832 	gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_dialog")));
21833 }
21834 
21835 /*
21836 	change conversion direction in unit manager on user request
21837 */
on_units_toggle_button_from_toggled(GtkToggleButton * togglebutton,gpointer)21838 void on_units_toggle_button_from_toggled(GtkToggleButton *togglebutton, gpointer) {
21839 	if(gtk_toggle_button_get_active(togglebutton)) {
21840 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(units_builder, "units_toggle_button_to")), FALSE);
21841 		convert_in_wUnits();
21842 	}
21843 }
21844 
21845 /*
21846 	convert button clicked
21847 */
on_units_button_convert_clicked(GtkButton *,gpointer)21848 void on_units_button_convert_clicked(GtkButton*, gpointer) {
21849 	convert_in_wUnits();
21850 }
21851 
21852 /*
21853 	change conversion direction in unit manager on user request
21854 */
on_units_toggle_button_to_toggled(GtkToggleButton * togglebutton,gpointer)21855 void on_units_toggle_button_to_toggled(GtkToggleButton *togglebutton, gpointer) {
21856 	if(gtk_toggle_button_get_active(togglebutton)) {
21857 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(units_builder, "units_toggle_button_from")), FALSE);
21858 		convert_in_wUnits();
21859 	}
21860 }
21861 
21862 /*
21863 	enter in conversion field
21864 */
on_units_entry_from_val_activate(GtkEntry *,gpointer)21865 void on_units_entry_from_val_activate(GtkEntry*, gpointer) {
21866 	convert_in_wUnits(0);
21867 }
on_units_entry_to_val_activate(GtkEntry *,gpointer)21868 void on_units_entry_to_val_activate(GtkEntry*, gpointer) {
21869 	convert_in_wUnits(1);
21870 }
21871 
contains_polynomial_division(MathStructure & m)21872 bool contains_polynomial_division(MathStructure &m) {
21873 	if(m.isPower() && m[0].containsType(STRUCT_ADDITION) && m[1].representsNegative()) return true;
21874 	for(size_t i = 0; i < m.size(); i++) {
21875 		if(contains_polynomial_division(m[i])) return true;
21876 	}
21877 	return false;
21878 }
contains_imaginary_number(MathStructure & m)21879 bool contains_imaginary_number(MathStructure &m) {
21880 	if(m.isNumber() && m.number().hasImaginaryPart()) return true;
21881 	for(size_t i = 0; i < m.size(); i++) {
21882 		if(contains_imaginary_number(m[i])) return true;
21883 	}
21884 	return false;
21885 }
contains_rational_number(MathStructure & m)21886 bool contains_rational_number(MathStructure &m) {
21887 	if(m.isNumber() && ((m.number().realPartIsRational() && !m.number().realPart().isInteger()) || (m.number().hasImaginaryPart() && m.number().imaginaryPart().isRational() && !m.number().imaginaryPart().isInteger()))) return true;
21888 	for(size_t i = 0; i < m.size(); i++) {
21889 		if(contains_rational_number(m[i])) {
21890 			return i != 1 || !m.isPower() || !m[1].isNumber() || m[1].number().denominatorIsGreaterThan(9) || (m[1].number().numeratorIsGreaterThan(9) && !m[1].number().denominatorIsTwo() && !m[0].representsNonNegative(true));
21891 		}
21892 	}
21893 	return false;
21894 }
21895 
find_match_unformat(MathStructure & m)21896 void find_match_unformat(MathStructure &m) {
21897 	for(size_t i = 0; i < m.size(); i++) {
21898 		find_match_unformat(m[i]);
21899 	}
21900 	switch(m.type()) {
21901 		case STRUCT_INVERSE: {
21902 			m.setToChild(1, true);
21903 			if(m.isPower() && m[1].isNumber()) m[1].number().negate();
21904 			else m.raise(nr_minus_one);
21905 			break;
21906 		}
21907 		case STRUCT_NEGATE: {
21908 			m.setToChild(1);
21909 			if(m.type() != STRUCT_MULTIPLICATION) m.transform(STRUCT_MULTIPLICATION);
21910 			m.insertChild(m_minus_one, 1);
21911 			break;
21912 		}
21913 		case STRUCT_DIVISION: {
21914 			m.setType(STRUCT_MULTIPLICATION);
21915 			if(m[1].isPower() && m[1][1].isNumber()) m[1][1].number().negate();
21916 			else m[1].raise(nr_minus_one);
21917 			find_match_unformat(m);
21918 			break;
21919 		}
21920 		case STRUCT_MULTIPLICATION: {
21921 			for(size_t i = 0; i < m.size();) {
21922 				if(m[i].isMultiplication()) {
21923 					for(size_t i2 = 0; i2 < m[i].size(); i2++) {
21924 						m[i][i2].ref();
21925 						m.insertChild_nocopy(&m[i][i2], i + i2 + 2);
21926 					}
21927 					m.delChild(i + 1);
21928 				} else {
21929 					i++;
21930 				}
21931 			}
21932 			break;
21933 		}
21934 		default: {}
21935 	}
21936 }
21937 
find_exact_matching_unit2(const MathStructure & m)21938 Unit *find_exact_matching_unit2(const MathStructure &m) {
21939 	switch(m.type()) {
21940 		case STRUCT_POWER: {
21941 			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) {
21942 				Unit *u_base = m.base()->unit();
21943 				int exp = m.exponent()->number().intValue();
21944 				for(size_t i = 0; i < CALCULATOR->units.size(); i++) {
21945 
21946 					if(CALCULATOR->units[i]->subtype() == SUBTYPE_ALIAS_UNIT) {
21947 						AliasUnit *u = (AliasUnit*) CALCULATOR->units[i];
21948 						if(u->firstBaseUnit() == u_base && u->firstBaseExponent() == exp) return u;
21949 					}
21950 				}
21951 			}
21952 			break;
21953 		}
21954 		case STRUCT_UNIT: {
21955 			if(m.prefix() && !m.prefix()->value().isOne()) {
21956 				for(size_t i = 0; i < CALCULATOR->units.size(); i++) {
21957 					if(CALCULATOR->units[i]->subtype() == SUBTYPE_COMPOSITE_UNIT) {
21958 						CompositeUnit *u = (CompositeUnit*) CALCULATOR->units[i];
21959 						int exp = 0;
21960 						Prefix *p = NULL;
21961 						if(u->countUnits() == 1 && u->get(1, &exp, &p) == m.unit() && exp == 1 && p == m.prefix()) return u;
21962 					}
21963 				}
21964 			}
21965 			return m.unit();
21966 		}
21967 		case STRUCT_MULTIPLICATION: {
21968 			if(m.size() == 2 && !m[0].containsType(STRUCT_UNIT, false)) {
21969 				return find_exact_matching_unit2(m[1]);
21970 			}
21971 			CompositeUnit *cu = new CompositeUnit("", "temporary_find_matching_unit");
21972 			for(size_t i = 1; i <= m.countChildren(); i++) {
21973 				if(m.getChild(i)->isUnit()) {
21974 					cu->add(m.getChild(i)->unit(), 1, m.getChild(i)->prefix() && !m.getChild(i)->prefix()->value().isOne() ? m.getChild(i)->prefix() : NULL);
21975 				} 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) {
21976 					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);
21977 				} else if(m.getChild(i)->containsType(STRUCT_UNIT, false)) {
21978 					delete cu;
21979 					return NULL;
21980 				}
21981 			}
21982 			if(cu->countUnits() == 1) {
21983 				int exp = 1;
21984 				Prefix *p = NULL;
21985 				Unit *u = cu->get(1, &exp, &p);
21986 				MathStructure m2(u, p);
21987 				if(exp != 1) m2.raise(exp);
21988 				return find_exact_matching_unit2(m2);
21989 			}
21990 			for(size_t i = 0; i < CALCULATOR->units.size(); i++) {
21991 				Unit *u = CALCULATOR->units[i];
21992 				if(u->subtype() == SUBTYPE_COMPOSITE_UNIT) {
21993 					if(((CompositeUnit*) u)->countUnits() == cu->countUnits()) {
21994 						bool b = true;
21995 						for(size_t i2 = 1; i2 <= cu->countUnits(); i2++) {
21996 							int exp1 = 1, exp2 = 1;
21997 							Prefix *p1 = NULL, *p2 = NULL;
21998 							Unit *ui1 = cu->get(i2, &exp1, &p1);
21999 							b = false;
22000 							for(size_t i3 = 1; i3 <= cu->countUnits(); i3++) {
22001 								Unit *ui2 = ((CompositeUnit*) u)->get(i3, &exp2, &p2);
22002 								if(ui1 == ui2) {
22003 									b = (exp1 == exp2 && p1 == p2);
22004 									break;
22005 								}
22006 							}
22007 							if(!b) break;
22008 						}
22009 						if(b) {
22010 							delete cu;
22011 							return u;
22012 						}
22013 					}
22014 				}
22015 			}
22016 			delete cu;
22017 			break;
22018 		}
22019 		default: {}
22020 	}
22021 	return NULL;
22022 }
22023 
22024 
find_exact_matching_unit(const MathStructure & m)22025 Unit *find_exact_matching_unit(const MathStructure &m) {
22026 	MathStructure m2(m);
22027 	find_match_unformat(m2);
22028 	return find_exact_matching_unit2(m2);
22029 }
22030 
contains_convertable_unit(MathStructure & m)22031 bool contains_convertable_unit(MathStructure &m) {
22032 	if(m.type() == STRUCT_UNIT) return true;
22033 	for(size_t i = 0; i < m.size(); i++) {
22034 		if(!m.isFunction() || !m.function()->getArgumentDefinition(i + 1) || m.function()->getArgumentDefinition(i + 1)->type() != ARGUMENT_TYPE_ANGLE) {
22035 			if(contains_convertable_unit(m[i])) return true;
22036 		}
22037 	}
22038 	return false;
22039 }
22040 
test_can_approximate(const MathStructure & m,bool top=true)22041 bool test_can_approximate(const MathStructure &m, bool top = true) {
22042 	if((m.isVariable() && m.variable()->isKnown()) || (m.isNumber() && !top)) return true;
22043 	if(m.isUnit_exp()) return false;
22044 	for(size_t i = 0; i < m.size(); i++) {
22045 		if(test_can_approximate(m[i], false)) return true;
22046 	}
22047 	return false;
22048 }
22049 
has_prefix(const MathStructure & m)22050 bool has_prefix(const MathStructure &m) {
22051 	if(m.isUnit() && (m.prefix() && m.prefix() != CALCULATOR->decimal_null_prefix && m.prefix() != CALCULATOR->binary_null_prefix)) return true;
22052 	for(size_t i = 0; i < m.size(); i++) {
22053 		if(has_prefix(m[i])) return true;
22054 	}
22055 	return false;
22056 }
22057 
update_resultview_popup()22058 void update_resultview_popup() {
22059 	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);
22060 	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);
22061 	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);
22062 	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);
22063 	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);
22064 	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);
22065 	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);
22066 	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);
22067 	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);
22068 	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);
22069 	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);
22070 	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);
22071 	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);
22072 	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);
22073 	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);
22074 	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);
22075 	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);
22076 	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);
22077 	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_mixed_units_conversion"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_mixed_units_conversion_activate, NULL);
22078 	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);
22079 	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);
22080 	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);
22081 	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);
22082 	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);
22083 	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);
22084 	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);
22085 	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_exact"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_exact_activate, NULL);
22086 	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);
22087 	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);
22088 	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);
22089 	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);
22090 	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);
22091 
22092 	bool b_unit = displayed_mstruct && contains_convertable_unit(*displayed_mstruct);
22093 	bool b_date = displayed_mstruct && displayed_mstruct->isDateTime();
22094 	bool b_complex = displayed_mstruct && mstruct && (contains_imaginary_number(*mstruct) || mstruct->containsFunctionId(FUNCTION_ID_CIS));
22095 	bool b_rational = displayed_mstruct && mstruct && contains_rational_number(*mstruct);
22096 	bool b_object = displayed_mstruct && (displayed_mstruct->containsType(STRUCT_UNIT) || displayed_mstruct->containsType(STRUCT_FUNCTION) || displayed_mstruct->containsType(STRUCT_VARIABLE));
22097 
22098 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_abbreviate_names")), b_object);
22099 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "separator_popup_abbreviate_names")), b_object);
22100 
22101 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "separator_popup_display_prefixes")), b_unit);
22102 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_display_no_prefixes")), b_unit);
22103 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_display_prefixes_for_selected_units")), b_unit);
22104 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_display_prefixes_for_currencies")), b_unit);
22105 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_display_prefixes_for_all_units")), b_unit);
22106 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_all_prefixes")), b_unit);
22107 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_denominator_prefixes")), b_unit);
22108 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "separator_popup_unit_settings")), b_unit);
22109 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_convert_to_unit")), FALSE);
22110 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_convert_to_base_units")), b_unit);
22111 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_convert_to_best_unit")), b_unit);
22112 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_set_optimal_prefix")), b_unit);
22113 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_convert_to")), FALSE);
22114 	if(displayed_mstruct && ((displayed_mstruct->isMultiplication() && displayed_mstruct->size() == 2 && (*displayed_mstruct)[1].isUnit() && (*displayed_mstruct)[0].isNumber() && (*displayed_mstruct)[1].unit()->subtype() == SUBTYPE_ALIAS_UNIT && ((AliasUnit*) (*displayed_mstruct)[1].unit())->mixWithBase()) || (displayed_mstruct->isAddition() && displayed_mstruct->size() > 0 && (*displayed_mstruct)[0].isMultiplication() && (*displayed_mstruct)[0].size() == 2 && (*displayed_mstruct)[0][1].isUnit() && (*displayed_mstruct)[0][0].isNumber() && (*displayed_mstruct)[0][1].unit()->subtype() == SUBTYPE_ALIAS_UNIT && ((AliasUnit*) (*displayed_mstruct)[0][1].unit())->mixWithBase()))) {
22115 		gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_mixed_units_conversion")), TRUE);
22116 	} else {
22117 		gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_mixed_units_conversion")), FALSE);
22118 	}
22119 	if(b_unit) {
22120 		GtkWidget *sub = GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_convert_to"));
22121 		GtkWidget *item;
22122 		if(expression_has_changed && !rpn_mode && !auto_calculate) execute_expression(true);
22123 		GList *list = gtk_container_get_children(GTK_CONTAINER(sub));
22124 		for(GList *l = list; l != NULL; l = l->next) {
22125 			gtk_widget_destroy(GTK_WIDGET(l->data));
22126 		}
22127 		g_list_free(list);
22128 		Unit *u_result = NULL;
22129 		if(displayed_mstruct) u_result = find_exact_matching_unit(*displayed_mstruct);
22130 		bool b_exact = (u_result != NULL);
22131 		if(!u_result) u_result = CALCULATOR->findMatchingUnit(*mstruct);
22132 		bool b_prefix = false;
22133 		if(b_exact && u_result && u_result->subtype() != SUBTYPE_COMPOSITE_UNIT) b_prefix = has_prefix(*displayed_mstruct);
22134 		vector<Unit*> to_us;
22135 		if(u_result && u_result->isCurrency()) {
22136 			Unit *u_local_currency = CALCULATOR->getLocalCurrency();
22137 			if(latest_button_currency && (!b_exact || b_prefix || latest_button_currency != u_result) && latest_button_currency != u_local_currency) to_us.push_back(latest_button_currency);
22138 			for(size_t i = 0; i < CALCULATOR->units.size() + 2; i++) {
22139 				Unit * u;
22140 				if(i == 0) u = u_local_currency;
22141 				else if(i == 1) u = latest_button_currency;
22142 				else u = CALCULATOR->units[i - 2];
22143 				if(u && (!b_exact || b_prefix || u != u_result) && u->isActive() && u->isCurrency() && (i == 0 || (u != u_local_currency && u != latest_button_currency && !u->isHidden()))) {
22144 					bool b = false;
22145 					for(size_t i2 = 0; i2 < to_us.size(); i2++) {
22146 						if(string_is_less(u->title(true), to_us[i2]->title(true))) {
22147 							to_us.insert(to_us.begin() + i2, u);
22148 							b = true;
22149 							break;
22150 						}
22151 					}
22152 					if(!b) to_us.push_back(u);
22153 				}
22154 			}
22155 			for(size_t i = 0; i < to_us.size(); i++) {
22156 				MENU_ITEM_WITH_POINTER_AND_FLAG(to_us[i]->title(true).c_str(), convert_to_unit, to_us[i])
22157 			}
22158 			vector<Unit*> to_us2;
22159 			for(size_t i = 0; i < CALCULATOR->units.size(); i++) {
22160 				if(CALCULATOR->units[i]->isCurrency()) {
22161 					Unit *u = CALCULATOR->units[i];
22162 					if(u->isActive() && (!b_exact || b_prefix || u != u_result) && u->isHidden() && u != u_local_currency && u != latest_button_currency) {
22163 						bool b = false;
22164 						for(int i2 = to_us2.size() - 1; i2 >= 0; i2--) {
22165 							if(u->title(true) > to_us2[(size_t) i2]->title(true)) {
22166 								if((size_t) i2 == to_us2.size() - 1) to_us2.push_back(u);
22167 								else to_us2.insert(to_us2.begin() + (size_t) i2 + 1, u);
22168 								b = true;
22169 								break;
22170 							}
22171 						}
22172 						if(!b) to_us2.insert(to_us2.begin(), u);
22173 					}
22174 				}
22175 			}
22176 			if(to_us2.size() > 0) {
22177 				SUBMENU_ITEM(_("more"), sub);
22178 				for(size_t i = 0; i < to_us2.size(); i++) {
22179 					// Show further items in a submenu
22180 					MENU_ITEM_WITH_POINTER_AND_FLAG(to_us2[i]->title(true).c_str(), convert_to_unit, to_us2[i])
22181 				}
22182 			}
22183 			gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_convert_to")), TRUE);
22184 		} else if(u_result && !u_result->category().empty()) {
22185 			string s_cat = u_result->category();
22186 			for(size_t i = 0; i < CALCULATOR->units.size(); i++) {
22187 				if(CALCULATOR->units[i]->category() == s_cat) {
22188 					Unit *u = CALCULATOR->units[i];
22189 					if((!b_exact || b_prefix || u != u_result) && u->isActive() && !u->isHidden()) {
22190 						bool b = false;
22191 						for(size_t i2 = 0; i2 < to_us.size(); i2++) {
22192 							if(string_is_less(u->title(true), to_us[i2]->title(true))) {
22193 								to_us.insert(to_us.begin() + i2, u);
22194 								b = true;
22195 								break;
22196 							}
22197 						}
22198 						if(!b) to_us.push_back(u);
22199 					}
22200 				}
22201 			}
22202 			for(size_t i = 0; i < to_us.size(); i++) {
22203 				MENU_ITEM_WITH_POINTER(to_us[i]->title(true).c_str(), convert_to_unit_noprefix, to_us[i])
22204 			}
22205 			gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_convert_to")), TRUE);
22206 		}
22207 	}
22208 
22209 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "separator_popup_units")), b_unit);
22210 
22211 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_octal")), !b_unit && !b_date && !b_complex);
22212 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_decimal")), !b_unit && !b_date && !b_complex);
22213 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_duodecimal")), !b_unit && !b_date && !b_complex);
22214 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_hexadecimal")), !b_unit && !b_date && !b_complex);
22215 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_binary")), !b_unit && !b_date && !b_complex);
22216 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_roman")), FALSE);
22217 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_sexagesimal")), FALSE);
22218 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_time_format")), FALSE);
22219 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_custom_base")), !b_unit && !b_date && !b_complex);
22220 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "separator_popup_base")), !b_unit && !b_date && !b_complex);
22221 
22222 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_complex_rectangular")), b_complex);
22223 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_complex_exponential")), b_complex);
22224 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_complex_polar")), b_complex);
22225 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_complex_angle")), b_complex);
22226 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "separator_popup_complex")), b_complex);
22227 
22228 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_display_normal")), !b_unit && !b_date);
22229 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_display_engineering")), !b_unit && !b_date);
22230 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_display_scientific")), !b_unit && !b_date);
22231 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_display_purely_scientific")), FALSE);
22232 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_display_non_scientific")), !b_unit && !b_date);
22233 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "separator_popup_display")), !b_unit && !b_date);
22234 
22235 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "separator_popup_fraction")), b_rational);
22236 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_fraction_decimal")), b_rational);
22237 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_fraction_decimal_exact")), b_rational);
22238 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_fraction_combined")), b_rational);
22239 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_fraction_fraction")), b_rational);
22240 
22241 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_calendarconversion")), b_date);
22242 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_to_utc")), b_date);
22243 	gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "separator_popup_display_date")), b_date);
22244 
22245 	if(mstruct && mstruct->containsUnknowns()) {
22246 		gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_set_unknowns")));
22247 		gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(main_builder, "separator_popup_factorize")));
22248 	} else {
22249 		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_set_unknowns")));
22250 		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "separator_popup_factorize")));
22251 	}
22252 	if(mstruct && mstruct->containsType(STRUCT_ADDITION)) {
22253 		if(evalops.structuring == STRUCTURING_FACTORIZE) {
22254 			gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_factorize")));
22255 		} else {
22256 			gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_factorize")));
22257 		}
22258 		if(evalops.structuring == STRUCTURING_SIMPLIFY) {
22259 			gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_simplify")));
22260 		} else {
22261 			gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_simplify")));
22262 		}
22263 		if(contains_polynomial_division(*mstruct)) gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_expand_partial_fractions")));
22264 		else gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_expand_partial_fractions")));
22265 		gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(main_builder, "separator_popup_factorize")));
22266 	} else {
22267 		if(mstruct && mstruct->isNumber() && mstruct->number().isInteger() && !mstruct->number().isZero()) {
22268 			gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_factorize")));
22269 			gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(main_builder, "separator_popup_factorize")));
22270 		} else {
22271 			gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_factorize")));
22272 		}
22273 		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_simplify")));
22274 		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_expand_partial_fractions")));
22275 	}
22276 	if(mstruct && (mstruct->isApproximate() || test_can_approximate(*mstruct))) {
22277 		gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_exact")));
22278 		gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(main_builder, "separator_popup_nonzero")));
22279 		if(!mstruct->isApproximate() && mstruct->containsDivision()) gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_assume_nonzero_denominators")));
22280 		else gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_assume_nonzero_denominators")));
22281 	} else {
22282 		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_exact")));
22283 		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_assume_nonzero_denominators")));
22284 		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "separator_popup_nonzero")));
22285 	}
22286 	if(mstruct->isVector() && (mstruct->size() != 1 || !(*mstruct)[0].isVector() || (*mstruct)[0].size() > 0)) {
22287 		if(mstruct->isMatrix()) {
22288 			gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_view_matrix")));
22289 			gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_view_vector")));
22290 		} else {
22291 			gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_view_matrix")));
22292 			gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_view_vector")));
22293 		}
22294 		gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(main_builder, "separator_popup_view_matrixvector")));
22295 	} else {
22296 		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_view_matrix")));
22297 		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_view_vector")));
22298 		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(main_builder, "separator_popup_view_matrixvector")));
22299 	}
22300 	switch (printops.base) {
22301 		case BASE_OCTAL: {
22302 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_octal")), TRUE);
22303 			break;
22304 		}
22305 		case BASE_DECIMAL: {
22306 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_decimal")), TRUE);
22307 			break;
22308 		}
22309 		case BASE_DUODECIMAL: {
22310 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_duodecimal")), TRUE);
22311 			break;
22312 		}
22313 		case BASE_HEXADECIMAL: {
22314 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_hexadecimal")), TRUE);
22315 			break;
22316 		}
22317 		case BASE_BINARY: {
22318 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_binary")), TRUE);
22319 			break;
22320 		}
22321 		case BASE_ROMAN_NUMERALS: {
22322 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_roman")), TRUE);
22323 			break;
22324 		}
22325 		/*case BASE_SEXAGESIMAL: {
22326 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_sexagesimal")), TRUE);
22327 			break;
22328 		}
22329 		case BASE_TIME: {
22330 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_time_format")), TRUE);
22331 			break;
22332 		}*/
22333 		default: {
22334 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_custom_base")), TRUE);
22335 			break;
22336 		}
22337 	}
22338 	switch(printops.min_exp) {
22339 		case EXP_PRECISION: {
22340 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_display_normal")), TRUE);
22341 			break;
22342 		}
22343 		case EXP_BASE_3: {
22344 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_display_engineering")), TRUE);
22345 			break;
22346 		}
22347 		case EXP_SCIENTIFIC: {
22348 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_display_scientific")), TRUE);
22349 			break;
22350 		}
22351 		case EXP_PURE: {
22352 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_display_purely_scientific")), TRUE);
22353 			break;
22354 		}
22355 		case EXP_NONE: {
22356 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_display_non_scientific")), TRUE);
22357 			break;
22358 		}
22359 	}
22360 	if(!printops.use_unit_prefixes) {
22361 		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_display_no_prefixes")), TRUE);
22362 	} else if(printops.use_prefixes_for_all_units) {
22363 		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);
22364 	} else if(printops.use_prefixes_for_currencies) {
22365 		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_display_prefixes_for_currencies")), TRUE);
22366 	} else {
22367 		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);
22368 	}
22369 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_mixed_units_conversion")), evalops.mixed_units_conversion != MIXED_UNITS_CONVERSION_NONE);
22370 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_abbreviate_names")), printops.abbreviate_names);
22371 	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);
22372 	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);
22373 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_exact")), evalops.approximation == APPROXIMATION_EXACT);
22374 	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);
22375 	switch(printops.number_fraction_format) {
22376 		case FRACTION_DECIMAL: {
22377 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_fraction_decimal")), TRUE);
22378 			break;
22379 		}
22380 		case FRACTION_DECIMAL_EXACT: {
22381 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_fraction_decimal_exact")), TRUE);
22382 			break;
22383 		}
22384 		case FRACTION_COMBINED: {
22385 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_fraction_combined")), TRUE);
22386 			break;
22387 		}
22388 		case FRACTION_FRACTIONAL: {
22389 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_fraction_fraction")), TRUE);
22390 			break;
22391 		}
22392 	}
22393 	switch(evalops.complex_number_form) {
22394 		case COMPLEX_NUMBER_FORM_RECTANGULAR: {
22395 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_complex_rectangular")), TRUE);
22396 			break;
22397 		}
22398 		case COMPLEX_NUMBER_FORM_EXPONENTIAL: {
22399 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_complex_exponential")), TRUE);
22400 			break;
22401 		}
22402 		case COMPLEX_NUMBER_FORM_POLAR: {
22403 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_complex_polar")), TRUE);
22404 			break;
22405 		}
22406 		case COMPLEX_NUMBER_FORM_CIS: {
22407 			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);
22408 			else gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_complex_polar")), TRUE);
22409 			break;
22410 		}
22411 	}
22412 	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);
22413 	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);
22414 	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);
22415 	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);
22416 	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);
22417 	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);
22418 	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);
22419 	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);
22420 	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);
22421 	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);
22422 	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);
22423 	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);
22424 	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);
22425 	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);
22426 	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);
22427 	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);
22428 	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);
22429 	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);
22430 	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_mixed_units_conversion"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_mixed_units_conversion_activate, NULL);
22431 	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);
22432 	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);
22433 	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);
22434 	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);
22435 	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);
22436 	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);
22437 	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);
22438 	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "popup_menu_item_exact"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_popup_menu_item_exact_activate, NULL);
22439 	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);
22440 	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);
22441 	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);
22442 	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);
22443 	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);
22444 }
22445 
epxression_tooltip_timeout(gpointer)22446 gboolean epxression_tooltip_timeout(gpointer) {
22447 	gtk_widget_trigger_tooltip_query(GTK_WIDGET(gtk_builder_get_object(main_builder, "expression_button")));
22448 	return FALSE;
22449 }
on_expression_button_button_press_event(GtkWidget *,GdkEventButton * event,gpointer)22450 gboolean on_expression_button_button_press_event(GtkWidget*, GdkEventButton *event, gpointer) {
22451 	if(event->button != 1) return FALSE;
22452 	GtkWidget *w = gtk_stack_get_visible_child(GTK_STACK(gtk_builder_get_object(main_builder, "expression_button_stack")));
22453 	if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "expression_button_equals"))) {
22454 		execute_expression();
22455 	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "expression_button_clear"))) {
22456 		clear_expression_text();
22457 		gtk_widget_grab_focus(expressiontext);
22458 	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "message_tooltip_icon"))) {
22459 		g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE, 0, epxression_tooltip_timeout, NULL, NULL);
22460 	} else {
22461 		if(b_busy_command) on_abort_command(NULL, 0, NULL);
22462 		else if(b_busy_expression) on_abort_calculation(NULL, 0, NULL);
22463 		else if(b_busy_result) on_abort_display(NULL, 0, NULL);
22464 	}
22465 	return TRUE;
22466 }
on_expression_button_button_release_event(GtkWidget *,GdkEventButton * event,gpointer)22467 gboolean on_expression_button_button_release_event(GtkWidget*, GdkEventButton *event, gpointer) {
22468 	if(event->button != 1) return FALSE;
22469 	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, "message_tooltip_icon"))) {
22470 		g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE, 0, epxression_tooltip_timeout, NULL, NULL);
22471 		return TRUE;
22472 	}
22473 	return FALSE;
22474 }
on_expressiontext_button_press_event(GtkWidget *,GdkEventButton * event,gpointer)22475 gboolean on_expressiontext_button_press_event(GtkWidget*, GdkEventButton *event, gpointer) {
22476 	if(gdk_event_triggers_context_menu((GdkEvent*) event) && event->type == GDK_BUTTON_PRESS) {
22477 		if(b_busy) return TRUE;
22478 	}
22479 	return FALSE;
22480 }
on_units_dialog_button_press_event(GtkWidget *,GdkEventButton * event,gpointer)22481 gboolean on_units_dialog_button_press_event(GtkWidget*, GdkEventButton *event, gpointer) {
22482 	gtk_widget_hide(units_convert_window);
22483 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(units_builder, "units_convert_to_button")), FALSE);
22484 	return FALSE;
22485 }
on_units_dialog_delete_event()22486 gboolean on_units_dialog_delete_event() {
22487 	gtk_widget_hide(units_convert_window);
22488 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(units_builder, "units_convert_to_button")), FALSE);
22489 	return FALSE;
22490 }
on_main_window_button_press_event(GtkWidget *,GdkEventButton * event,gpointer)22491 gboolean on_main_window_button_press_event(GtkWidget*, GdkEventButton *event, gpointer) {
22492 	gtk_widget_hide(completion_window);
22493 	return FALSE;
22494 }
on_resultview_button_press_event(GtkWidget *,GdkEventButton * event,gpointer)22495 gboolean on_resultview_button_press_event(GtkWidget*, GdkEventButton *event, gpointer) {
22496 	if(gdk_event_triggers_context_menu((GdkEvent*) event) && event->type == GDK_BUTTON_PRESS) {
22497 		if(b_busy) return TRUE;
22498 		update_resultview_popup();
22499 #if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 22
22500 		gtk_menu_popup_at_pointer(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_resultview")), (GdkEvent*) event);
22501 #else
22502 		gtk_menu_popup(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_resultview")), NULL, NULL, NULL, NULL, event->button, event->time);
22503 #endif
22504 		return TRUE;
22505 	}
22506 	if(event->button == 1 && surface_result && event->x >= gtk_widget_get_allocated_width(resultview) - cairo_image_surface_get_width(surface_result) - 20) {
22507 		on_menu_item_copy_activate(NULL, NULL);
22508 		// Result was copied
22509 		show_notification(_("Copied"));
22510 	}
22511 	return FALSE;
22512 }
on_resultview_popup_menu(GtkWidget *,gpointer)22513 gboolean on_resultview_popup_menu(GtkWidget*, gpointer) {
22514 	if(b_busy) return TRUE;
22515 	update_resultview_popup();
22516 #if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 22
22517 	gtk_menu_popup_at_pointer(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_resultview")), NULL);
22518 #else
22519 	gtk_menu_popup(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_resultview")), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time());
22520 #endif
22521 	return TRUE;
22522 }
22523 
on_button_programmers_keypad_toggled(GtkToggleButton * w,gpointer)22524 void on_button_programmers_keypad_toggled(GtkToggleButton *w, gpointer) {
22525 	previous_keypad = visible_keypad;
22526 	if(gtk_toggle_button_get_active(w)) {
22527 		visible_keypad = visible_keypad | PROGRAMMING_KEYPAD;
22528 		if(evalops.approximation == APPROXIMATION_EXACT) {
22529 			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "button_exact")), FALSE);
22530 			versatile_exact = true;
22531 		} else {
22532 			versatile_exact = false;
22533 		}
22534 		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)) {
22535 			if(printops.base != programming_outbase) {
22536 				printops.base = programming_outbase;
22537 				set_output_base_from_dialog(programming_outbase);
22538 				output_base_updated_from_menu();
22539 				if(evalops.parse_options.base == programming_inbase) result_format_updated();
22540 			}
22541 			if(evalops.parse_options.base != programming_inbase) {
22542 				evalops.parse_options.base = programming_inbase;
22543 				input_base_updated_from_menu();
22544 				update_keypad_bases();
22545 				expression_format_updated();
22546 			}
22547 		}
22548 		programming_inbase = 0;
22549 		programming_outbase = 0;
22550 		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")));
22551 		if(displayed_mstruct) {
22552 			set_result_bases(*displayed_mstruct);
22553 			update_result_bases();
22554 		}
22555 		gtk_stack_set_visible_child_name(GTK_STACK(gtk_builder_get_object(main_builder, "stack_keypad_top")), "page1");
22556 	} else {
22557 		if(versatile_exact && evalops.approximation == APPROXIMATION_TRY_EXACT) {
22558 			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "button_exact")), TRUE);
22559 		}
22560 		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")));
22561 		gtk_stack_set_visible_child_name(GTK_STACK(gtk_builder_get_object(main_builder, "stack_keypad_top")), "page0");
22562 		visible_keypad = visible_keypad & ~PROGRAMMING_KEYPAD;
22563 		programming_inbase = evalops.parse_options.base;
22564 		programming_outbase = printops.base;
22565 		if(evalops.parse_options.base != 10) clear_expression_text();
22566 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "button_dec")), TRUE);
22567 		result_bin = ""; result_oct = ""; result_dec = ""; result_hex = "";
22568 		update_result_bases();
22569 	}
22570 	focus_keeping_selection();
22571 }
22572 
on_hide_left_buttons_button_release_event(GtkWidget *,GdkEventButton * event,gpointer)22573 gboolean on_hide_left_buttons_button_release_event(GtkWidget*, GdkEventButton *event, gpointer) {
22574 	if(event->type == GDK_BUTTON_RELEASE && event->button == 1) {
22575 		bool hide_left_keypad = gtk_widget_is_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "stack_left_buttons")));
22576 		gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "stack_left_buttons")), !hide_left_keypad);
22577 		gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "event_hide_right_buttons")), !hide_left_keypad);
22578 		if(hide_left_keypad) {
22579 			visible_keypad = visible_keypad | HIDE_LEFT_KEYPAD;
22580 			GtkRequisition req;
22581 			gtk_widget_get_preferred_size(GTK_WIDGET(gtk_builder_get_object(main_builder, "menubar")), &req, NULL);
22582 			gtk_window_resize(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), req.width + 24, 1);
22583 		} else {
22584 			visible_keypad = visible_keypad & ~HIDE_LEFT_KEYPAD;
22585 		}
22586 		focus_keeping_selection();
22587 		return TRUE;
22588 	}
22589 	return FALSE;
22590 }
on_hide_right_buttons_button_release_event(GtkWidget *,GdkEventButton * event,gpointer)22591 gboolean on_hide_right_buttons_button_release_event(GtkWidget*, GdkEventButton *event, gpointer) {
22592 	if(event->type == GDK_BUTTON_RELEASE && event->button == 1) {
22593 		bool hide_right_keypad = gtk_widget_is_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "box_right_buttons")));
22594 		gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "box_right_buttons")), !hide_right_keypad);
22595 		gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(main_builder, "event_hide_left_buttons")), !hide_right_keypad);
22596 		if(hide_right_keypad) {
22597 			visible_keypad = visible_keypad | HIDE_RIGHT_KEYPAD;
22598 			GtkRequisition req;
22599 			gtk_widget_get_preferred_size(GTK_WIDGET(gtk_builder_get_object(main_builder, "menubar")), &req, NULL);
22600 			gtk_window_resize(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), req.width + 24, 1);
22601 		} else {
22602 			visible_keypad = visible_keypad & ~HIDE_RIGHT_KEYPAD;
22603 		}
22604 		focus_keeping_selection();
22605 		return TRUE;
22606 	}
22607 	return FALSE;
22608 }
22609 
on_units_entry_from_val_focus_out_event(GtkEntry *,GdkEventFocus *,gpointer)22610 gboolean on_units_entry_from_val_focus_out_event(GtkEntry*, GdkEventFocus*, gpointer) {
22611 	if(old_fromValue != gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(units_builder, "units_entry_from_val")))) convert_in_wUnits(0);
22612 	return FALSE;
22613 }
on_units_entry_to_val_focus_out_event(GtkEntry *,GdkEventFocus *,gpointer)22614 gboolean on_units_entry_to_val_focus_out_event(GtkEntry*, GdkEventFocus*, gpointer) {
22615 	if(old_toValue != gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(units_builder, "units_entry_to_val")))) convert_in_wUnits(1);
22616 	return FALSE;
22617 }
22618 
22619 /*
22620 	enter in expression entry does the same as clicking "Execute" button
22621 */
on_expression_activate(GtkEntry *,gpointer)22622 void on_expression_activate(GtkEntry*, gpointer) {
22623 	execute_expression();
22624 }
22625 
on_convert_entry_unit_icon_release(GtkEntry * entry,GtkEntryIconPosition icon_pos,GdkEvent *,gpointer)22626 void on_convert_entry_unit_icon_release(GtkEntry *entry, GtkEntryIconPosition icon_pos, GdkEvent*, gpointer) {
22627 	switch(icon_pos) {
22628 		case GTK_ENTRY_ICON_PRIMARY: {
22629 			break;
22630 		}
22631 		case GTK_ENTRY_ICON_SECONDARY: {
22632 			gtk_editable_delete_text(GTK_EDITABLE(entry), 0, -1);
22633 			break;
22634 		}
22635 	}
22636 }
22637 
22638 /*
22639 	save preferences, mode and definitions and then quit
22640 */
on_gcalc_exit(GtkWidget *,GdkEvent *,gpointer)22641 gboolean on_gcalc_exit(GtkWidget*, GdkEvent*, gpointer) {
22642 	stop_timeouts = true;
22643 	exit_in_progress = true;
22644 	CALCULATOR->abort();
22645 	if(plot_builder && gtk_widget_get_visible(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_dialog")))) {
22646 		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_dialog")));
22647 	}
22648 	if(save_mode_on_exit) {
22649 		save_mode();
22650 	} else {
22651 		save_preferences();
22652 	}
22653 	if(save_defs_on_exit) {
22654 		save_defs();
22655 	}
22656 	for(size_t i = 0; i < history_parsed.size(); i++) {
22657 		if(history_parsed[i]) history_parsed[i]->unref();
22658 		if(history_answer[i]) history_answer[i]->unref();
22659 	}
22660 	if(view_thread->running) {
22661 		view_thread->write(0);
22662 		view_thread->write(NULL);
22663 	}
22664 	CALCULATOR->terminateThreads();
22665 	g_application_quit(g_application_get_default());
22666 	return TRUE;
22667 }
22668 
on_button_reciprocal_clicked(GtkButton *,gpointer)22669 void on_button_reciprocal_clicked(GtkButton*, gpointer) {
22670 	if(rpn_mode || evalops.parse_options.parsing_mode == PARSING_MODE_RPN || is_at_beginning_of_expression()) {
22671 		insertButtonFunction(CALCULATOR->getActiveFunction("inv"));
22672 	} else {
22673 		bool do_exec = wrap_expression_selection(NULL, true) > 0;
22674 		insert_text("^-1");
22675 		if(do_exec) execute_expression();
22676 	}
22677 }
on_button_idiv_clicked(GtkButton *,gpointer)22678 void on_button_idiv_clicked(GtkButton*, gpointer) {
22679 	if(expression_is_empty() || rpn_mode || evalops.parse_options.parsing_mode == PARSING_MODE_RPN || is_at_beginning_of_expression() || wrap_expression_selection() < 0) {
22680 		insertButtonFunction(CALCULATOR->getActiveFunction("div"));
22681 	} else {
22682 		insert_text("//");
22683 	}
22684 }
22685 
22686 /*
22687 	STO button clicked -- store result
22688 */
on_button_store_clicked(GtkButton *,gpointer)22689 void on_button_store_clicked(GtkButton*, gpointer) {
22690 	if(displayed_mstruct && mstruct && !mstruct->isZero()) add_as_variable();
22691 	else edit_variable(_("My Variables"), NULL, NULL, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")));
22692 }
22693 
22694 bool completion_ignore_enter = false, completion_hover_blocked = false;
22695 
on_completionview_enter_notify_event(GtkWidget *,GdkEventCrossing *,gpointer)22696 gboolean on_completionview_enter_notify_event(GtkWidget*, GdkEventCrossing*, gpointer) {
22697 	return completion_ignore_enter;
22698 }
on_completionview_motion_notify_event(GtkWidget *,GdkEventMotion *,gpointer)22699 gboolean on_completionview_motion_notify_event(GtkWidget*, GdkEventMotion*, gpointer) {
22700 	completion_ignore_enter = FALSE;
22701 	if(completion_hover_blocked) {
22702 		gtk_tree_view_set_hover_selection(GTK_TREE_VIEW(completion_view), TRUE);
22703 		completion_hover_blocked = false;
22704 	}
22705 	return FALSE;
22706 }
on_completionwindow_key_press_event(GtkWidget * widget,GdkEventKey * event,gpointer user_data)22707 gboolean on_completionwindow_key_press_event(GtkWidget *widget, GdkEventKey *event, gpointer user_data) {
22708 	if(!gtk_widget_get_mapped(completion_window)) return FALSE;
22709 	gtk_widget_event(expressiontext, (GdkEvent*) event);
22710 	return TRUE;
22711 }
on_completionwindow_button_press_event(GtkWidget * widget,GdkEventButton * event,gpointer user_data)22712 gboolean on_completionwindow_button_press_event(GtkWidget *widget, GdkEventButton *event, gpointer user_data) {
22713 	if(!gtk_widget_get_mapped(completion_window)) return FALSE;
22714 	gtk_widget_hide(completion_window);
22715 	return TRUE;
22716 }
22717 
22718 bool units_convert_ignore_enter = false, units_convert_hover_blocked = false;
22719 
on_units_convert_view_enter_notify_event(GtkWidget *,GdkEventCrossing *,gpointer)22720 gboolean on_units_convert_view_enter_notify_event(GtkWidget*, GdkEventCrossing*, gpointer) {
22721 	return units_convert_ignore_enter;
22722 }
on_units_convert_view_motion_notify_event(GtkWidget *,GdkEventMotion *,gpointer)22723 gboolean on_units_convert_view_motion_notify_event(GtkWidget*, GdkEventMotion*, gpointer) {
22724 	units_convert_ignore_enter = FALSE;
22725 	if(units_convert_hover_blocked) {
22726 		gtk_tree_view_set_hover_selection(GTK_TREE_VIEW(units_convert_view), TRUE);
22727 		units_convert_hover_blocked = false;
22728 	}
22729 	return FALSE;
22730 }
on_units_convert_window_key_press_event(GtkWidget * widget,GdkEventKey * event,gpointer)22731 gboolean on_units_convert_window_key_press_event(GtkWidget *widget, GdkEventKey *event, gpointer) {
22732 	if(!gtk_widget_get_mapped(units_convert_window)) return FALSE;
22733 	gtk_widget_event(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_convert_to_button")), (GdkEvent*) event);
22734 	return TRUE;
22735 }
on_units_convert_window_button_press_event(GtkWidget * widget,GdkEventButton * event,gpointer)22736 gboolean on_units_convert_window_button_press_event(GtkWidget *widget, GdkEventButton *event, gpointer) {
22737 	if(!gtk_widget_get_mapped(units_convert_window)) return FALSE;
22738 	gtk_widget_hide(units_convert_window);
22739 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(units_builder, "units_convert_to_button")), FALSE);
22740 	return TRUE;
22741 }
units_convert_resize_popup()22742 void units_convert_resize_popup() {
22743 
22744 	int matches = gtk_tree_model_iter_n_children(units_convert_filter, NULL);
22745 
22746 	gint x, y;
22747 	gint items, height = 0, items_y = 0, height_diff;
22748 	GdkDisplay *display;
22749 
22750 #if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 22
22751 	GdkMonitor *monitor;
22752 #endif
22753 	GdkRectangle area, rect;
22754 	GtkAllocation alloc;
22755 	GdkWindow *window;
22756 	GtkRequisition popup_req;
22757 	GtkRequisition tree_req;
22758 	GtkTreePath *path;
22759 	gboolean above;
22760 	GtkTreeViewColumn *column;
22761 
22762 	gtk_widget_get_allocation(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_convert_to_button")), &alloc);
22763 	window = gtk_widget_get_window(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_convert_to_button")));
22764 	gdk_window_get_origin(window, &x, &y);
22765 	x += alloc.x;
22766 	y += alloc.y;
22767 
22768 	gtk_widget_realize(units_convert_view);
22769 	while(gtk_events_pending()) gtk_main_iteration();
22770 	gtk_tree_view_columns_autosize(GTK_TREE_VIEW(units_convert_view));
22771 	column = gtk_tree_view_get_column(GTK_TREE_VIEW(units_convert_view), 0);
22772 
22773 	gtk_widget_get_preferred_size(units_convert_view, &tree_req, NULL);
22774 	gtk_tree_view_column_cell_get_size(column, NULL, NULL, NULL, NULL, &height_diff);
22775 
22776 	path = gtk_tree_path_new_from_indices(0, -1);
22777 	gtk_tree_view_get_cell_area(GTK_TREE_VIEW(units_convert_view), path, column, &rect);
22778 	gtk_tree_path_free(path);
22779 	items_y = rect.y;
22780 	height_diff -= rect.height;
22781 	if(height_diff < 2) height_diff = 2;
22782 
22783 	display = gtk_widget_get_display(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_convert_to_button")));
22784 #if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 22
22785 	monitor = gdk_display_get_monitor_at_window(display, window);
22786 	gdk_monitor_get_workarea(monitor, &area);
22787 #else
22788 	GdkScreen *screen = gdk_display_get_default_screen(display);
22789 	gdk_screen_get_monitor_workarea(screen, gdk_screen_get_monitor_at_window(screen, window), &area);
22790 #endif
22791 
22792 	items = matches;
22793 	if(items > 20) items = 20;
22794 	if(items > 0) {
22795 		path = gtk_tree_path_new_from_indices(items - 1, -1);
22796 		gtk_tree_view_get_cell_area(GTK_TREE_VIEW(units_convert_view), path, column, &rect);
22797 		gtk_tree_path_free(path);
22798 		height = rect.y + rect.height - items_y + height_diff;
22799 	}
22800 	while(items > 0 && ((y > area.height / 2 && area.y + y < height) || (y <= area.height / 2 && area.height - y < height))) {
22801 		items--;
22802 		path = gtk_tree_path_new_from_indices(items - 1, -1);
22803 		gtk_tree_view_get_cell_area(GTK_TREE_VIEW(units_convert_view), path, column, &rect);
22804 		gtk_tree_path_free(path);
22805 		height = rect.y + rect.height - items_y + height_diff;
22806 	}
22807 
22808 	gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW(units_convert_scrolled), height);
22809 	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(units_convert_scrolled), GTK_POLICY_NEVER, matches > 20 ? GTK_POLICY_ALWAYS : GTK_POLICY_NEVER);
22810 
22811 
22812 	if(items <= 0) gtk_widget_hide(units_convert_scrolled);
22813 	else gtk_widget_show(units_convert_scrolled);
22814 
22815 	gtk_widget_get_preferred_size(units_convert_window, &popup_req, NULL);
22816 
22817 	if(popup_req.width < rect.width + 2) popup_req.width = rect.width + 2;
22818 	if(popup_req.width < alloc.width) {
22819 		popup_req.width = alloc.width;
22820 		gtk_widget_set_size_request(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_convert_search")), popup_req.width, -1);
22821 	}
22822 
22823 	if(x < area.x) x = area.x;
22824 	else if(x + popup_req.width > area.x + area.width) x = area.x + area.width - popup_req.width;
22825 
22826 	if(y + alloc.height + popup_req.height <= area.y + area.height || y - area.y < (area.y + area.height) - (y + alloc.height)) {
22827 		y += alloc.height;
22828 		above = FALSE;
22829 	} else {
22830 		path = gtk_tree_path_new_from_indices(matches - 1, -1);
22831 		gtk_tree_view_get_cell_area(GTK_TREE_VIEW(units_convert_view), path, column, &rect);
22832 		gtk_tree_path_free(path);
22833 		height = rect.y + rect.height + height_diff;
22834 		path = gtk_tree_path_new_from_indices(matches - items, -1);
22835 		gtk_tree_view_get_cell_area(GTK_TREE_VIEW(units_convert_view), path, column, &rect);
22836 		gtk_tree_path_free(path);
22837 		height -= rect.y;
22838 		gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW(units_convert_scrolled), height);
22839 		y -= popup_req.height;
22840 		above = TRUE;
22841 	}
22842 
22843 	if(matches > 0) {
22844 		path = gtk_tree_path_new_from_indices(above ? matches - 1 : 0, -1);
22845 		gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(units_convert_view), path, NULL, FALSE, 0.0, 0.0);
22846 		gtk_tree_path_free(path);
22847 	}
22848 
22849 	gtk_window_move(GTK_WINDOW(units_convert_window), x, y);
22850 
22851 }
on_units_convert_to_button_toggled(GtkToggleButton * w,gpointer)22852 void on_units_convert_to_button_toggled(GtkToggleButton *w, gpointer) {
22853 	if(gtk_toggle_button_get_active(w)) {
22854 		units_convert_ignore_enter = TRUE;
22855 		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(units_builder, "units_convert_search")), "");
22856 		units_convert_resize_popup();
22857 		if(!gtk_widget_is_visible(units_convert_window)) {
22858 			gtk_tree_view_set_hover_selection(GTK_TREE_VIEW(completion_view), TRUE);
22859 			gtk_window_set_transient_for(GTK_WINDOW(units_convert_window), GTK_WINDOW(gtk_builder_get_object(units_builder, "units_dialog")));
22860 			gtk_window_group_add_window(gtk_window_get_group(GTK_WINDOW(gtk_builder_get_object(units_builder, "units_dialog"))), GTK_WINDOW(units_convert_window));
22861 			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"))));
22862 			gtk_widget_show(units_convert_window);
22863 		}
22864 		gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(units_convert_view)));
22865 		while(gtk_events_pending()) gtk_main_iteration();
22866 		gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(units_convert_view)));
22867 	} else {
22868 		gtk_widget_hide(units_convert_window);
22869 	}
22870 }
22871 
completion_resize_popup(int matches)22872 void completion_resize_popup(int matches) {
22873 
22874 	gint x, y;
22875 	gint items, height = 0, items_y = 0, height_diff;
22876 	GdkDisplay *display;
22877 
22878 #if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 22
22879 	GdkMonitor *monitor;
22880 #endif
22881 	GdkRectangle area, bufloc, rect;
22882 	GdkWindow *window;
22883 	GtkRequisition popup_req;
22884 	GtkRequisition tree_req;
22885 	GtkTreePath *path;
22886 	gboolean above;
22887 	GtkTreeViewColumn *column;
22888 
22889 	GtkTextMark *miter = gtk_text_buffer_get_insert(expressionbuffer);
22890 	GtkTextIter iter;
22891 	gtk_text_buffer_get_iter_at_mark(expressionbuffer, &iter, miter);
22892 	gtk_text_view_get_iter_location(GTK_TEXT_VIEW(expressiontext), &iter, &bufloc);
22893 	gtk_text_view_buffer_to_window_coords(GTK_TEXT_VIEW(expressiontext), GTK_TEXT_WINDOW_WIDGET, bufloc.x, bufloc.y, &bufloc.x, &bufloc.y);
22894 	window = gtk_text_view_get_window(GTK_TEXT_VIEW(expressiontext), GTK_TEXT_WINDOW_WIDGET);
22895 	gdk_window_get_origin(window, &x, &y);
22896 
22897 	x += bufloc.x;
22898 	y += bufloc.y;
22899 
22900 	gtk_widget_realize(completion_view);
22901 	while(gtk_events_pending()) gtk_main_iteration();
22902 	gtk_tree_view_columns_autosize(GTK_TREE_VIEW(completion_view));
22903 	column = gtk_tree_view_get_column(GTK_TREE_VIEW(completion_view), 0);
22904 
22905 	gtk_widget_get_preferred_size(completion_view, &tree_req, NULL);
22906 	gtk_tree_view_column_cell_get_size(column, NULL, NULL, NULL, NULL, &height_diff);
22907 
22908 	path = gtk_tree_path_new_from_indices(0, -1);
22909 	gtk_tree_view_get_cell_area(GTK_TREE_VIEW(completion_view), path, column, &rect);
22910 	gtk_tree_path_free(path);
22911 	items_y = rect.y;
22912 	height_diff -= rect.height;
22913 	if(height_diff < 2) height_diff = 2;
22914 
22915 	display = gtk_widget_get_display(GTK_WIDGET(expressiontext));
22916 #if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 22
22917 	monitor = gdk_display_get_monitor_at_window(display, window);
22918 	gdk_monitor_get_workarea(monitor, &area);
22919 #else
22920 	GdkScreen *screen = gdk_display_get_default_screen(display);
22921 	gdk_screen_get_monitor_workarea(screen, gdk_screen_get_monitor_at_window(screen, window), &area);
22922 #endif
22923 
22924 	items = matches;
22925 	if(items > 20) items = 20;
22926 	if(items > 0) {
22927 		path = gtk_tree_path_new_from_indices(items - 1, -1);
22928 		gtk_tree_view_get_cell_area(GTK_TREE_VIEW(completion_view), path, column, &rect);
22929 		gtk_tree_path_free(path);
22930 		height = rect.y + rect.height - items_y + height_diff;
22931 	}
22932 	while(items > 0 && ((y > area.height / 2 && area.y + y < height) || (y <= area.height / 2 && area.height - y < height))) {
22933 		items--;
22934 		path = gtk_tree_path_new_from_indices(items - 1, -1);
22935 		gtk_tree_view_get_cell_area(GTK_TREE_VIEW(completion_view), path, column, &rect);
22936 		gtk_tree_path_free(path);
22937 		height = rect.y + rect.height - items_y + height_diff;
22938 	}
22939 
22940 	gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW(completion_scrolled), height);
22941 
22942 	if(items <= 0) gtk_widget_hide(completion_scrolled);
22943 	else gtk_widget_show(completion_scrolled);
22944 
22945 	gtk_widget_get_preferred_size(completion_window, &popup_req, NULL);
22946 
22947 	if(popup_req.width < rect.width + 2) popup_req.width = rect.width + 2;
22948 
22949 	if(x < area.x) x = area.x;
22950 	else if(x + popup_req.width > area.x + area.width) x = area.x + area.width - popup_req.width;
22951 
22952 	if(y + bufloc.height + popup_req.height <= area.y + area.height || y - area.y < (area.y + area.height) - (y + bufloc.height)) {
22953 		y += bufloc.height;
22954 		above = FALSE;
22955 	} else {
22956 		path = gtk_tree_path_new_from_indices(matches - 1, -1);
22957 		gtk_tree_view_get_cell_area(GTK_TREE_VIEW(completion_view), path, column, &rect);
22958 		gtk_tree_path_free(path);
22959 		height = rect.y + rect.height + height_diff;
22960 		path = gtk_tree_path_new_from_indices(matches - items, -1);
22961 		gtk_tree_view_get_cell_area(GTK_TREE_VIEW(completion_view), path, column, &rect);
22962 		gtk_tree_path_free(path);
22963 		height -= rect.y;
22964 		gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW(completion_scrolled), height);
22965 		y -= popup_req.height;
22966 		above = TRUE;
22967 	}
22968 
22969 	if(matches > 0) {
22970 		path = gtk_tree_path_new_from_indices(above ? matches - 1 : 0, -1);
22971 		gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(completion_view), path, NULL, FALSE, 0.0, 0.0);
22972 		gtk_tree_path_free(path);
22973 	}
22974 
22975 	gtk_window_move(GTK_WINDOW(completion_window), x, y);
22976 
22977 }
22978 
contains_related_unit(const MathStructure & m,Unit * u)22979 bool contains_related_unit(const MathStructure &m, Unit *u) {
22980 	if(m.isUnit()) return u == m.unit() || u->containsRelativeTo(m.unit()) || m.unit()->containsRelativeTo(u);
22981 	for(size_t i = 0; i < m.size(); i++) {
22982 		if(contains_related_unit(m[i], u)) return true;
22983 	}
22984 	return false;
22985 }
22986 
do_completion()22987 void do_completion() {
22988 	if(!enable_completion) {gtk_widget_hide(completion_window); return;}
22989 	set_current_object();
22990 	string str;
22991 	int to_type = 0;
22992 	if(editing_to_expression && current_from_struct && current_from_struct->isDateTime()) to_type = 3;
22993 	if(current_object_start < 0) {
22994 		if(editing_to_expression && current_from_struct && current_from_unit) {
22995 			to_type = 4;
22996 		} else if(editing_to_expression && editing_to_expression1 && current_from_struct && current_from_struct->isNumber()) {
22997 			to_type = 2;
22998 		} else if(current_function && current_function->subtype() == SUBTYPE_DATA_SET && current_function_index > 1) {
22999 			Argument *arg = current_function->getArgumentDefinition(current_function_index);
23000 			if(!arg || arg->type() != ARGUMENT_TYPE_DATA_PROPERTY) {
23001 				gtk_widget_hide(completion_window);
23002 				return;
23003 			}
23004 		} else if(to_type < 2) {
23005 			gtk_widget_hide(completion_window);
23006 			return;
23007 		}
23008 	} else {
23009 		GtkTextIter object_start, object_end;
23010 		gtk_text_buffer_get_iter_at_offset(expressionbuffer, &object_start, current_object_start);
23011 		gtk_text_buffer_get_iter_at_offset(expressionbuffer, &object_end, current_object_end);
23012 		gchar *gstr2 = gtk_text_buffer_get_text(expressionbuffer, &object_start, &object_end, FALSE);
23013 		str = gstr2;
23014 		g_free(gstr2);
23015 		if(str.length() < (size_t) completion_min) {gtk_widget_hide(completion_window); return;}
23016 	}
23017 	GtkTreeIter iter;
23018 	int matches = 0;
23019 	int highest_match = 0;
23020 	if(editing_to_expression && editing_to_expression1 && current_from_struct) {
23021 		if((current_from_struct->isUnit() && current_from_struct->unit()->isCurrency()) || (current_from_struct->isMultiplication() && current_from_struct->size() == 2 && (*current_from_struct)[0].isNumber() && (*current_from_struct)[1].isUnit() && (*current_from_struct)[1].unit()->isCurrency())) {
23022 			if(to_type == 4) to_type = 5;
23023 			else to_type = 1;
23024 		}
23025 	}
23026 	bool show_separator1 = false, show_separator2 = false;
23027 	if(((str.length() > 0 && is_not_in(NUMBERS NOT_IN_NAMES "%", str[0])) || (str.empty() && current_function && current_function->subtype() == SUBTYPE_DATA_SET) || to_type >= 2) && gtk_tree_model_get_iter_first(GTK_TREE_MODEL(completion_store), &iter)) {
23028 		Argument *arg = NULL;
23029 		if(current_function && current_function->subtype() == SUBTYPE_DATA_SET) {
23030 			arg = current_function->getArgumentDefinition(current_function_index);
23031 			if(arg && (arg->type() == ARGUMENT_TYPE_DATA_OBJECT || arg->type() == ARGUMENT_TYPE_DATA_PROPERTY)) {
23032 				if(arg->type() == ARGUMENT_TYPE_DATA_OBJECT && (str.empty() || str.length() < (size_t) completion_min)) {gtk_widget_hide(completion_window); return;}
23033 				if(current_function_index == 1) {
23034 					for(size_t i = 1; i <= current_function->countNames(); i++) {
23035 						if(str.find(current_function->getName(i).name) != string::npos) {
23036 							arg = NULL;
23037 							break;
23038 						}
23039 					}
23040 				}
23041 			} else {
23042 				arg = NULL;
23043 			}
23044 			if(arg) {
23045 				DataSet *o = NULL;
23046 				if(arg->type() == ARGUMENT_TYPE_DATA_OBJECT) o = ((DataObjectArgument*) arg)->dataSet();
23047 				else if(arg->type() == ARGUMENT_TYPE_DATA_PROPERTY) o = ((DataPropertyArgument*) arg)->dataSet();
23048 				if(o) {
23049 					while(true) {
23050 						int p_type = 0;
23051 						gtk_tree_model_get(GTK_TREE_MODEL(completion_store), &iter, 8, &p_type, -1);
23052 						if(p_type > 2 && p_type < 100) {
23053 							if(!gtk_list_store_remove(completion_store, &iter)) break;
23054 						} else {
23055 							gtk_list_store_set(completion_store, &iter, 3, FALSE, 4, 0, 6, PANGO_WEIGHT_NORMAL, 7, 0, -1);
23056 							if(!gtk_tree_model_iter_next(GTK_TREE_MODEL(completion_store), &iter)) break;
23057 						}
23058 					}
23059 					DataPropertyIter it;
23060 					DataProperty *dp = o->getFirstProperty(&it);
23061 					vector<DataObject*> found_objects;
23062 					while(dp) {
23063 						if(arg->type() == ARGUMENT_TYPE_DATA_OBJECT) {
23064 							if(dp->isKey() && dp->propertyType() == PROPERTY_STRING) {
23065 								DataObjectIter it2;
23066 								DataObject *obj = o->getFirstObject(&it2);
23067 								while(obj) {
23068 									const string &name = obj->getProperty(dp);
23069 									int b_match = 0;
23070 									if(equalsIgnoreCase(str, name, 0, str.length(), 0)) b_match = name.length() == str.length() ? 1 : 2;
23071 									for(size_t i = 0; b_match && i < found_objects.size(); i++) {
23072 										if(found_objects[i] == obj) b_match = 0;
23073 									}
23074 									if(b_match) {
23075 										found_objects.push_back(obj);
23076 										DataPropertyIter it3;
23077 										DataProperty *dp2 = o->getFirstProperty(&it3);
23078 										string names = name;
23079 										string title;
23080 										while(dp2) {
23081 											if(title.empty() && dp2->hasName("name")) {
23082 												title = dp2->getDisplayString(obj->getProperty(dp2));
23083 											}
23084 											if(dp2 != dp && dp2->isKey()) {
23085 												names += " <i>";
23086 												names += dp2->getDisplayString(obj->getProperty(dp2));
23087 												names += "</i>";
23088 											}
23089 											dp2 = o->getNextProperty(&it3);
23090 										}
23091 										gtk_list_store_append(completion_store, &iter); 										gtk_list_store_set(completion_store, &iter, 0, names.c_str(), 1, title.empty() ? _("Data object") : title.c_str(), 2, NULL, 3, TRUE, 4, b_match, 6, b_match == 1 ? PANGO_WEIGHT_BOLD : (b_match > 3 ? PANGO_WEIGHT_LIGHT : PANGO_WEIGHT_NORMAL), 7, 0, 8, 4, -1);
23092 										matches++;
23093 									}
23094 									obj = o->getNextObject(&it2);
23095 								}
23096 							}
23097 						} else {
23098 							int b_match = 0;
23099 							size_t i_match = 0;
23100 							if(str.empty()) {
23101 								b_match = 2;
23102 								i_match = 1;
23103 							} else {
23104 								for(size_t i = 1; i <= dp->countNames(); i++) {
23105 									const string &name = dp->getName(i);
23106 									if((i_match == 0 || name.length() == str.length()) && equalsIgnoreCase(str, name, 0, str.length(), 0)) {
23107 										b_match = name.length() == str.length() ? 1 : 2;
23108 										i_match = i;
23109 										if(b_match == 1) break;
23110 									}
23111 								}
23112 							}
23113 							if(b_match) {
23114 								string names = dp->getName(i_match);
23115 								for(size_t i = 1; i <= dp->countNames(); i++) {
23116 									if(i != i_match) {
23117 										names += " <i>";
23118 										names += dp->getName(i);
23119 										names += "</i>";
23120 									}
23121 								}
23122 								i_match = 0;
23123 								gtk_list_store_append(completion_store, &iter);
23124 								gtk_list_store_set(completion_store, &iter, 0, names.c_str(), 1, dp->title().c_str(), 2, NULL, 3, TRUE, 4, b_match, 6, b_match == 1 ? PANGO_WEIGHT_BOLD : (b_match > 3 ? PANGO_WEIGHT_LIGHT : PANGO_WEIGHT_NORMAL), 7, 0, 8, 3, -1);
23125 								if(b_match > highest_match) highest_match = b_match;
23126 								matches++;
23127 							}
23128 						}
23129 						dp = o->getNextProperty(&it);
23130 					}
23131 				} else {
23132 					arg = NULL;
23133 				}
23134 			}
23135 		}
23136 		if(!arg) {
23137 			string str2, str3, str4;
23138 			Prefix *p2 = NULL, *p3 = NULL, *p4 = NULL;
23139 			if(str.length() > (size_t) completion_min) {
23140 				for(size_t pi = 1; ; pi++) {
23141 					Prefix *prefix = CALCULATOR->getPrefix(pi);
23142 					if(!prefix) break;
23143 					for(size_t name_i = 0; name_i < 3; name_i++) {
23144 						const string *pname;
23145 						if(name_i == 0) pname = &prefix->shortName(false);
23146 						else if(name_i == 1) pname = &prefix->longName(false);
23147 						else pname = &prefix->unicodeName(false);
23148 						if(!pname->empty() && pname->length() < str.length() - completion_min + 1) {
23149 							bool pmatch = true;
23150 							for(size_t i = 0; i < pname->length(); i++) {
23151 								if((*pname)[i] != str[i]) {
23152 									pmatch = false;
23153 									break;
23154 								}
23155 							}
23156 							if(pmatch) {
23157 								if(str2.empty()) {p2 = prefix; str2 = str.substr(pname->length());}
23158 								else if(str3.empty()) {p3 = prefix; str3 = str.substr(pname->length());}
23159 								else if(str4.empty()) {p4 = prefix; str4 = str.substr(pname->length());}
23160 							}
23161 						}
23162 					}
23163 				}
23164 			}
23165 			GtkTreeIter exact_prefix_match;
23166 			bool exact_match_found = false, exact_prefix_match_found = false;
23167 			do {
23168 				ExpressionItem *item = NULL;
23169 				Prefix *prefix = NULL;
23170 				void *p = NULL;
23171 				int p_type = 0;
23172 				gtk_tree_model_get(GTK_TREE_MODEL(completion_store), &iter, 2, &p, 8, &p_type, -1);
23173 				if(p_type == 1) item = (ExpressionItem*) p;
23174 				else if(p_type == 2) prefix = (Prefix*) p;
23175 				int b_match = false;
23176 				size_t i_match = 0;
23177 				if(item && to_type < 2) {
23178 					if((editing_to_expression || !evalops.parse_options.functions_enabled) && item->type() == TYPE_FUNCTION) {}
23179 					else if(item->type() == TYPE_VARIABLE && (!evalops.parse_options.variables_enabled || (editing_to_expression && (!((Variable*) item)->isKnown() || ((KnownVariable*) item)->unit().empty())))) {}
23180 					else if(!evalops.parse_options.units_enabled && item->type() == TYPE_UNIT) {}
23181 					else {
23182 						CompositeUnit *cu = NULL;
23183 						int exp = 0;
23184 						if(item->type() == TYPE_UNIT && ((Unit*) item)->subtype() == SUBTYPE_COMPOSITE_UNIT) {
23185 							cu = (CompositeUnit*) item;
23186 							item = cu->get(1, &exp, &prefix);
23187 							if(item && prefix) {
23188 								for(size_t name_i = 0; name_i < 3; name_i++) {
23189 									const string *pname;
23190 									if(name_i == 0) pname = &prefix->shortName(false);
23191 									else if(name_i == 1) pname = &prefix->longName(false);
23192 									else pname = &prefix->unicodeName(false);
23193 									if(!pname->empty() && pname->length() >= str.length() && (name_i != 1 || str.length() >= 2)) {
23194 										bool pmatch = true;
23195 										for(size_t i = 0; i < str.length(); i++) {
23196 											if((*pname)[i] != str[i]) {
23197 												pmatch = false;
23198 												break;
23199 											}
23200 										}
23201 										if(pmatch) {
23202 											b_match = 2;
23203 											item = NULL;
23204 											break;
23205 										}
23206 									}
23207 								}
23208 								if(item && exp == 1 && cu->countUnits() == 1 && ((Unit*) item)->useWithPrefixesByDefault()) {
23209 									if(!b_match && enable_completion2 && title_matches(cu, str, completion_min2)) {
23210 										b_match = 4;
23211 									}
23212 									item = NULL;
23213 								}
23214 							}
23215 						}
23216 						for(size_t name_i = 1; item && name_i <= item->countNames() && !b_match; name_i++) {
23217 							const ExpressionName *ename = &item->getName(name_i);
23218 							if(ename && (!cu || ename->abbreviation || str.length() >= 3 || str.length() == ename->name.length())) {
23219 								if(item->isHidden() && (item->type() != TYPE_UNIT || !((Unit*) item)->isCurrency()) && ename) {
23220 									b_match = (ename->name == str) ? 1 : 0;
23221 								} else {
23222 									for(size_t icmp = 0; icmp < 4; icmp++) {
23223 										if(icmp == 1 && (item->type() != TYPE_UNIT || str2.empty() || (cu && !prefix) || (!cu && !((Unit*) item)->useWithPrefixesByDefault()))) break;
23224 										if(cu && prefix) {
23225 											if(icmp == 0 || (icmp == 1 && prefix != p2) || (icmp == 2 && prefix != p3) || (icmp == 3 && prefix != p3)) continue;
23226 										}
23227 										const string *cmpstr;
23228 										if(icmp == 0) cmpstr = &str;
23229 										else if(icmp == 1) cmpstr = &str2;
23230 										else if(icmp == 2) cmpstr = &str3;
23231 										else cmpstr = &str4;
23232 										if(cmpstr->empty()) break;
23233 										if(cmpstr->length() <= ename->name.length()) {
23234 											b_match = 2;
23235 											for(size_t i = 0; i < cmpstr->length(); i++) {
23236 												if(ename->name[i] != (*cmpstr)[i]) {
23237 													b_match = false;
23238 													break;
23239 												}
23240 											}
23241 											if(b_match && (!cu || (exp == 1 && cu->countUnits() == 1)) && ((!ename->case_sensitive && equalsIgnoreCase(ename->name, *cmpstr)) || (ename->case_sensitive && ename->name == *cmpstr))) b_match = 1;
23242 											if(b_match) {
23243 												if(icmp > 0 && !cu) {
23244 													if(icmp == 1) prefix = p2;
23245 													else if(icmp == 2) prefix = p3;
23246 													else if(icmp == 3) prefix = p4;
23247 													i_match = str.length() - cmpstr->length();
23248 												} else if(b_match > 1 && !editing_to_expression && item->isHidden() && str.length() == 1) {
23249 													b_match = 4;
23250 													i_match = name_i;
23251 												}
23252 												break;
23253 											}
23254 										}
23255 									}
23256 								}
23257 							}
23258 						}
23259 						if(item && ((!cu && b_match >= 2) || (exp == 1 && cu->countUnits() == 1 && b_match == 2)) && item->countNames() > 1) {
23260 							for(size_t icmp = 0; icmp < 4 && b_match > 1; icmp++) {
23261 								if(icmp == 1 && (item->type() != TYPE_UNIT || str2.empty() || (cu && !prefix) || (!cu && !((Unit*) item)->useWithPrefixesByDefault()))) break;
23262 								if(cu && prefix) {
23263 									if(icmp == 0 || (icmp == 1 && prefix != p2) || (icmp == 2 && prefix != p3) || (icmp == 3 && prefix != p3)) continue;
23264 								}
23265 								const string *cmpstr;
23266 								if(icmp == 0) cmpstr = &str;
23267 								else if(icmp == 1) cmpstr = &str2;
23268 								else if(icmp == 2) cmpstr = &str3;
23269 								else cmpstr = &str4;
23270 								if(cmpstr->empty()) break;
23271 								for(size_t name_i = 1; name_i <= item->countNames(); name_i++) {
23272 									if(item->getName(name_i).name == *cmpstr) {
23273 										if(!cu) {
23274 											if(icmp == 1) prefix = p2;
23275 											else if(icmp == 2) prefix = p3;
23276 											else if(icmp == 3) prefix = p4;
23277 											else prefix = NULL;
23278 										}
23279 										b_match = 1; break;
23280 									}
23281 								}
23282 							}
23283 						}
23284 						if(item && !b_match && enable_completion2 && (!item->isHidden() || (item->type() == TYPE_UNIT && str.length() > 1 && ((Unit*) item)->isCurrency()))) {
23285 							int i_cinm = name_matches2(cu ? cu : item, str, to_type == 1 ? 1 : completion_min2, &i_match);
23286 							if(i_cinm == 1) {b_match = 1; i_match = 0;}
23287 							else if(i_cinm == 2) b_match = 4;
23288 							else if(title_matches(cu ? cu : item, str, to_type == 1 ? 1 : completion_min2)) b_match = 4;
23289 							else if(!cu && item->type() == TYPE_UNIT && ((Unit*) item)->isCurrency() && country_matches((Unit*) item, str, to_type == 1 ? 1 : completion_min2)) b_match = 5;
23290 						}
23291 						if(cu) prefix = NULL;
23292 					}
23293 					if(b_match > 1 && (
23294 					(to_type == 1 && (!item || item->type() != TYPE_UNIT)) ||
23295 					((b_match > 2 || str.length() < 3) && editing_to_expression && current_from_struct && !current_from_struct->isAborted() && item && item->type() == TYPE_UNIT && !contains_related_unit(*current_from_struct, (Unit*) item) && (!current_from_struct->isNumber() || !current_from_struct->number().isReal() || (!prefix && ((Unit*) item)->isSIUnit() && (Unit*) item != CALCULATOR->getRadUnit())))
23296 					)) {
23297 						b_match = 0;
23298 						i_match = 0;
23299 					}
23300 					if(b_match) {
23301 						gchar *gstr;
23302 						gtk_tree_model_get(GTK_TREE_MODEL(completion_store), &iter, 0, &gstr, -1);
23303 						if(gstr && strlen(gstr) > 0) {
23304 							string nstr;
23305 							if(gstr[0] == '<') {
23306 								nstr = gstr;
23307 								size_t i = nstr.find("-) </small>");
23308 								if(i != string::npos && i > 2) {
23309 									if(prefix && prefix->longName() == nstr.substr(8, i - 8)) {
23310 										prefix = NULL;
23311 									} else {
23312 										nstr = nstr.substr(i + 11);
23313 										if(!prefix) gtk_list_store_set(completion_store, &iter, 0, nstr.c_str(), -1);
23314 									}
23315 								}
23316 							}
23317 							if(prefix) {
23318 								if(nstr.empty()) nstr = gstr;
23319 								nstr.insert(0, "-) </small>");
23320 								nstr.insert(0, prefix->longName());
23321 								nstr.insert(0, "<small>(");
23322 								gtk_list_store_set(completion_store, &iter, 0, nstr.c_str(), -1);
23323 							}
23324 						}
23325 						if(gstr) g_free(gstr);
23326 						if(b_match == 1 && item->type() != TYPE_FUNCTION) {
23327 							if(prefix) {
23328 								exact_prefix_match = iter;
23329 								exact_prefix_match_found = true;
23330 							} else {
23331 								exact_match_found = true;
23332 							}
23333 						}
23334 						if(b_match > highest_match) highest_match = b_match;
23335 					}
23336 				} else if(item && to_type == 4) {
23337 					if(item->type() == TYPE_UNIT && item->category() == current_from_unit->category()) {
23338 						gchar *gstr;
23339 						gtk_tree_model_get(GTK_TREE_MODEL(completion_store), &iter, 0, &gstr, -1);
23340 						if(gstr && strlen(gstr) > 0 && gstr[0] == '<') {
23341 							string nstr = gstr;
23342 							size_t i = nstr.find("-) </small>");
23343 							if(i != string::npos && i > 2) {
23344 								nstr = nstr.substr(i + 11);
23345 								gtk_list_store_set(completion_store, &iter, 0, nstr.c_str(), -1);
23346 							}
23347 						}
23348 						if(gstr) g_free(gstr);
23349 						b_match = 2;
23350 					}
23351 				} else if(item && to_type == 5) {
23352 					if(item->type() == TYPE_UNIT && ((Unit*) item)->isCurrency() && (!item->isHidden() || item == CALCULATOR->getLocalCurrency())) b_match = 2;
23353 				} else if(prefix && to_type < 2) {
23354 					for(size_t name_i = 0; name_i < 3 && !b_match; name_i++) {
23355 						const string *pname;
23356 						if(name_i == 0) pname = &prefix->shortName(false);
23357 						else if(name_i == 1) pname = &prefix->unicodeName(false);
23358 						else pname = &prefix->longName(false);
23359 						if(!pname->empty() && str.length() <= pname->length()) {
23360 							b_match = 2;
23361 							for(size_t i = 0; i < str.length(); i++) {
23362 								if(str[i] != (*pname)[i]) {
23363 									b_match = false;
23364 									break;
23365 								}
23366 							}
23367 							if(b_match && *pname == str) b_match = 1;
23368 						}
23369 					}
23370 					if(to_type == 1 && b_match > 1) b_match = 0;
23371 					if(b_match > highest_match) highest_match = b_match;
23372 					else if(b_match == 1 && highest_match < 2) highest_match = 2;
23373 					prefix = NULL;
23374 				} else if(p_type >= 100 && editing_to_expression && editing_to_expression1) {
23375 					gchar *gstr;
23376 					gtk_tree_model_get(GTK_TREE_MODEL(completion_store), &iter, 0, &gstr, -1);
23377 					if(to_type >= 2 && str.empty()) b_match = 2;
23378 					else b_match = completion_names_match(gstr, str, completion_min, &i_match);
23379 					if(b_match > 1) {
23380 						if(current_from_struct && str.length() < 3) {
23381 							if(p_type >= 100 && p_type < 200) {
23382 								if(to_type == 5 || current_from_struct->containsType(STRUCT_UNIT) <= 0) b_match = 0;
23383 							} else if(p_type >= 200 && p_type < 300 && ((p_type != 292 && p_type != 200) || to_type == 1 || to_type >= 3)) {
23384 								if(!current_from_struct->isNumber()) b_match = 0;
23385 								else if(str.empty() && p_type >= 202 && p_type < 290 && !current_from_struct->isInteger()) b_match = 0;
23386 							} else if(p_type >= 300 && p_type < 400) {
23387 								if(p_type == 300) {
23388 									if(!contains_rational_number(*current_from_struct)) b_match = 0;
23389 								} else {
23390 									if(!current_from_struct->isNumber()) b_match = 0;
23391 								}
23392 							} else if(p_type >= 400 && p_type < 500) {
23393 								if(!contains_imaginary_number(*current_from_struct)) b_match = 0;
23394 							} else if(p_type >= 500 && p_type < 600) {
23395 								if(!current_from_struct->isDateTime()) b_match = 0;
23396 							} else if(p_type == 600) {
23397 								if(!current_from_struct->isInteger() && current_from_struct->containsType(STRUCT_ADDITION) <= 0) b_match = 0;
23398 							} else if(p_type == 601) {
23399 								if(current_from_struct->containsType(STRUCT_ADDITION) <= 0) b_match = 0;
23400 							}
23401 						}
23402 						if(b_match > highest_match) highest_match = b_match;
23403 					}
23404 					g_free(gstr);
23405 				}
23406 				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);
23407 				if(b_match) {
23408 					matches++;
23409 					if(b_match > 3) show_separator2 = true;
23410 					else if(b_match < 3) show_separator1 = true;
23411 				}
23412 			} while(gtk_tree_model_iter_next(GTK_TREE_MODEL(completion_store), &iter));
23413 			if(exact_match_found && exact_prefix_match_found) {
23414 				gtk_list_store_set(completion_store, &exact_prefix_match, 3, FALSE, 4, 0, 6, PANGO_WEIGHT_NORMAL, 7, 0, -1);
23415 				matches--;
23416 			}
23417 		}
23418 	}
23419 	if(matches > 0 && (highest_match != 1 || completion_delay <= 0 || !display_expression_status)) {
23420 		gtk_list_store_set(completion_store, &completion_separator_iter, 3, show_separator1 && show_separator2, 4, 3, -1);
23421 		if(show_separator1 && show_separator2) matches++;
23422 		completion_ignore_enter = TRUE;
23423 		completion_resize_popup(matches);
23424 		if(!gtk_widget_is_visible(completion_window)) {
23425 			gtk_window_set_transient_for(GTK_WINDOW(completion_window), GTK_WINDOW(mainwindow));
23426 			gtk_window_group_add_window(gtk_window_get_group(GTK_WINDOW(mainwindow)), GTK_WINDOW(completion_window));
23427 			gtk_window_set_screen(GTK_WINDOW(completion_window), gtk_widget_get_screen(expressiontext));
23428 			gtk_widget_show(completion_window);
23429 		}
23430 		gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(completion_view)));
23431 		while(gtk_events_pending()) gtk_main_iteration();
23432 		gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(completion_view)));
23433 	} else {
23434 		gtk_widget_hide(completion_window);
23435 	}
23436 }
23437 
do_completion_timeout(gpointer)23438 gboolean do_completion_timeout(gpointer) {
23439 	if(!completion_blocked) do_completion();
23440 	completion_timeout_id = 0;
23441 	return FALSE;
23442 }
on_expressionbuffer_changed(GtkTextBuffer * o,gpointer)23443 void on_expressionbuffer_changed(GtkTextBuffer *o, gpointer) {
23444 	if(completion_timeout_id != 0) {
23445 		g_source_remove(completion_timeout_id);
23446 		completion_timeout_id = 0;
23447 	}
23448 	if(!block_add_to_undo) add_expression_to_undo();
23449 	if(!expression_has_changed || (rpn_mode && gtk_text_buffer_get_char_count(o) == 1)) {
23450 		expression_has_changed = true;
23451 		update_expression_icons();
23452 	}
23453 	expression_has_changed2 = true;
23454 	current_object_has_changed = true;
23455 	expression_has_changed_pos = true;
23456 	highlight_parentheses();
23457 	display_parse_status();
23458 	if(!completion_blocked) {
23459 		if(completion_delay <= 0 || gtk_widget_is_visible(completion_window)) {
23460 			completion_timeout_id = gdk_threads_add_idle(do_completion_timeout, NULL);
23461 		} else {
23462 			completion_timeout_id = g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE, completion_delay, do_completion_timeout, NULL, NULL);
23463 		}
23464 	}
23465 	showhide_expression_button();
23466 	if(o && !rpn_mode && auto_calculate) do_auto_calc();
23467 	if(result_text.empty() && !autocalc_history_timeout_id && (!chain_mode || auto_calculate)) return;
23468 	if(!dont_change_index) expression_history_index = -1;
23469 	if((!o || !auto_calculate) && !rpn_mode) clearresult();
23470 }
23471 
on_convert_entry_unit_changed(GtkEditable * w,gpointer)23472 void on_convert_entry_unit_changed(GtkEditable *w, gpointer) {
23473 	bool b = gtk_entry_get_text_length(GTK_ENTRY(w)) > 0;
23474 	gtk_entry_set_icon_from_icon_name(GTK_ENTRY(w), GTK_ENTRY_ICON_SECONDARY, b ? "edit-clear-symbolic" : NULL);
23475 	gtk_entry_set_icon_tooltip_text(GTK_ENTRY(w), GTK_ENTRY_ICON_SECONDARY, b ? _("Clear expression") : NULL);
23476 	if(!keep_unit_selection) gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitSelector)));
23477 }
entry_insert_text(GtkWidget * w,const gchar * text)23478 void entry_insert_text(GtkWidget *w, const gchar *text) {
23479 	gtk_editable_delete_selection(GTK_EDITABLE(w));
23480 	gint pos = gtk_editable_get_position(GTK_EDITABLE(w));
23481 	gtk_editable_insert_text(GTK_EDITABLE(w), text, -1, &pos);
23482 	gtk_editable_set_position(GTK_EDITABLE(w), pos);
23483 	gtk_widget_grab_focus(w);
23484 	gtk_editable_select_region(GTK_EDITABLE(w), pos, pos);
23485 }
23486 
23487 bool block_input = false;
key_press_get_symbol(GdkEventKey * event,bool do_caret_as_xor=true,bool unit_expression=false)23488 const gchar *key_press_get_symbol(GdkEventKey *event, bool do_caret_as_xor = true, bool unit_expression = false) {
23489 	if(block_input && (event->keyval == GDK_KEY_q || event->keyval == GDK_KEY_Q) && !(event->state & GDK_CONTROL_MASK)) {block_input = false; return "";}
23490 #if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 18
23491 	guint state = event->state & gdk_keymap_get_modifier_mask(gdk_keymap_get_for_display(gtk_widget_get_display(mainwindow)), GDK_MODIFIER_INTENT_DEFAULT_MOD_MASK);
23492 	state = state & ~GDK_SHIFT_MASK;
23493 #else
23494 	guint state = event->state & (GDK_CONTROL_MASK | GDK_MOD1_MASK | GDK_SUPER_MASK | GDK_HYPER_MASK | GDK_META_MASK);
23495 #endif
23496 	if(state == GDK_CONTROL_MASK) {
23497 		switch(event->keyval) {
23498 			case GDK_KEY_asciicircum: {}
23499 			case GDK_KEY_dead_circumflex: {
23500 				bool input_xor = !do_caret_as_xor || !caret_as_xor;
23501 				return input_xor ? " xor " : "^";
23502 			}
23503 			case GDK_KEY_KP_Multiply: {}
23504 			case GDK_KEY_asterisk: {
23505 				return "^";
23506 			}
23507 		}
23508 	}
23509 	if(state != 0) return NULL;
23510 	switch(event->keyval) {
23511 		case GDK_KEY_dead_circumflex: {
23512 #ifdef _WIN32
23513 			// fix dead key
23514 			block_input = true;
23515 			INPUT ip; ip.type = INPUT_KEYBOARD; ip.ki.wScan = 0; ip.ki.time = 0; ip.ki.dwExtraInfo = 0;
23516 			ip.ki.wVk = 0x51; ip.ki.dwFlags = 0; SendInput(1, &ip, sizeof(INPUT));
23517 			ip.ki.dwFlags = KEYEVENTF_KEYUP; SendInput(1, &ip, sizeof(INPUT));
23518 #endif
23519 		}
23520 		case GDK_KEY_asciicircum: {
23521 			bool input_xor = !do_caret_as_xor && caret_as_xor;
23522 			return input_xor ? " xor " : "^";
23523 		}
23524 		case GDK_KEY_KP_Multiply: {}
23525 		case GDK_KEY_asterisk: {
23526 			if(printops.use_unicode_signs && printops.multiplication_sign == MULTIPLICATION_SIGN_DOT) return sdot_o.c_str();
23527 			else if(printops.use_unicode_signs && (printops.multiplication_sign == MULTIPLICATION_SIGN_ALTDOT || (unit_expression && printops.multiplication_sign == MULTIPLICATION_SIGN_X))) return saltdot_o.c_str();
23528 			else if(printops.use_unicode_signs && printops.multiplication_sign == MULTIPLICATION_SIGN_X) return stimes_o.c_str();
23529 			return "*";
23530 		}
23531 		case GDK_KEY_KP_Divide: {}
23532 		case GDK_KEY_slash: {
23533 			if(!printops.use_unicode_signs) return "/";
23534 			if(printops.division_sign == DIVISION_SIGN_DIVISION) return sdiv_o.c_str();
23535 			return sslash_o.c_str();
23536 		}
23537 		case GDK_KEY_KP_Subtract: {}
23538 		case GDK_KEY_minus: {
23539 			if(!printops.use_unicode_signs) return "-";
23540 			return sminus_o.c_str();
23541 		}
23542 		case GDK_KEY_KP_Add: {}
23543 		case GDK_KEY_plus: {
23544 			return "+";
23545 		}
23546 		case GDK_KEY_braceleft: {}
23547 		case GDK_KEY_braceright: {
23548 			return "";
23549 		}
23550 	}
23551 	return NULL;
23552 }
on_math_entry_key_press_event(GtkWidget * o,GdkEventKey * event,gpointer)23553 gboolean on_math_entry_key_press_event(GtkWidget *o, GdkEventKey *event, gpointer) {
23554 	const gchar *key = key_press_get_symbol(event);
23555 	if(!key) return FALSE;
23556 	if(strlen(key) > 0) entry_insert_text(o, key);
23557 	return TRUE;
23558 }
on_unit_entry_key_press_event(GtkWidget * o,GdkEventKey * event,gpointer)23559 gboolean on_unit_entry_key_press_event(GtkWidget *o, GdkEventKey *event, gpointer) {
23560 	const gchar *key = key_press_get_symbol(event, false, true);
23561 	if(!key) return FALSE;
23562 	if(strlen(key) > 0) entry_insert_text(o, key);
23563 	return TRUE;
23564 }
23565 
reenable_tooltip(GtkWidget * w,gpointer)23566 gboolean reenable_tooltip(GtkWidget *w, gpointer) {
23567 	gtk_widget_set_has_tooltip(w, TRUE);
23568 	g_signal_handlers_disconnect_matched((gpointer) w, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) reenable_tooltip, NULL);
23569 	return FALSE;
23570 }
23571 
memory_recall()23572 void memory_recall() {
23573 	insert_var(v_memory);
23574 }
memory_store()23575 void memory_store() {
23576 	if(expression_has_changed && !rpn_mode && !auto_calculate) execute_expression(true);
23577 	if(!mstruct) return;
23578 	v_memory->set(*mstruct);
23579 	if(parsed_mstruct && parsed_mstruct->contains(v_memory, true)) expression_calculation_updated();
23580 }
memory_add()23581 void memory_add() {
23582 	if(expression_has_changed && !rpn_mode && !auto_calculate) execute_expression(true);
23583 	if(!mstruct) return;
23584 	MathStructure m = v_memory->get();
23585 	m.calculateAdd(*mstruct, evalops);
23586 	v_memory->set(m);
23587 	if(parsed_mstruct && parsed_mstruct->contains(v_memory, true)) expression_calculation_updated();
23588 }
memory_subtract()23589 void memory_subtract() {
23590 	if(expression_has_changed && !rpn_mode && !auto_calculate) execute_expression(true);
23591 	if(!mstruct) return;
23592 	MathStructure m = v_memory->get();
23593 	m.calculateSubtract(*mstruct, evalops);
23594 	v_memory->set(m);
23595 	if(parsed_mstruct && parsed_mstruct->contains(v_memory, true)) expression_calculation_updated();
23596 }
memory_clear()23597 void memory_clear() {
23598 	v_memory->set(m_zero);
23599 	if(parsed_mstruct && parsed_mstruct->contains(v_memory, true)) expression_calculation_updated();
23600 }
23601 
hide_tooltip(GtkWidget * w)23602 void hide_tooltip(GtkWidget *w) {
23603 	if(!gtk_widget_get_has_tooltip(w)) return;
23604 	gtk_widget_set_has_tooltip(w, FALSE);
23605 	g_signal_connect(w, "leave-notify-event", G_CALLBACK(reenable_tooltip), NULL);
23606 }
23607 
23608 #define DO_CUSTOM_BUTTONS(i) \
23609 	if(b2 && custom_buttons[i].type[2] != -1) {\
23610 		if(custom_buttons[i].type[2] < 0) return FALSE;\
23611 		do_shortcut(custom_buttons[i].type[2], custom_buttons[i].value[2]);\
23612 		return TRUE;\
23613 	} else if(!b2 && custom_buttons[i].type[1] != -1) {\
23614 		if(custom_buttons[i].type[1] < 0) return FALSE;\
23615 		do_shortcut(custom_buttons[i].type[1], custom_buttons[i].value[1]);\
23616 		return TRUE;\
23617 	}
23618 
on_keypad_button_alt(GtkWidget * w,bool b2)23619 gboolean on_keypad_button_alt(GtkWidget *w, bool b2) {
23620 	hide_tooltip(w);
23621 	if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_ac"))) {
23622 		DO_CUSTOM_BUTTONS(25)
23623 		memory_clear();
23624 		show_notification("MC");
23625 		return TRUE;
23626 	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_equals"))) {
23627 		DO_CUSTOM_BUTTONS(28)
23628 		if(b2) {memory_store(); show_notification("MS");}
23629 		else memory_recall();
23630 		return TRUE;
23631 	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_divide"))) {
23632 		DO_CUSTOM_BUTTONS(21)
23633 		insertButtonFunction(CALCULATOR->getActiveFunction("inv"));
23634 		return TRUE;
23635 	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_exp"))) {
23636 		DO_CUSTOM_BUTTONS(19)
23637 		if(b2) {
23638 			insertButtonFunction(CALCULATOR->getActiveFunction("exp10"));
23639 		} else {
23640 			insertButtonFunction(CALCULATOR->f_exp);
23641 		}
23642 		return TRUE;
23643 	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_comma"))) {
23644 		DO_CUSTOM_BUTTONS(4)
23645 		if(b2) insert_text("\n");
23646 		else insert_text(" ");
23647 		return TRUE;
23648 	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_dot"))) {
23649 		DO_CUSTOM_BUTTONS(18)
23650 		if(b2) insert_text("\n");
23651 		else insert_text(" ");
23652 		return TRUE;
23653 	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_brace_open"))) {
23654 		DO_CUSTOM_BUTTONS(6)
23655 		insert_text("[");
23656 		return TRUE;
23657 	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_brace_close"))) {
23658 		DO_CUSTOM_BUTTONS(7)
23659 		insert_text("]");
23660 		return TRUE;
23661 	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_brace_wrap"))) {
23662 		DO_CUSTOM_BUTTONS(5)
23663 		if(gtk_text_buffer_get_has_selection(expressionbuffer)) {
23664 			GtkTextIter istart, iend;
23665 			gtk_text_buffer_get_selection_bounds(expressionbuffer, &istart, &iend);
23666 			gchar *gstr = gtk_text_buffer_get_text(expressionbuffer, &istart, &iend, FALSE);
23667 			string str = "[";
23668 			str += gstr;
23669 			str += "]";
23670 			insert_text(str.c_str());
23671 			g_free(gstr);
23672 		} else {
23673 			insert_text("[]");
23674 			GtkTextIter iter;
23675 			gtk_text_buffer_get_iter_at_mark(expressionbuffer, &iter, gtk_text_buffer_get_insert(expressionbuffer));
23676 			gtk_text_iter_backward_char(&iter);
23677 			gtk_text_buffer_place_cursor(expressionbuffer, &iter);
23678 		}
23679 		return TRUE;
23680 	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_add"))) {
23681 		DO_CUSTOM_BUTTONS(23)
23682 		if(b2) insert_bitwise_and();
23683 		else {memory_add(); show_notification("M+");}
23684 		return TRUE;
23685 	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_sub"))) {
23686 		DO_CUSTOM_BUTTONS(24)
23687 		if(b2) insert_bitwise_or();
23688 		else insertButtonFunction(CALCULATOR->getActiveFunction("neg"));
23689 		return TRUE;
23690 	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_times"))) {
23691 		DO_CUSTOM_BUTTONS(22)
23692 		insert_bitwise_xor();
23693 		return TRUE;
23694 	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_xy"))) {
23695 		DO_CUSTOM_BUTTONS(20)
23696 		insertButtonFunction(CALCULATOR->f_sqrt);
23697 		return TRUE;
23698 	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_del"))) {
23699 		DO_CUSTOM_BUTTONS(26)
23700 		if(b2) {
23701 			memory_subtract();
23702 			show_notification("M−");
23703 		} else {
23704 			if(gtk_text_buffer_get_has_selection(expressionbuffer)) {
23705 				overwrite_expression_selection(NULL);
23706 			} else {
23707 				block_completion();
23708 				GtkTextMark *mpos = gtk_text_buffer_get_insert(expressionbuffer);
23709 				GtkTextIter ipos, iend;
23710 				gtk_text_buffer_get_iter_at_mark(expressionbuffer, &ipos, mpos);
23711 				iend = ipos;
23712 				if(gtk_text_iter_backward_char(&ipos)) {
23713 					gtk_text_buffer_delete(expressionbuffer, &ipos, &iend);
23714 				}
23715 				focus_keeping_selection();
23716 				unblock_completion();
23717 			}
23718 		}
23719 		return TRUE;
23720 	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_ans"))) {
23721 		DO_CUSTOM_BUTTONS(27)
23722 		if(history_answer.size() > 0) {
23723 			string str = f_answer->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext).name;
23724 			Number nr(history_answer.size(), 1);
23725 			str += '(';
23726 			str += print_with_evalops(nr);
23727 			str += ')';
23728 			insert_text(str.c_str());
23729 		}
23730 		return TRUE;
23731 	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_move"))) {
23732 		DO_CUSTOM_BUTTONS(0)
23733 	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_move2"))) {
23734 		DO_CUSTOM_BUTTONS(1)
23735 	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_percent"))) {
23736 		DO_CUSTOM_BUTTONS(2)
23737 		insert_var(CALCULATOR->v_permille);
23738 		return TRUE;
23739 	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_plusminus"))) {
23740 		DO_CUSTOM_BUTTONS(3)
23741 		if(b2) insertButtonFunction(CALCULATOR->f_interval);
23742 		else insertButtonFunction(CALCULATOR->f_uncertainty);
23743 		return TRUE;
23744 	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_bin"))) {
23745 		base_button_alternative(2);
23746 		return TRUE;
23747 	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_oct"))) {
23748 		base_button_alternative(8);
23749 		return TRUE;
23750 	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_dec"))) {
23751 		base_button_alternative(10);
23752 		return TRUE;
23753 	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_hex"))) {
23754 		base_button_alternative(16);
23755 		return TRUE;
23756 	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_mod2"))) {
23757 		if(expression_is_empty() || rpn_mode || evalops.parse_options.parsing_mode == PARSING_MODE_RPN || wrap_expression_selection() < 0) {
23758 			insertButtonFunction(CALCULATOR->f_rem);
23759 		} else {
23760 			insert_text(" rem ");
23761 		}
23762 		return TRUE;
23763 	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_sqrt2"))) {
23764 		insertButtonFunction(CALCULATOR->f_cbrt);
23765 		return TRUE;
23766 	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_expf"))) {
23767 		insertButtonFunction(CALCULATOR->getActiveFunction("exp2"));
23768 		return TRUE;
23769 	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_log2"))) {
23770 		insertButtonFunction(CALCULATOR->getActiveFunction("log10"));
23771 		return TRUE;
23772 	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_code"))) {
23773 		insertButtonFunction(CALCULATOR->f_char);
23774 		return TRUE;
23775 	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_stamptodate"))) {
23776 		insertButtonFunction(CALCULATOR->f_timestamp);
23777 		return TRUE;
23778 	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_and"))) {
23779 		if(rpn_mode) {calculateRPN(OPERATION_LOGICAL_AND); return TRUE;}
23780 		if(evalops.parse_options.parsing_mode != PARSING_MODE_RPN) wrap_expression_selection();
23781 		insert_text("&&");
23782 		return TRUE;
23783 	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_or"))) {
23784 		if(rpn_mode) {calculateRPN(OPERATION_LOGICAL_OR); return TRUE;}
23785 		if(evalops.parse_options.parsing_mode != PARSING_MODE_RPN) wrap_expression_selection();
23786 		insert_text("||");
23787 		return TRUE;
23788 	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_not"))) {
23789 		if(rpn_mode) {
23790 			if(expression_has_changed) {
23791 				if(get_expression_text().find_first_not_of(SPACES) != string::npos) {
23792 					execute_expression(true);
23793 				}
23794 			}
23795 			execute_expression(true, false, OPERATION_ADD, NULL, false, 0, "!");
23796 			return TRUE;
23797 		}
23798 		if(evalops.parse_options.parsing_mode != PARSING_MODE_RPN && wrap_expression_selection("!") > 0) return TRUE;
23799 		insert_text("!");
23800 		return TRUE;
23801 	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_c1"))) {
23802 		DO_CUSTOM_BUTTONS(29)
23803 	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_c2"))) {
23804 		DO_CUSTOM_BUTTONS(30)
23805 	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_c3"))) {
23806 		DO_CUSTOM_BUTTONS(31)
23807 	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_c4"))) {
23808 		DO_CUSTOM_BUTTONS(32)
23809 	} else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_c5"))) {
23810 		DO_CUSTOM_BUTTONS(33)
23811 	} else {
23812 		int i = 0;
23813 		if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_zero"))) i = 0;
23814 		else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_one"))) i = 1;
23815 		else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_two"))) i = 2;
23816 		else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_three"))) i = 3;
23817 		else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_four"))) i = 4;
23818 		else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_five"))) i = 5;
23819 		else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_six"))) i = 6;
23820 		else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_seven"))) i = 7;
23821 		else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_eight"))) i = 8;
23822 		else if(w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_nine"))) i = 9;
23823 		else return FALSE;
23824 		DO_CUSTOM_BUTTONS(i + 8)
23825 		if(b2 && i == 1) {
23826 			insertButtonFunction(CALCULATOR->getActiveFunction("inv"));
23827 			return TRUE;
23828 		} else if(b2 && i == 0) {
23829 			insert_text(SIGN_DEGREE);
23830 			return TRUE;
23831 		}
23832 		if(!b2) wrap_expression_selection();
23833 		if(printops.use_unicode_signs && (evalops.parse_options.base > i || i == 0)) {
23834 			if(b2) {
23835 				if(i == 2 && can_display_unicode_string_function("½", (void*) expressiontext)) {insert_text("½"); return TRUE;}
23836 				if(i == 3 && can_display_unicode_string_function("⅓", (void*) expressiontext)) {insert_text("⅓"); return TRUE;}
23837 				if(i == 4 && can_display_unicode_string_function("¼", (void*) expressiontext)) {insert_text("¼"); return TRUE;}
23838 				if(i == 5 && can_display_unicode_string_function("⅕", (void*) expressiontext)) {insert_text("⅕"); return TRUE;}
23839 				if(i == 6 && can_display_unicode_string_function("⅙", (void*) expressiontext)) {insert_text("⅙"); return TRUE;}
23840 				if(i == 7 && can_display_unicode_string_function("⅐", (void*) expressiontext)) {insert_text("⅐"); return TRUE;}
23841 				if(i == 8 && can_display_unicode_string_function("⅛", (void*) expressiontext)) {insert_text("⅛"); return TRUE;}
23842 				if(i == 9 && can_display_unicode_string_function("⅑", (void*) expressiontext)) {insert_text("⅑"); return TRUE;}
23843 			} else {
23844 				if(i == 0 && can_display_unicode_string_function(SIGN_POWER_0, (void*) expressiontext)) {insert_text(SIGN_POWER_0); return TRUE;}
23845 				if(i == 1 && can_display_unicode_string_function(SIGN_POWER_1, (void*) expressiontext)) {insert_text(SIGN_POWER_1); return TRUE;}
23846 				if(i == 2 && can_display_unicode_string_function(SIGN_POWER_2, (void*) expressiontext)) {insert_text(SIGN_POWER_2); return TRUE;}
23847 				if(i == 3 && can_display_unicode_string_function(SIGN_POWER_3, (void*) expressiontext)) {insert_text(SIGN_POWER_3); return TRUE;}
23848 				if(i == 4 && can_display_unicode_string_function(SIGN_POWER_4, (void*) expressiontext)) {insert_text(SIGN_POWER_4); return TRUE;}
23849 				if(i == 5 && can_display_unicode_string_function(SIGN_POWER_5, (void*) expressiontext)) {insert_text(SIGN_POWER_5); return TRUE;}
23850 				if(i == 6 && can_display_unicode_string_function(SIGN_POWER_6, (void*) expressiontext)) {insert_text(SIGN_POWER_6); return TRUE;}
23851 				if(i == 7 && can_display_unicode_string_function(SIGN_POWER_7, (void*) expressiontext)) {insert_text(SIGN_POWER_7); return TRUE;}
23852 				if(i == 8 && can_display_unicode_string_function(SIGN_POWER_8, (void*) expressiontext)) {insert_text(SIGN_POWER_8); return TRUE;}
23853 				if(i == 9 && can_display_unicode_string_function(SIGN_POWER_9, (void*) expressiontext)) {insert_text(SIGN_POWER_9); return TRUE;}
23854 			}
23855 		}
23856 		if(b2) {
23857 			string str = "(";
23858 			str += print_with_evalops(Number(1, 1));
23859 			str += "/";
23860 			str += print_with_evalops(Number(i, 1));
23861 			str += ")";
23862 			insert_text(str.c_str());
23863 		} else {
23864 			string str = "^";
23865 			str += print_with_evalops(Number(i, 1));
23866 			insert_text(str.c_str());
23867 		}
23868 		return TRUE;
23869 	}
23870 	return FALSE;
23871 }
23872 
23873 guint button_press_timeout_id = 0;
23874 GtkWidget *button_press_timeout_w = NULL;
23875 int button_press_timeout_side = 0;
23876 bool button_press_timeout_done = false;
23877 
keypad_long_press_timeout(gpointer data)23878 gboolean keypad_long_press_timeout(gpointer data) {
23879 	if(!button_press_timeout_w) {
23880 		button_press_timeout_id = 0;
23881 		button_press_timeout_w = NULL;
23882 		button_press_timeout_side = 0;
23883 		button_press_timeout_done = false;
23884 		return FALSE;
23885 	}
23886 	if(data) {
23887 		hide_tooltip(GTK_WIDGET(data));
23888 		if(GTK_WIDGET(data) == GTK_WIDGET(gtk_builder_get_object(main_builder, "menu_to"))) {
23889 			if(b_busy) return TRUE;
23890 			update_mb_to_menu();
23891 		}
23892 #if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 22
23893 		gtk_menu_popup_at_widget(GTK_MENU(data), button_press_timeout_w, GDK_GRAVITY_SOUTH_WEST, GDK_GRAVITY_NORTH_WEST, gtk_get_current_event());
23894 #else
23895 		gtk_menu_popup(GTK_MENU(data), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time());
23896 #endif
23897 	} else if(button_press_timeout_w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_move2")) && button_press_timeout_side) {
23898 		hide_tooltip(button_press_timeout_w);
23899 		GtkTextIter iter;
23900 		gtk_text_buffer_get_iter_at_mark(expressionbuffer, &iter, gtk_text_buffer_get_insert(expressionbuffer));
23901 		if(button_press_timeout_side == 2) {
23902 			if(gtk_text_iter_is_end(&iter)) gtk_text_buffer_get_start_iter(expressionbuffer, &iter);
23903 			else gtk_text_iter_forward_char(&iter);
23904 		} else {
23905 			if(gtk_text_iter_is_start(&iter)) gtk_text_buffer_get_end_iter(expressionbuffer, &iter);
23906 			else gtk_text_iter_backward_char(&iter);
23907 		}
23908 		gtk_text_buffer_place_cursor(expressionbuffer, &iter);
23909 		button_press_timeout_done = true;
23910 		return TRUE;
23911 	} else if(button_press_timeout_w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_move")) && button_press_timeout_side) {
23912 		hide_tooltip(button_press_timeout_w);
23913 		if(button_press_timeout_side == 2) {
23914 			if(expression_history_index > -1) {
23915 				expression_history_index--;
23916 				dont_change_index = true;
23917 				block_completion();
23918 				if(expression_history_index < 0) {
23919 					clear_expression_text();
23920 				} else {
23921 					set_expression_text(expression_history[expression_history_index].c_str());
23922 				}
23923 				unblock_completion();
23924 				dont_change_index = false;
23925 			}
23926 		} else {
23927 			if(expression_history_index + 1 < (int) expression_history.size()) {
23928 				expression_history_index++;
23929 				dont_change_index = true;
23930 				block_completion();
23931 				set_expression_text(expression_history[expression_history_index].c_str());
23932 				unblock_completion();
23933 				dont_change_index = false;
23934 			}
23935 		}
23936 		button_press_timeout_done = true;
23937 		return TRUE;
23938 	} else if(button_press_timeout_w == GTK_WIDGET(gtk_builder_get_object(main_builder, "button_del")) && custom_buttons[26].type[0] == -1) {
23939 		hide_tooltip(button_press_timeout_w);
23940 		on_button_del_clicked(GTK_BUTTON(button_press_timeout_w), NULL);
23941 		button_press_timeout_done = true;
23942 		return TRUE;
23943 	} else {
23944 		on_keypad_button_alt(button_press_timeout_w, false);
23945 	}
23946 	button_press_timeout_done = true;
23947 	button_press_timeout_id = 0;
23948 	return FALSE;
23949 }
23950 
keypad_unblock_timeout(gpointer w)23951 gboolean keypad_unblock_timeout(gpointer w) {
23952 	while(gtk_events_pending()) gtk_main_iteration();
23953 	g_signal_handlers_unblock_matched(w, (GSignalMatchType) (G_SIGNAL_MATCH_DATA | G_SIGNAL_MATCH_ID), g_signal_lookup("clicked", G_OBJECT_TYPE(w)), 0, NULL, NULL, NULL);
23954 	g_signal_handlers_unblock_matched(w, (GSignalMatchType) (G_SIGNAL_MATCH_DATA | G_SIGNAL_MATCH_ID), g_signal_lookup("toggled", G_OBJECT_TYPE(w)), 0, NULL, NULL, NULL);
23955 	return FALSE;
23956 }
23957 
on_keypad_button_button_event(GtkWidget * w,GdkEventButton * event,gpointer)23958 gboolean on_keypad_button_button_event(GtkWidget *w, GdkEventButton *event, gpointer) {
23959 	if(event->type == GDK_BUTTON_RELEASE && button_press_timeout_id != 0) {
23960 		g_source_remove(button_press_timeout_id);
23961 		button_press_timeout_id = 0;
23962 		button_press_timeout_w = NULL;
23963 		button_press_timeout_side = 0;
23964 		button_press_timeout_done = false;
23965 	} else if(event->type == GDK_BUTTON_RELEASE && button_press_timeout_done) {
23966 		button_press_timeout_done = false;
23967 		bool b_this = (button_press_timeout_w == w);
23968 		button_press_timeout_w = NULL;
23969 		button_press_timeout_side = 0;
23970 		if(b_this) {
23971 			g_signal_handlers_block_matched((gpointer) w, (GSignalMatchType) (G_SIGNAL_MATCH_DATA | G_SIGNAL_MATCH_ID), g_signal_lookup("clicked", G_OBJECT_TYPE(w)), 0, NULL, NULL, NULL);
23972 			g_signal_handlers_block_matched((gpointer) w, (GSignalMatchType) (G_SIGNAL_MATCH_DATA | G_SIGNAL_MATCH_ID), g_signal_lookup("toggled", G_OBJECT_TYPE(w)), 0, NULL, NULL, NULL);
23973 			g_timeout_add(50, keypad_unblock_timeout, (gpointer) w);
23974 			return FALSE;
23975 		}
23976 	}
23977 	if(event->type == GDK_BUTTON_PRESS && event->button == 1) {
23978 		button_press_timeout_w = w;
23979 		button_press_timeout_side = 0;
23980 		button_press_timeout_id = g_timeout_add(500, keypad_long_press_timeout, NULL);
23981 		return FALSE;
23982 	}
23983 	if(event->type == GDK_BUTTON_RELEASE && (event->button == 2 || event->button == 3)) {
23984 		if(on_keypad_button_alt(w, event->button == 2)) return TRUE;
23985 	}
23986 	return FALSE;
23987 }
23988 
on_button_del_button_event(GtkWidget * w,GdkEventButton * event,gpointer)23989 gboolean on_button_del_button_event(GtkWidget *w, GdkEventButton *event, gpointer) {
23990 	if((event->button == 1 && custom_buttons[26].type[0] != -1) || (event->button == 3 && custom_buttons[26].type[1] != -1) || (event->button == 2 && custom_buttons[26].type[2] != -1)) return on_keypad_button_button_event(w, event, NULL);
23991 	if(event->type == GDK_BUTTON_RELEASE && button_press_timeout_id != 0) {
23992 		g_source_remove(button_press_timeout_id);
23993 		bool b_this = (button_press_timeout_w == w);
23994 		button_press_timeout_id = 0;
23995 		button_press_timeout_w = NULL;
23996 		button_press_timeout_side = 0;
23997 		if(button_press_timeout_done) {
23998 			button_press_timeout_done = false;
23999 			if(b_this) return TRUE;
24000 		}
24001 	}
24002 	if(event->type == GDK_BUTTON_PRESS && event->button == 1) {
24003 		button_press_timeout_w = w;
24004 		button_press_timeout_side = 0;
24005 		button_press_timeout_id = g_timeout_add(250, keypad_long_press_timeout, NULL);
24006 		return FALSE;
24007 	}
24008 	if(event->type == GDK_BUTTON_RELEASE && (event->button == 2 || event->button == 3)) {
24009 		on_keypad_button_alt(w, event->button == 2);
24010 	}
24011 	return FALSE;
24012 }
on_button_move2_button_event(GtkWidget * w,GdkEventButton * event,gpointer)24013 gboolean on_button_move2_button_event(GtkWidget *w, GdkEventButton *event, gpointer) {
24014 	if((event->button == 1 && custom_buttons[1].type[0] != -1) || (event->button == 3 && custom_buttons[1].type[1] != -1) || (event->button == 2 && custom_buttons[1].type[2] != -1)) return on_keypad_button_button_event(w, event, NULL);
24015 	hide_tooltip(w);
24016 	if(event->type == GDK_BUTTON_RELEASE && button_press_timeout_id != 0) {
24017 		g_source_remove(button_press_timeout_id);
24018 		bool b_this = (button_press_timeout_w == w);
24019 		button_press_timeout_id = 0;
24020 		button_press_timeout_w = NULL;
24021 		button_press_timeout_side = 0;
24022 		if(button_press_timeout_done) {
24023 			button_press_timeout_done = false;
24024 			if(b_this) return TRUE;
24025 		}
24026 	}
24027 	if(event->type == GDK_BUTTON_PRESS && event->button == 1) {
24028 		button_press_timeout_w = w;
24029 		if(event->window && event->x > gdk_window_get_width(event->window) / 2) button_press_timeout_side = 2;
24030 		else button_press_timeout_side = 1;
24031 		button_press_timeout_id = g_timeout_add(250, keypad_long_press_timeout, NULL);
24032 		return FALSE;
24033 	}
24034 	hide_tooltip(w);
24035 	if(event->button == 2 || event->button == 3) {
24036 		if(event->type == GDK_BUTTON_RELEASE) {
24037 			GtkTextIter iter;
24038 			if(event->window && event->x > gdk_window_get_width(event->window) / 2) {
24039 				gtk_text_buffer_get_end_iter(expressionbuffer, &iter);
24040 			} else {
24041 				gtk_text_buffer_get_start_iter(expressionbuffer, &iter);
24042 			}
24043 			gtk_text_buffer_place_cursor(expressionbuffer, &iter);
24044 		}
24045 	} else {
24046 		GtkTextIter iter;
24047 		gtk_text_buffer_get_iter_at_mark(expressionbuffer, &iter, gtk_text_buffer_get_insert(expressionbuffer));
24048 		if(event->window && event->x > gdk_window_get_width(event->window) / 2) {
24049 			if(gtk_text_iter_is_end(&iter)) gtk_text_buffer_get_start_iter(expressionbuffer, &iter);
24050 			else gtk_text_iter_forward_char(&iter);
24051 		} else {
24052 			if(gtk_text_iter_is_start(&iter)) gtk_text_buffer_get_end_iter(expressionbuffer, &iter);
24053 			else gtk_text_iter_backward_char(&iter);
24054 		}
24055 		gtk_text_buffer_place_cursor(expressionbuffer, &iter);
24056 	}
24057 	return FALSE;
24058 }
on_button_move_button_event(GtkWidget * w,GdkEventButton * event,gpointer)24059 gboolean on_button_move_button_event(GtkWidget *w, GdkEventButton *event, gpointer) {
24060 	if((event->button == 1 && custom_buttons[0].type[0] != -1) || (event->button == 3 && custom_buttons[0].type[1] != -1) || (event->button == 2 && custom_buttons[0].type[2] != -1)) return on_keypad_button_button_event(w, event, NULL);
24061 	hide_tooltip(w);
24062 	if(event->type == GDK_BUTTON_RELEASE && button_press_timeout_id != 0) {
24063 		g_source_remove(button_press_timeout_id);
24064 		bool b_this = (button_press_timeout_w == w);
24065 		button_press_timeout_id = 0;
24066 		button_press_timeout_w = NULL;
24067 		button_press_timeout_side = 0;
24068 		if(button_press_timeout_done) {
24069 			button_press_timeout_done = false;
24070 			if(b_this) return TRUE;
24071 		}
24072 	}
24073 	if(event->type == GDK_BUTTON_PRESS && event->button == 1) {
24074 		button_press_timeout_w = w;
24075 		if(event->window && event->x > gdk_window_get_width(event->window) / 2) button_press_timeout_side = 2;
24076 		else button_press_timeout_side = 1;
24077 		button_press_timeout_id = g_timeout_add(250, keypad_long_press_timeout, NULL);
24078 		return FALSE;
24079 	}
24080 	hide_tooltip(w);
24081 	if(event->type == GDK_BUTTON_RELEASE && event->button == 1) {
24082 		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;
24083 		if(event->window && event->x > gdk_window_get_width(event->window) / 2) {
24084 			if(expression_history_index > -1) {
24085 				expression_history_index--;
24086 				dont_change_index = true;
24087 				block_completion();
24088 				if(expression_history_index < 0) {
24089 					clear_expression_text();
24090 				} else {
24091 					set_expression_text(expression_history[expression_history_index].c_str());
24092 				}
24093 				unblock_completion();
24094 				dont_change_index = false;
24095 			}
24096 		} else {
24097 			if(expression_history_index + 1 < (int) expression_history.size()) {
24098 				expression_history_index++;
24099 				dont_change_index = true;
24100 				block_completion();
24101 				set_expression_text(expression_history[expression_history_index].c_str());
24102 				unblock_completion();
24103 				dont_change_index = false;
24104 			}
24105 		}
24106 	}
24107 	return FALSE;
24108 }
24109 
on_keypad_menu_button_button_event(GtkWidget * w,GdkEventButton * event,gpointer data)24110 gboolean on_keypad_menu_button_button_event(GtkWidget *w, GdkEventButton *event, gpointer data) {
24111 	if(event->type == GDK_BUTTON_RELEASE && button_press_timeout_id != 0) {
24112 		g_source_remove(button_press_timeout_id);
24113 		button_press_timeout_id = 0;
24114 		button_press_timeout_w = NULL;
24115 		button_press_timeout_side = 0;
24116 		button_press_timeout_done = false;
24117 	} else if(event->type == GDK_BUTTON_RELEASE && button_press_timeout_done) {
24118 		button_press_timeout_done = false;
24119 		bool b_this = (button_press_timeout_w == w);
24120 		button_press_timeout_w = NULL;
24121 		button_press_timeout_side = 0;
24122 		if(b_this) return TRUE;
24123 	}
24124 	if(event->type == GDK_BUTTON_PRESS && event->button == 1) {
24125 		button_press_timeout_w = w;
24126 		button_press_timeout_side = 0;
24127 		button_press_timeout_id = g_timeout_add(500, keypad_long_press_timeout, data);
24128 		return FALSE;
24129 	}
24130 	bool b = (event->type == GDK_BUTTON_RELEASE && (event->button == 2 || event->button == 3));
24131 	if(b) {
24132 		if(GTK_WIDGET(data) == GTK_WIDGET(gtk_builder_get_object(main_builder, "menu_to"))) {
24133 			if(b_busy) return TRUE;
24134 			update_mb_to_menu();
24135 		}
24136 #if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 22
24137 		gtk_menu_popup_at_pointer(GTK_MENU(data), (GdkEvent*) event);
24138 #else
24139 		gtk_menu_popup(GTK_MENU(data), NULL, NULL, NULL, NULL, event->button, event->time);
24140 #endif
24141 		return TRUE;
24142 	}
24143 	return FALSE;
24144 }
24145 
24146 #define DO_CUSTOM_BUTTON_1(i) \
24147 	if(custom_buttons[i].type[0] != -1) {\
24148 		do_shortcut(custom_buttons[i].type[0], custom_buttons[i].value[0]);\
24149 		return;\
24150 	}
24151 
24152 /*
24153 	Button clicked -- insert text (1,2,3,... +,-,...)
24154 */
on_button_zero_clicked(GtkButton *,gpointer)24155 void on_button_zero_clicked(GtkButton*, gpointer) {
24156 	DO_CUSTOM_BUTTON_1(8)
24157 	insert_text("0");
24158 }
on_button_one_clicked(GtkButton *,gpointer)24159 void on_button_one_clicked(GtkButton*, gpointer) {
24160 	DO_CUSTOM_BUTTON_1(9)
24161 	insert_text("1");
24162 }
on_button_two_clicked(GtkButton *,gpointer)24163 void on_button_two_clicked(GtkButton*, gpointer) {
24164 	DO_CUSTOM_BUTTON_1(10)
24165 	insert_text("2");
24166 }
on_button_three_clicked(GtkButton *,gpointer)24167 void on_button_three_clicked(GtkButton*, gpointer) {
24168 	DO_CUSTOM_BUTTON_1(11)
24169 	insert_text("3");
24170 }
on_button_four_clicked(GtkButton *,gpointer)24171 void on_button_four_clicked(GtkButton*, gpointer) {
24172 	DO_CUSTOM_BUTTON_1(12)
24173 	insert_text("4");
24174 }
on_button_five_clicked(GtkButton *,gpointer)24175 void on_button_five_clicked(GtkButton*, gpointer) {
24176 	DO_CUSTOM_BUTTON_1(13)
24177 	insert_text("5");
24178 }
on_button_six_clicked(GtkButton *,gpointer)24179 void on_button_six_clicked(GtkButton*, gpointer) {
24180 	DO_CUSTOM_BUTTON_1(14)
24181 	insert_text("6");
24182 }
on_button_seven_clicked(GtkButton *,gpointer)24183 void on_button_seven_clicked(GtkButton*, gpointer) {
24184 	DO_CUSTOM_BUTTON_1(15)
24185 	insert_text("7");
24186 }
on_button_eight_clicked(GtkButton *,gpointer)24187 void on_button_eight_clicked(GtkButton*, gpointer) {
24188 	DO_CUSTOM_BUTTON_1(16)
24189 	insert_text("8");
24190 }
on_button_nine_clicked(GtkButton *,gpointer)24191 void on_button_nine_clicked(GtkButton*, gpointer) {
24192 	DO_CUSTOM_BUTTON_1(17)
24193 	insert_text("9");
24194 }
on_button_c1_clicked(GtkButton *,gpointer)24195 void on_button_c1_clicked(GtkButton*, gpointer) {
24196 	DO_CUSTOM_BUTTON_1(29)
24197 }
on_button_c2_clicked(GtkButton *,gpointer)24198 void on_button_c2_clicked(GtkButton*, gpointer) {
24199 	DO_CUSTOM_BUTTON_1(30)
24200 }
on_button_c3_clicked(GtkButton *,gpointer)24201 void on_button_c3_clicked(GtkButton*, gpointer) {
24202 	DO_CUSTOM_BUTTON_1(31)
24203 }
on_button_c4_clicked(GtkButton *,gpointer)24204 void on_button_c4_clicked(GtkButton*, gpointer) {
24205 	DO_CUSTOM_BUTTON_1(32)
24206 }
on_button_c5_clicked(GtkButton *,gpointer)24207 void on_button_c5_clicked(GtkButton*, gpointer) {
24208 	DO_CUSTOM_BUTTON_1(33)
24209 }
on_button_a_clicked(GtkButton *,gpointer)24210 void on_button_a_clicked(GtkButton*, gpointer) {
24211 	insert_text(printops.lower_case_numbers ? "a" : "A");
24212 }
on_button_b_clicked(GtkButton *,gpointer)24213 void on_button_b_clicked(GtkButton*, gpointer) {
24214 	insert_text(printops.lower_case_numbers ? "b" : "B");
24215 }
on_button_c_clicked(GtkButton *,gpointer)24216 void on_button_c_clicked(GtkButton*, gpointer) {
24217 	insert_text(printops.lower_case_numbers ? "c" : "C");
24218 }
on_button_d_clicked(GtkButton *,gpointer)24219 void on_button_d_clicked(GtkButton*, gpointer) {
24220 	insert_text(printops.lower_case_numbers ? "d" : "D");
24221 }
on_button_e_clicked(GtkButton *,gpointer)24222 void on_button_e_clicked(GtkButton*, gpointer) {
24223 	insert_text(printops.lower_case_numbers ? "e" : "E");
24224 }
on_button_f_clicked(GtkButton *,gpointer)24225 void on_button_f_clicked(GtkButton*, gpointer) {
24226 	insert_text(printops.lower_case_numbers ? "f" : "F");
24227 }
on_button_dot_clicked(GtkButton *,gpointer)24228 void on_button_dot_clicked(GtkButton*, gpointer) {
24229 	DO_CUSTOM_BUTTON_1(18)
24230 	insert_text(CALCULATOR->getDecimalPoint().c_str());
24231 }
on_button_brace_open_clicked(GtkButton *,gpointer)24232 void on_button_brace_open_clicked(GtkButton*, gpointer) {
24233 	DO_CUSTOM_BUTTON_1(6)
24234 	insert_text("(");
24235 }
on_button_brace_close_clicked(GtkButton *,gpointer)24236 void on_button_brace_close_clicked(GtkButton*, gpointer) {
24237 	DO_CUSTOM_BUTTON_1(7)
24238 	insert_text(")");
24239 }
brace_wrap()24240 void brace_wrap() {
24241 	string expr = get_expression_text();
24242 	GtkTextIter istart, iend, ipos;
24243 	gint il = expr.length();
24244 	if(il == 0) {
24245 		set_expression_text("()");
24246 		gtk_text_buffer_get_start_iter(expressionbuffer, &istart);
24247 		gtk_text_iter_forward_char(&istart);
24248 		gtk_text_buffer_place_cursor(expressionbuffer, &istart);
24249 		return;
24250 	}
24251 	GtkTextMark *mpos = gtk_text_buffer_get_insert(expressionbuffer);
24252 	gtk_text_buffer_get_iter_at_mark(expressionbuffer, &ipos, mpos);
24253 	gtk_text_buffer_get_start_iter(expressionbuffer, &istart);
24254 	iend = istart;
24255 	bool goto_start = false;
24256 	if(gtk_text_buffer_get_has_selection(expressionbuffer)) {
24257 		GtkTextMark *mstart = gtk_text_buffer_get_selection_bound(expressionbuffer);
24258 		gtk_text_buffer_get_iter_at_mark(expressionbuffer, &istart, mstart);
24259 		if(gtk_text_iter_compare(&istart, &ipos) > 0) {
24260 			iend = istart;
24261 			istart = ipos;
24262 		} else {
24263 			iend = ipos;
24264 		}
24265 	} else {
24266 		iend = ipos;
24267 		if(!gtk_text_iter_is_start(&iend)) {
24268 			gchar *gstr = gtk_text_buffer_get_text(expressionbuffer, &istart, &iend, FALSE);
24269 			string str = CALCULATOR->unlocalizeExpression(gstr, evalops.parse_options);
24270 			g_free(gstr);
24271 			CALCULATOR->parseSigns(str);
24272 			if(str.empty() || is_in(OPERATORS SPACES SEXADOT DOT LEFT_VECTOR_WRAP LEFT_PARENTHESIS COMMAS, str[str.length() - 1])) {
24273 				istart = iend;
24274 				gtk_text_buffer_get_end_iter(expressionbuffer, &iend);
24275 				if(gtk_text_iter_compare(&istart, &iend) < 0) {
24276 					gstr = gtk_text_buffer_get_text(expressionbuffer, &istart, &iend, FALSE);
24277 					str = CALCULATOR->unlocalizeExpression(gstr, evalops.parse_options);
24278 					g_free(gstr);
24279 					CALCULATOR->parseSigns(str);
24280 					if(str.empty() || (is_in(OPERATORS SPACES SEXADOT DOT RIGHT_VECTOR_WRAP LEFT_PARENTHESIS RIGHT_PARENTHESIS COMMAS, str[0]) && str[0] != MINUS_CH)) {
24281 						iend = istart;
24282 					}
24283 				}
24284 			}
24285 		} else {
24286 			goto_start = true;
24287 			gtk_text_buffer_get_end_iter(expressionbuffer, &iend);
24288 			gchar *gstr = gtk_text_buffer_get_text(expressionbuffer, &istart, &iend, FALSE);
24289 			string str = CALCULATOR->unlocalizeExpression(gstr, evalops.parse_options);
24290 			g_free(gstr);
24291 			CALCULATOR->parseSigns(str);
24292 			if(str.empty() || (is_in(OPERATORS SPACES SEXADOT DOT RIGHT_VECTOR_WRAP LEFT_PARENTHESIS RIGHT_PARENTHESIS COMMAS, str[0]) && str[0] != MINUS_CH)) {
24293 				iend = istart;
24294 			}
24295 		}
24296 	}
24297 	if(gtk_text_iter_compare(&istart, &iend) >= 0) {
24298 		gtk_text_buffer_insert(expressionbuffer, &istart, "()", -1);
24299 		gtk_text_iter_backward_char(&istart);
24300 		gtk_text_buffer_place_cursor(expressionbuffer, &istart);
24301 		return;
24302 	}
24303 	gchar *gstr = gtk_text_buffer_get_text(expressionbuffer, &istart, &iend, FALSE);
24304 	GtkTextMark *mstart = gtk_text_buffer_create_mark(expressionbuffer, "istart", &istart, TRUE);
24305 	GtkTextMark *mend = gtk_text_buffer_create_mark(expressionbuffer, "iend", &iend, FALSE);
24306 	block_add_to_undo++;
24307 	gtk_text_buffer_insert(expressionbuffer, &istart, "(", -1);
24308 	gtk_text_buffer_get_iter_at_mark(expressionbuffer, &iend, mend);
24309 	block_add_to_undo--;
24310 	gtk_text_buffer_insert(expressionbuffer, &iend, ")", -1);
24311 	gtk_text_buffer_get_iter_at_mark(expressionbuffer, &istart, mstart);
24312 	gtk_text_buffer_delete_mark(expressionbuffer, mstart);
24313 	gtk_text_buffer_delete_mark(expressionbuffer, mend);
24314 	string str = CALCULATOR->unlocalizeExpression(gstr, evalops.parse_options);
24315 	g_free(gstr);
24316 	CALCULATOR->parseSigns(str);
24317 	if(str.empty() || is_in(OPERATORS SPACES SEXADOT DOT LEFT_VECTOR_WRAP LEFT_PARENTHESIS COMMAS, str[str.length() - 1])) {
24318 		gtk_text_iter_backward_char(&iend);
24319 		goto_start = false;
24320 	}
24321 	gtk_text_buffer_place_cursor(expressionbuffer, goto_start ? &istart : &iend);
24322 }
on_button_brace_wrap_clicked(GtkButton *,gpointer)24323 void on_button_brace_wrap_clicked(GtkButton*, gpointer) {
24324 	DO_CUSTOM_BUTTON_1(5)
24325 	brace_wrap();
24326 }
on_button_i_clicked(GtkButton *,gpointer)24327 void on_button_i_clicked(GtkButton*, gpointer) {
24328 	insert_var(CALCULATOR->v_i);
24329 }
on_button_move_clicked(GtkButton *,gpointer)24330 void on_button_move_clicked(GtkButton*, gpointer) {
24331 	DO_CUSTOM_BUTTON_1(0)
24332 }
on_button_move2_clicked(GtkButton *,gpointer)24333 void on_button_move2_clicked(GtkButton*, gpointer) {
24334 	DO_CUSTOM_BUTTON_1(1)
24335 }
on_button_percent_clicked(GtkButton *,gpointer)24336 void on_button_percent_clicked(GtkButton*, gpointer) {
24337 	DO_CUSTOM_BUTTON_1(2)
24338 	insert_text("%");
24339 }
on_button_si_clicked(GtkButton *,gpointer)24340 void on_button_si_clicked(GtkButton*, gpointer) {
24341 	if(latest_button_unit) {
24342 		insert_button_unit(NULL, (gpointer) latest_button_unit);
24343 	} else {
24344 		insert_text("kg");
24345 	}
24346 }
on_button_euro_clicked(GtkButton *,gpointer)24347 void on_button_euro_clicked(GtkButton*, gpointer) {
24348 	if(latest_button_currency) {
24349 		insert_button_currency(NULL, (gpointer) latest_button_currency);
24350 	} else {
24351 		insert_text("€");
24352 	}
24353 }
24354 
24355 /*
24356 	DEL button clicked -- delete in expression entry
24357 */
on_button_del_clicked(GtkButton *,gpointer)24358 void on_button_del_clicked(GtkButton*, gpointer) {
24359 	DO_CUSTOM_BUTTON_1(26)
24360 	if(gtk_text_buffer_get_has_selection(expressionbuffer)) {
24361 		overwrite_expression_selection(NULL);
24362 		return;
24363 	}
24364 	block_completion();
24365 	GtkTextMark *mpos = gtk_text_buffer_get_insert(expressionbuffer);
24366 	GtkTextIter ipos, iend;
24367 	gtk_text_buffer_get_iter_at_mark(expressionbuffer, &ipos, mpos);
24368 	if(gtk_text_iter_is_end(&ipos)) {
24369 		gtk_text_buffer_get_end_iter(expressionbuffer, &iend);
24370 		if(gtk_text_iter_backward_char(&ipos)) {
24371 			gtk_text_buffer_delete(expressionbuffer, &ipos, &iend);
24372 		}
24373 	} else {
24374 		iend = ipos;
24375 		if(!gtk_text_iter_forward_char(&iend)) {
24376 			gtk_text_buffer_get_end_iter(expressionbuffer, &iend);
24377 		}
24378 		gtk_text_buffer_delete(expressionbuffer, &ipos, &iend);
24379 	}
24380 	focus_keeping_selection();
24381 	unblock_completion();
24382 }
24383 
24384 /*
24385 	"Execute" clicked
24386 */
on_button_execute_clicked(GtkButton *,gpointer)24387 void on_button_execute_clicked(GtkButton*, gpointer) {
24388 	DO_CUSTOM_BUTTON_1(28)
24389 	execute_expression();
24390 }
24391 
24392 /*
24393 	AC button clicked -- clear expression entry
24394 */
on_button_ac_clicked(GtkButton *,gpointer)24395 void on_button_ac_clicked(GtkButton*, gpointer) {
24396 	DO_CUSTOM_BUTTON_1(27)
24397 	clear_expression_text();
24398 	focus_keeping_selection();
24399 }
24400 
on_button_to_clicked(GtkButton *,gpointer)24401 void on_button_to_clicked(GtkButton*, gpointer) {
24402 	if(b_busy) return;
24403 	string to_str;
24404 	GtkTextIter istart, iend;
24405 	gtk_text_buffer_get_end_iter(expressionbuffer, &iend);
24406 	gtk_text_buffer_select_range(expressionbuffer, &iend, &iend);
24407 	if(printops.use_unicode_signs && can_display_unicode_string_function("➞", (void*) expressiontext)) {
24408 		to_str = "➞";
24409 	} else {
24410 		gtk_text_buffer_get_start_iter(expressionbuffer, &istart);
24411 		gchar *gstr = gtk_text_buffer_get_text(expressionbuffer, &istart, &iend, FALSE);
24412 		to_str = CALCULATOR->localToString();
24413 		remove_blank_ends(to_str);
24414 		to_str += ' ';
24415 		if(strlen(gstr) > 0 && gstr[strlen(gstr) - 1] != ' ') to_str.insert(0, " ");
24416 		g_free(gstr);
24417 	}
24418 	gtk_text_buffer_insert_at_cursor(expressionbuffer, to_str.c_str(), -1);
24419 	if(!gtk_widget_is_focus(expressiontext)) {
24420 		gtk_widget_grab_focus(expressiontext);
24421 	}
24422 }
on_button_new_function_clicked(GtkButton *,gpointer)24423 void on_button_new_function_clicked(GtkButton*, gpointer) {
24424 	edit_function_simple("", NULL, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")));
24425 }
on_button_fac_clicked(GtkButton *,gpointer)24426 void on_button_fac_clicked(GtkButton*, gpointer) {
24427 	if(rpn_mode || evalops.parse_options.parsing_mode == PARSING_MODE_RPN || is_at_beginning_of_expression()) {
24428 		insertButtonFunction(CALCULATOR->f_factorial);
24429 	}
24430 	bool do_exec = wrap_expression_selection(NULL, true) > 0;
24431 	insert_text("!");
24432 	if(do_exec) execute_expression();
24433 }
on_button_comma_clicked(GtkButton *,gpointer)24434 void on_button_comma_clicked(GtkButton*, gpointer) {
24435 	DO_CUSTOM_BUTTON_1(4)
24436 	insert_text(CALCULATOR->getComma().c_str());
24437 }
on_button_x_clicked(GtkButton *,gpointer)24438 void on_button_x_clicked(GtkButton*, gpointer) {
24439 	insert_text("x");
24440 }
on_button_y_clicked(GtkButton *,gpointer)24441 void on_button_y_clicked(GtkButton*, gpointer) {
24442 	insert_text("y");
24443 }
on_button_z_clicked(GtkButton *,gpointer)24444 void on_button_z_clicked(GtkButton*, gpointer) {
24445 	insert_text("z");
24446 }
on_button_xequals_clicked(GtkButton *,gpointer)24447 void on_button_xequals_clicked(GtkButton*, gpointer) {
24448 	insert_text("=");
24449 }
on_button_plusminus_clicked(GtkButton *,gpointer)24450 void on_button_plusminus_clicked(GtkButton*, gpointer) {
24451 	DO_CUSTOM_BUTTON_1(3)
24452 	wrap_expression_selection();
24453 	insert_text("±");
24454 }
on_button_factorize_clicked(GtkButton *,gpointer)24455 void on_button_factorize_clicked(GtkButton*, gpointer) {
24456 	if(evalops.structuring == STRUCTURING_FACTORIZE) executeCommand(COMMAND_EXPAND);
24457 	else executeCommand(COMMAND_FACTORIZE);
24458 }
on_button_factorize2_clicked(GtkButton *,gpointer)24459 void on_button_factorize2_clicked(GtkButton*, gpointer) {
24460 	executeCommand(COMMAND_FACTORIZE);
24461 }
insert_angle_symbol()24462 void insert_angle_symbol() {
24463 	if(!rpn_mode && do_chain_mode("∠")) return;
24464 	insert_text("∠");
24465 }
insert_left_shift()24466 void insert_left_shift() {
24467 	if(evalops.parse_options.parsing_mode != PARSING_MODE_RPN) {
24468 		if(!rpn_mode && do_chain_mode("<<")) return;
24469 		wrap_expression_selection();
24470 	}
24471 	insert_text("<<");
24472 }
insert_right_shift()24473 void insert_right_shift() {
24474 	if(evalops.parse_options.parsing_mode != PARSING_MODE_RPN) {
24475 		if(!rpn_mode && do_chain_mode(">>")) return;
24476 		wrap_expression_selection();
24477 	}
24478 	insert_text(">>");
24479 }
insert_bitwise_and()24480 void insert_bitwise_and() {
24481 	if(rpn_mode) {calculateRPN(OPERATION_BITWISE_AND); return;}
24482 	if(evalops.parse_options.parsing_mode != PARSING_MODE_RPN) {
24483 		if(do_chain_mode("&")) return;
24484 		wrap_expression_selection();
24485 	}
24486 	insert_text("&");
24487 }
insert_bitwise_or()24488 void insert_bitwise_or() {
24489 	if(rpn_mode) {calculateRPN(OPERATION_BITWISE_OR); return;}
24490 	if(evalops.parse_options.parsing_mode != PARSING_MODE_RPN) {
24491 		if(do_chain_mode("|")) return;
24492 		wrap_expression_selection();
24493 	}
24494 	insert_text("|");
24495 }
insert_bitwise_xor()24496 void insert_bitwise_xor() {
24497 	if(rpn_mode) {calculateRPN(OPERATION_BITWISE_XOR); return;}
24498 	if(evalops.parse_options.parsing_mode != PARSING_MODE_RPN) {
24499 		if(do_chain_mode(" xor ")) return;
24500 		wrap_expression_selection();
24501 	}
24502 	insert_text(" xor ");
24503 }
insert_bitwise_not()24504 void insert_bitwise_not() {
24505 	if(rpn_mode) {
24506 		if(expression_has_changed) {
24507 			if(get_expression_text().find_first_not_of(SPACES) != string::npos) {
24508 				execute_expression(true);
24509 			}
24510 		}
24511 		execute_expression(true, false, OPERATION_ADD, NULL, false, 0, "~");
24512 		return;
24513 	}
24514 	if(evalops.parse_options.parsing_mode != PARSING_MODE_RPN && wrap_expression_selection("~") > 0) return;
24515 	insert_text("~");
24516 }
24517 
24518 void history_operator(string str_sign);
on_button_add_clicked(GtkButton *,gpointer)24519 void on_button_add_clicked(GtkButton*, gpointer) {
24520 	DO_CUSTOM_BUTTON_1(23)
24521 	if(persistent_keypad && gtk_expander_get_expanded(GTK_EXPANDER(expander_history)) && gtk_tree_selection_count_selected_rows(gtk_tree_view_get_selection(GTK_TREE_VIEW(historyview))) > 0) {
24522 		history_operator(expression_add_sign());
24523 		return;
24524 	}
24525 	if(rpn_mode) {
24526 		calculateRPN(OPERATION_ADD);
24527 		return;
24528 	}
24529 	if(evalops.parse_options.parsing_mode != PARSING_MODE_RPN) {
24530 		if(do_chain_mode(expression_add_sign())) return;
24531 		wrap_expression_selection();
24532 	}
24533 	insert_text(expression_add_sign());
24534 }
24535 
on_button_sub_clicked(GtkButton *,gpointer)24536 void on_button_sub_clicked(GtkButton*, gpointer) {
24537 	DO_CUSTOM_BUTTON_1(24)
24538 	if(persistent_keypad && gtk_expander_get_expanded(GTK_EXPANDER(expander_history)) && gtk_tree_selection_count_selected_rows(gtk_tree_view_get_selection(GTK_TREE_VIEW(historyview))) > 0) {
24539 		history_operator(expression_sub_sign());
24540 		return;
24541 	}
24542 	if(rpn_mode) {
24543 		calculateRPN(OPERATION_SUBTRACT);
24544 		return;
24545 	}
24546 	if(evalops.parse_options.parsing_mode != PARSING_MODE_RPN) {
24547 		if(do_chain_mode(expression_sub_sign())) return;
24548 		wrap_expression_selection();
24549 	}
24550 	insert_text(expression_sub_sign());
24551 }
on_button_times_clicked(GtkButton *,gpointer)24552 void on_button_times_clicked(GtkButton*, gpointer) {
24553 	DO_CUSTOM_BUTTON_1(22)
24554 	if(persistent_keypad && gtk_expander_get_expanded(GTK_EXPANDER(expander_history)) && gtk_tree_selection_count_selected_rows(gtk_tree_view_get_selection(GTK_TREE_VIEW(historyview))) > 0) {
24555 		history_operator(expression_times_sign());
24556 		return;
24557 	}
24558 	if(rpn_mode) {
24559 		calculateRPN(OPERATION_MULTIPLY);
24560 		return;
24561 	}
24562 	if(evalops.parse_options.parsing_mode != PARSING_MODE_RPN) {
24563 		if(do_chain_mode(expression_times_sign())) return;
24564 		wrap_expression_selection();
24565 	}
24566 	insert_text(expression_times_sign());
24567 }
on_button_divide_clicked(GtkButton *,gpointer)24568 void on_button_divide_clicked(GtkButton*, gpointer) {
24569 	DO_CUSTOM_BUTTON_1(21)
24570 	if(persistent_keypad && gtk_expander_get_expanded(GTK_EXPANDER(expander_history)) && gtk_tree_selection_count_selected_rows(gtk_tree_view_get_selection(GTK_TREE_VIEW(historyview))) > 0) {
24571 		history_operator(expression_divide_sign());
24572 		return;
24573 	}
24574 	if(rpn_mode) {
24575 		calculateRPN(OPERATION_DIVIDE);
24576 		return;
24577 	}
24578 	if(evalops.parse_options.parsing_mode != PARSING_MODE_RPN) {
24579 		if(do_chain_mode(expression_divide_sign())) return;
24580 		wrap_expression_selection();
24581 	}
24582 	insert_text(expression_divide_sign());
24583 }
on_button_ans_clicked(GtkButton *,gpointer)24584 void on_button_ans_clicked(GtkButton*, gpointer) {
24585 	DO_CUSTOM_BUTTON_1(27)
24586 	insert_text(vans[0]->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext).name.c_str());
24587 }
on_button_exp_clicked(GtkButton *,gpointer)24588 void on_button_exp_clicked(GtkButton*, gpointer) {
24589 	DO_CUSTOM_BUTTON_1(19)
24590 	if(rpn_mode) {
24591 		calculateRPN(OPERATION_EXP10);
24592 		return;
24593 	}
24594 	if((evalops.parse_options.parsing_mode != PARSING_MODE_RPN && wrap_expression_selection() > 0) || (evalops.parse_options.base != 10 && evalops.parse_options.base >= 2)) {
24595 		insert_text((expression_times_sign() + i2s(evalops.parse_options.base) + "^").c_str());
24596 	} else {
24597 		if(printops.lower_case_e) insert_text("e");
24598 		else insert_text("E");
24599 	}
24600 }
on_button_xy_clicked(GtkButton *,gpointer)24601 void on_button_xy_clicked(GtkButton*, gpointer) {
24602 	DO_CUSTOM_BUTTON_1(20)
24603 	if(persistent_keypad && gtk_expander_get_expanded(GTK_EXPANDER(expander_history)) && gtk_tree_selection_count_selected_rows(gtk_tree_view_get_selection(GTK_TREE_VIEW(historyview))) > 0) {
24604 		history_operator("^");
24605 		return;
24606 	}
24607 	if(rpn_mode) {
24608 		calculateRPN(OPERATION_RAISE);
24609 		return;
24610 	}
24611 	if(evalops.parse_options.parsing_mode != PARSING_MODE_RPN) {
24612 		if(do_chain_mode("^")) return;
24613 		wrap_expression_selection();
24614 	}
24615 	insert_text("^");
24616 }
on_button_square_clicked()24617 void on_button_square_clicked() {
24618 	if(rpn_mode) {
24619 		calculateRPN(CALCULATOR->f_sq);
24620 		return;
24621 	}
24622 	if(evalops.parse_options.parsing_mode == PARSING_MODE_RPN || chain_mode || wrap_expression_selection() < 0) {
24623 		insertButtonFunction(CALCULATOR->f_sq);
24624 	} else {
24625 		if(printops.use_unicode_signs && can_display_unicode_string_function(SIGN_POWER_2, (void*) expressiontext)) insert_text(SIGN_POWER_2);
24626 		else insert_text("^2");
24627 	}
24628 }
24629 
24630 /*
24631 	Button clicked -- insert corresponding function
24632 */
on_button_sqrt_clicked(GtkButton *,gpointer)24633 void on_button_sqrt_clicked(GtkButton*, gpointer) {
24634 	insertButtonFunction(CALCULATOR->f_sqrt);
24635 }
on_button_log_clicked(GtkButton *,gpointer)24636 void on_button_log_clicked(GtkButton*, gpointer) {
24637 	MathFunction *f = CALCULATOR->getActiveFunction("log10");
24638 	if(f) {
24639 		insertButtonFunction(f);
24640 	} else {
24641 		show_message(_("log10 function not found."), GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")));
24642 	}
24643 }
on_button_ln_clicked(GtkButton *,gpointer)24644 void on_button_ln_clicked(GtkButton*, gpointer) {
24645 	insertButtonFunction(CALCULATOR->f_ln);
24646 }
24647 
24648 /*
24649 	Buttons to the left of the RPN stack clicked
24650 */
on_button_rpn_add_clicked(GtkButton *,gpointer)24651 void on_button_rpn_add_clicked(GtkButton*, gpointer) {
24652 	calculateRPN(OPERATION_ADD);
24653 }
on_button_rpn_sub_clicked(GtkButton *,gpointer)24654 void on_button_rpn_sub_clicked(GtkButton*, gpointer) {
24655 	calculateRPN(OPERATION_SUBTRACT);
24656 }
on_button_rpn_times_clicked(GtkButton *,gpointer)24657 void on_button_rpn_times_clicked(GtkButton*, gpointer) {
24658 	calculateRPN(OPERATION_MULTIPLY);
24659 }
on_button_rpn_divide_clicked(GtkButton *,gpointer)24660 void on_button_rpn_divide_clicked(GtkButton*, gpointer) {
24661 	calculateRPN(OPERATION_DIVIDE);
24662 }
on_button_rpn_xy_clicked(GtkButton *,gpointer)24663 void on_button_rpn_xy_clicked(GtkButton*, gpointer) {
24664 	calculateRPN(OPERATION_RAISE);
24665 }
on_button_rpn_sqrt_clicked(GtkButton *,gpointer)24666 void on_button_rpn_sqrt_clicked(GtkButton*, gpointer) {
24667 	insertButtonFunction(CALCULATOR->f_sqrt);
24668 }
on_button_rpn_reciprocal_clicked(GtkButton *,gpointer)24669 void on_button_rpn_reciprocal_clicked(GtkButton*, gpointer) {
24670 	insertButtonFunction(CALCULATOR->getActiveFunction("inv"));
24671 }
on_button_rpn_negate_clicked(GtkButton *,gpointer)24672 void on_button_rpn_negate_clicked(GtkButton*, gpointer) {
24673 	insertButtonFunction(CALCULATOR->getActiveFunction("neg"));
24674 }
on_button_rpn_sum_clicked(GtkButton *,gpointer)24675 void on_button_rpn_sum_clicked(GtkButton*, gpointer) {
24676 	insertButtonFunction(CALCULATOR->f_total);
24677 }
24678 #define INDEX_TYPE_ANS 0
24679 #define INDEX_TYPE_XPR 1
24680 #define INDEX_TYPE_TXT 2
process_history_selection(vector<size_t> * selected_rows,vector<size_t> * selected_indeces,vector<int> * selected_index_type,bool ans_priority=false)24681 void process_history_selection(vector<size_t> *selected_rows, vector<size_t> *selected_indeces, vector<int> *selected_index_type, bool ans_priority = false) {
24682 	GtkTreeModel *model;
24683 	GtkTreeIter iter;
24684 	GList *selected_list, *current_selected_list;
24685 	gint index = -1, hindex = -1;
24686 	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(historyview));
24687 	selected_list = gtk_tree_selection_get_selected_rows(select, &model);
24688 	current_selected_list = selected_list;
24689 	while(current_selected_list) {
24690 		gtk_tree_model_get_iter(model, &iter, (GtkTreePath*) current_selected_list->data);
24691 		gtk_tree_model_get(model, &iter, 1, &hindex, 3, &index, -1);
24692 		if(hindex >= 0) {
24693 			if(selected_rows) selected_rows->push_back((size_t) hindex);
24694 			if(selected_indeces && (index <= 0 || !evalops.parse_options.functions_enabled || evalops.parse_options.base > BASE_DECIMAL || evalops.parse_options.base < 0)) {
24695 				if(HISTORY_NOT_MESSAGE(hindex) && (hindex < 1 || inhistory_type[hindex] != QALCULATE_HISTORY_TRANSFORMATION || inhistory_type[hindex - 1] == QALCULATE_HISTORY_RESULT || inhistory_type[hindex - 1] == QALCULATE_HISTORY_RESULT_APPROXIMATE)) {
24696 					selected_indeces->push_back((size_t) hindex);
24697 					selected_index_type->push_back(INDEX_TYPE_TXT);
24698 				}
24699 			} else if(selected_indeces && index > 0) {
24700 				bool index_found = false;
24701 				size_t i = selected_indeces->size();
24702 				for(; i > 0; i--) {
24703 					if(selected_index_type->at(i - 1) != INDEX_TYPE_TXT && selected_indeces->at(i - 1) == (size_t) index) {
24704 						index_found = true;
24705 						break;
24706 					}
24707 				}
24708 				if(!index_found) selected_indeces->push_back(index);
24709 				switch(inhistory_type[hindex]) {
24710 					case QALCULATE_HISTORY_EXPRESSION: {}
24711 					case QALCULATE_HISTORY_REGISTER_MOVED: {}
24712 					case QALCULATE_HISTORY_PARSE: {}
24713 					case QALCULATE_HISTORY_PARSE_APPROXIMATE: {}
24714 					case QALCULATE_HISTORY_RPN_OPERATION: {
24715 						if(!index_found) selected_index_type->push_back(INDEX_TYPE_XPR);
24716 						else if(!ans_priority) selected_index_type->at(i - 1) = INDEX_TYPE_XPR;
24717 						break;
24718 					}
24719 					default: {
24720 						if(!index_found) selected_index_type->push_back(INDEX_TYPE_ANS);
24721 						else if(ans_priority) selected_index_type->at(i - 1) = INDEX_TYPE_ANS;
24722 					}
24723 				}
24724 			}
24725 		}
24726 		current_selected_list = current_selected_list->next;
24727 	}
24728 	if(selected_list) g_list_free_full(selected_list, (GDestroyNotify) gtk_tree_path_free);
24729 }
history_operator(string str_sign)24730 void history_operator(string str_sign) {
24731 	if(b_busy) return;
24732 	vector<size_t> selected_indeces;
24733 	vector<int> selected_index_type;
24734 	process_history_selection(NULL, &selected_indeces, &selected_index_type);
24735 	if(rpn_mode && !expression_is_empty()) execute_expression();
24736 	if(selected_indeces.empty()) {
24737 		if(rpn_mode) {
24738 			block_add_to_undo++;
24739 			insert_text(str_sign.c_str());
24740 			block_add_to_undo--;
24741 			execute_expression();
24742 			return;
24743 		}
24744 		if(evalops.parse_options.parsing_mode != PARSING_MODE_RPN) {
24745 			if(do_chain_mode(expression_times_sign())) return;
24746 			wrap_expression_selection();
24747 		}
24748 		insert_text(str_sign.c_str());
24749 		return;
24750 	}
24751 	bool only_one_value = false;
24752 	string str;
24753 	if(selected_indeces.size() == 1) {
24754 		str = get_selected_expression_text(true);
24755 		if(str.empty()) {
24756 			only_one_value = true;
24757 		} else {
24758 			string search_s = CALCULATOR->getDecimalPoint() + NUMBER_ELEMENTS;
24759 			if((str.length() < 2 || str[0] != '(' || str[str.length() - 1] != ')') && str.find_first_not_of(search_s) != string::npos) {
24760 				str.insert(str.begin(), '(');
24761 				str += ')';
24762 			}
24763 			if(evalops.parse_options.parsing_mode == PARSING_MODE_RPN) str += ' ';
24764 			else str += str_sign;
24765 		}
24766 	}
24767 
24768 	for(size_t i = 0; i < selected_indeces.size(); i++) {
24769 		if(i > 0) {
24770 			if(evalops.parse_options.parsing_mode == PARSING_MODE_RPN) str += ' ';
24771 			else str += str_sign;
24772 		}
24773 		if(selected_index_type[i] == INDEX_TYPE_TXT) {
24774 			int index = selected_indeces[i];
24775 			if(index > 0 && inhistory_type[index] == QALCULATE_HISTORY_TRANSFORMATION) index--;
24776 			string search_s = CALCULATOR->getDecimalPoint() + NUMBER_ELEMENTS;
24777 			if((inhistory[index].length() >= 2 && inhistory[index][0] == '(' && inhistory[index][inhistory[index].length() - 1] == ')') || inhistory[index].find_first_not_of(search_s) == string::npos) {
24778 				str += inhistory[index];
24779 			} else {
24780 				str += '(';
24781 				str += inhistory[index];
24782 				str += ')';
24783 			}
24784 		} else {
24785 			const ExpressionName *ename = NULL;
24786 			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);
24787 			else ename = &f_answer->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext);
24788 			str += ename->name;
24789 			str += '(';
24790 			Number nr(selected_indeces[i], 1);
24791 			str += print_with_evalops(nr);
24792 			str += ')';
24793 		}
24794 	}
24795 	if(only_one_value && evalops.parse_options.parsing_mode != PARSING_MODE_RPN && !rpn_mode) {
24796 		str += str_sign;
24797 	}
24798 	if(evalops.parse_options.parsing_mode == PARSING_MODE_RPN) {
24799 		str += ' ';
24800 		if(selected_indeces.size() == 1) {
24801 			str += str_sign;
24802 		} else {
24803 			for(size_t i = 0; i < selected_indeces.size() - 1; i++) {
24804 				str += str_sign;
24805 			}
24806 		}
24807 	}
24808 	block_add_to_undo++;
24809 	gtk_text_buffer_set_text(expressionbuffer, "", -1);
24810 	block_add_to_undo--;
24811 	insert_text(str.c_str());
24812 	if(!only_one_value) {
24813 		execute_expression();
24814 	} else if(rpn_mode) {
24815 		execute_expression();
24816 		block_add_to_undo++;
24817 		insert_text(str_sign.c_str());
24818 		block_add_to_undo--;
24819 		execute_expression();
24820 	}
24821 
24822 	if(persistent_keypad) gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(historyview)));
24823 
24824 }
24825 
on_button_history_add_clicked(GtkButton *,gpointer)24826 void on_button_history_add_clicked(GtkButton*, gpointer) {
24827 	history_operator(expression_add_sign());
24828 }
on_button_history_sub_clicked(GtkButton *,gpointer)24829 void on_button_history_sub_clicked(GtkButton*, gpointer) {
24830 	history_operator(expression_sub_sign());
24831 }
on_button_history_times_clicked(GtkButton *,gpointer)24832 void on_button_history_times_clicked(GtkButton*, gpointer) {
24833 	history_operator(expression_times_sign());
24834 }
on_button_history_divide_clicked(GtkButton *,gpointer)24835 void on_button_history_divide_clicked(GtkButton*, gpointer) {
24836 	history_operator(expression_divide_sign());
24837 }
on_button_history_xy_clicked(GtkButton *,gpointer)24838 void on_button_history_xy_clicked(GtkButton*, gpointer) {
24839 	history_operator("^");
24840 }
on_button_history_sqrt_clicked(GtkButton *,gpointer)24841 void on_button_history_sqrt_clicked(GtkButton*, gpointer) {
24842 	if(b_busy) return;
24843 	vector<size_t> selected_indeces;
24844 	vector<int> selected_index_type;
24845 	process_history_selection(NULL, &selected_indeces, &selected_index_type);
24846 	if(selected_indeces.empty()) {
24847 		insertButtonFunction(CALCULATOR->f_sqrt);
24848 		return;
24849 	}
24850 	const ExpressionName *ename2 = &CALCULATOR->f_sqrt->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext);
24851 	string str = ename2->name;
24852 	str += "(";
24853 	if(selected_index_type[0] == INDEX_TYPE_TXT) {
24854 		int index = selected_indeces[0];
24855 		if(index > 0 && inhistory_type[index] == QALCULATE_HISTORY_TRANSFORMATION) index--;
24856 		str += inhistory[index];
24857 	} else {
24858 		const ExpressionName *ename = NULL;
24859 		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);
24860 		else ename = &f_answer->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext);
24861 		str += ename->name;
24862 		str += "(";
24863 		Number nr(selected_indeces[0], 1);
24864 		str += print_with_evalops(nr);
24865 		str += ")";
24866 	}
24867 	str += ")";
24868 	block_add_to_undo++;
24869 	gtk_text_buffer_set_text(expressionbuffer, "", -1);
24870 	block_add_to_undo--;
24871 	insert_text(str.c_str());
24872 	execute_expression();
24873 }
on_button_history_insert_value_clicked(GtkButton *,gpointer)24874 void on_button_history_insert_value_clicked(GtkButton*, gpointer) {
24875 	if(b_busy) return;
24876 	vector<size_t> selected_indeces;
24877 	vector<int> selected_index_type;
24878 	process_history_selection(NULL, &selected_indeces, &selected_index_type);
24879 	if(selected_indeces.empty() || selected_index_type[0] == INDEX_TYPE_TXT) return;
24880 	if(selected_indeces.size() > 1) {
24881 		selected_indeces.clear();
24882 		selected_index_type.clear();
24883 		process_history_selection(NULL, &selected_indeces, &selected_index_type, true);
24884 	}
24885 	const ExpressionName *ename = NULL;
24886 	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);
24887 	else ename = &f_answer->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext);
24888 	string str = ename->name;
24889 	str += "(";
24890 	for(size_t i = 0; i < selected_indeces.size(); i++) {
24891 		if(selected_index_type[i] != INDEX_TYPE_TXT) {
24892 			if(i > 0) {str += CALCULATOR->getComma(); str += ' ';}
24893 			Number nr(selected_indeces[i], 1);
24894 			str += print_with_evalops(nr);
24895 		}
24896 	}
24897 	str += ")";
24898 	if(rpn_mode) {
24899 		block_add_to_undo++;
24900 		insert_text(str.c_str());
24901 		block_add_to_undo--;
24902 		execute_expression();
24903 	} else {
24904 		insert_text(str.c_str());
24905 	}
24906 	if(persistent_keypad) gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(historyview)));
24907 }
on_button_history_insert_text_clicked(GtkButton *,gpointer)24908 void on_button_history_insert_text_clicked(GtkButton*, gpointer) {
24909 	if(b_busy) return;
24910 	vector<size_t> selected_rows;
24911 	process_history_selection(&selected_rows, NULL, NULL);
24912 	if(selected_rows.empty()) return;
24913 	int index = selected_rows[0];
24914 	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--;
24915 	else if((size_t) index < inhistory_type.size() - 1 && HISTORY_IS_PARSE(index) && inhistory_type[index + 1] == QALCULATE_HISTORY_EXPRESSION) index++;
24916 	insert_text(inhistory[index].c_str());
24917 	if(persistent_keypad) gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(historyview)));
24918 }
on_button_history_insert_parsed_text_clicked(GtkButton *,gpointer)24919 void on_button_history_insert_parsed_text_clicked(GtkButton*, gpointer) {
24920 	if(b_busy) return;
24921 	vector<size_t> selected_rows;
24922 	process_history_selection(&selected_rows, NULL, NULL);
24923 	if(selected_rows.empty()) return;
24924 	int index = selected_rows[0];
24925 	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--;
24926 	else if(index > 0 && inhistory_type[index] == QALCULATE_HISTORY_EXPRESSION && HISTORY_IS_PARSE(index - 1)) index--;
24927 	insert_text(inhistory[index].c_str());
24928 	if(persistent_keypad) gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(historyview)));
24929 }
history_copy(bool full_text)24930 void history_copy(bool full_text) {
24931 	if(b_busy) return;
24932 	vector<size_t> selected_rows;
24933 	process_history_selection(&selected_rows, NULL, NULL);
24934 	if(selected_rows.empty()) return;
24935 	if(!full_text && selected_rows.size() == 1) {
24936 		int index = selected_rows[0];
24937 		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--;
24938 		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++;
24939 		string copy_text = inhistory[index];
24940 		if(!copy_separator) {
24941 			remove_separator(copy_text);
24942 		}
24943 		gtk_clipboard_set_text(gtk_clipboard_get(gdk_atom_intern("CLIPBOARD", FALSE)), copy_text.c_str(), -1);
24944 	} else {
24945 		string str;
24946 		int hindex = 0;
24947 		for(size_t i = 0; i < selected_rows.size(); i++) {
24948 			if(i > 0) str += '\n';
24949 			hindex = selected_rows[i];
24950 			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++;
24951 			on_button_history_copy_add_hindex:
24952 			bool add_parse = false;
24953 			switch(inhistory_type[hindex]) {
24954 				case QALCULATE_HISTORY_EXPRESSION: {
24955 					if(i > 0) str += '\n';
24956 					str += inhistory[hindex];
24957 					add_parse = true;
24958 					break;
24959 				}
24960 				case QALCULATE_HISTORY_REGISTER_MOVED: {
24961 					if(i > 0) str += '\n';
24962 					str += _("RPN Register Moved");
24963 					add_parse = true;
24964 					break;
24965 				}
24966 				case QALCULATE_HISTORY_RPN_OPERATION: {
24967 					if(i > 0) str += '\n';
24968 					str += _("RPN Operation");
24969 					add_parse = true;
24970 					break;
24971 				}
24972 				case QALCULATE_HISTORY_TRANSFORMATION: {
24973 					str += inhistory[hindex];
24974 					str += ": ";
24975 					if(hindex > 0 && (inhistory_type[hindex - 1] == QALCULATE_HISTORY_RESULT || inhistory_type[hindex - 1] == QALCULATE_HISTORY_RESULT_APPROXIMATE)) {
24976 						hindex--;
24977 						goto on_button_history_copy_add_hindex;
24978 					}
24979 					break;
24980 				}
24981 				case QALCULATE_HISTORY_PARSE: {str += " ";}
24982 				case QALCULATE_HISTORY_RESULT: {
24983 					str += "= ";
24984 					str += inhistory[hindex];
24985 					break;
24986 				}
24987 				case QALCULATE_HISTORY_PARSE_APPROXIMATE: {str += " ";}
24988 				case QALCULATE_HISTORY_RESULT_APPROXIMATE: {
24989 					if(printops.use_unicode_signs && can_display_unicode_string_function(SIGN_ALMOST_EQUAL, (void*) historyview)) {
24990 						str += SIGN_ALMOST_EQUAL " ";
24991 					} else {
24992 						str += "= ";
24993 						str += _("approx.");
24994 						str += " ";
24995 					}
24996 					str += inhistory[hindex];
24997 					break;
24998 				}
24999 				case QALCULATE_HISTORY_PARSE_WITHEQUALS: {
25000 					str += " ";
25001 					str += inhistory[hindex];
25002 					break;
25003 				}
25004 				case QALCULATE_HISTORY_MESSAGE: {}
25005 				case QALCULATE_HISTORY_WARNING: {}
25006 				case QALCULATE_HISTORY_ERROR: {}
25007 				case QALCULATE_HISTORY_OLD: {
25008 					str += inhistory[hindex];
25009 					break;
25010 				}
25011 				case QALCULATE_HISTORY_BOOKMARK: {break;}
25012 			}
25013 			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)) {
25014 				hindex--;
25015 				goto on_button_history_copy_add_hindex;
25016 			}
25017 		}
25018 		if(!copy_separator) {
25019 			remove_separator(str);
25020 		}
25021 		gtk_clipboard_set_text(gtk_clipboard_get(gdk_atom_intern("CLIPBOARD", FALSE)), str.c_str(), -1);
25022 	}
25023 	if(persistent_keypad) gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(historyview)));
25024 }
on_button_history_copy_clicked(GtkButton *,gpointer)25025 void on_button_history_copy_clicked(GtkButton*, gpointer) {
25026 	history_copy(false);
25027 }
25028 bool history_protected_by_bookmark(size_t hi);
25029 bool history_protected(size_t hi);
on_popup_menu_item_history_clear_activate(GtkMenuItem *,gpointer)25030 void on_popup_menu_item_history_clear_activate(GtkMenuItem*, gpointer) {
25031 	if(b_busy) return;
25032 	gtk_list_store_clear(historystore);
25033 	bool b_protected = false;
25034 	for(size_t i = inhistory.size(); i > 0;) {
25035 		--i;
25036 		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) {
25037 			b_protected = (inhistory_type[i] != QALCULATE_HISTORY_OLD && (inhistory_protected[i] || history_protected_by_bookmark(i)));
25038 		}
25039 		if(!b_protected && inhistory_type[i] != QALCULATE_HISTORY_BOOKMARK) {
25040 			inhistory.erase(inhistory.begin() + i);
25041 			inhistory_type.erase(inhistory_type.begin() + i);
25042 			inhistory_protected.erase(inhistory_protected.begin() + i);
25043 			inhistory_value.erase(inhistory_value.begin() + i);
25044 		}
25045 	}
25046 	current_inhistory_index = inhistory.size() - 1;
25047 	history_index = -1;
25048 	initial_inhistory_index = inhistory.size() - 1;
25049 	on_expressionbuffer_changed(NULL, NULL);
25050 	reload_history();
25051 }
on_popup_menu_item_history_movetotop_activate(GtkMenuItem *,gpointer)25052 void on_popup_menu_item_history_movetotop_activate(GtkMenuItem*, gpointer) {
25053 	if(b_busy) return;
25054 	GtkTreeModel *model;
25055 	GtkTreeIter iter, iter_first;
25056 	GList *selected_list;
25057 	gint hindex = -1, hindex2 = -1;
25058 	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(historyview));
25059 	selected_list = gtk_tree_selection_get_selected_rows(select, &model);
25060 	if(!selected_list) return;
25061 	GList *list_i = g_list_last(selected_list);
25062 	vector<int> indexes;
25063 	while(list_i) {
25064 		gtk_tree_model_get_iter(model, &iter, (GtkTreePath*) list_i->data);
25065 		gtk_tree_model_get(model, &iter, 1, &hindex, -1);
25066 		list_i = list_i->prev;
25067 		if(hindex >= 0) {
25068 			if(inhistory_type[hindex] == QALCULATE_HISTORY_OLD) {
25069 				indexes.push_back(hindex);
25070 				gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
25071 			} else {
25072 				iter_first = iter;
25073 				while(gtk_tree_model_iter_next(model, &iter)) {
25074 					gtk_tree_model_get(model, &iter, 1, &hindex, -1);
25075 					if(hindex < 0 || ITEM_IS_EXPRESSION(hindex) || inhistory_type[hindex] == QALCULATE_HISTORY_OLD || inhistory_type[hindex] == QALCULATE_HISTORY_BOOKMARK) {
25076 						if(hindex < 0) {
25077 							gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
25078 						}
25079 						break;
25080 					}
25081 					iter_first = iter;
25082 				}
25083 				iter = iter_first;
25084 				bool b2 = true;
25085 				do {
25086 					if(list_i) {
25087 						GtkTreePath *path = gtk_tree_model_get_path(model, &iter);
25088 						if(gtk_tree_path_compare(path, (GtkTreePath*) list_i->data) == 0) list_i = list_i->prev;
25089 						gtk_tree_path_free(path);
25090 					}
25091 					gtk_tree_model_get(model, &iter, 1, &hindex, -1);
25092 					if(inhistory_type[hindex] == QALCULATE_HISTORY_TRANSFORMATION) indexes.push_back(hindex - 1);
25093 					indexes.push_back(hindex);
25094 					if(HISTORY_IS_MESSAGE(hindex) && ITEM_IS_EXPRESSION(hindex)) {indexes.push_back(hindex + 1); hindex++;}
25095 					if(HISTORY_IS_PARSE(hindex)) {indexes.push_back(hindex + 1); hindex++;}
25096 					GtkTreeIter iter2 = iter;
25097 					b2 = gtk_tree_model_iter_previous(model, &iter2);
25098 					gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
25099 					if(hindex < 0 || ITEM_IS_EXPRESSION(hindex) || inhistory_type[hindex] == QALCULATE_HISTORY_OLD || inhistory_type[hindex] == QALCULATE_HISTORY_BOOKMARK) {
25100 						if(hindex >= 0 && inhistory_type[hindex] != QALCULATE_HISTORY_BOOKMARK && b2) {
25101 							gtk_tree_model_get(model, &iter2, 1, &hindex, -1);
25102 							if(hindex < 0 || inhistory_type[hindex] != QALCULATE_HISTORY_BOOKMARK) {
25103 								break;
25104 							}
25105 						} else {
25106 							break;
25107 						}
25108 					}
25109 					iter = iter2;
25110 				} while(b2);
25111 			}
25112 		} else {
25113 			gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
25114 		}
25115 	}
25116 	unordered_map<int, int> new_indexes;
25117 	hindex2 = -1;
25118 	int n = 0;
25119 	for(size_t i = 0; i < indexes.size(); i++) {
25120 		hindex = indexes[i];
25121 		if(hindex >= 0) {
25122 			while(hindex2 >= 0 && hindex2 < hindex) {
25123 				new_indexes[hindex2] = hindex2 - n;
25124 				hindex2++;
25125 			}
25126 			n++;
25127 			hindex2 = hindex + 1;
25128 		}
25129 	}
25130 	while(hindex2 >= 0 && hindex2 < (gint) inhistory.size()) {
25131 		new_indexes[hindex2] = hindex2 - n;
25132 		hindex2++;
25133 	}
25134 	hindex2 = indexes[0];
25135 	if(gtk_tree_model_get_iter_first(model, &iter)) {
25136 		do {
25137 			gtk_tree_model_get(model, &iter, 1, &hindex, -1);
25138 			if(hindex >= 0) {
25139 				if(hindex < hindex2) break;
25140 				gtk_list_store_set(GTK_LIST_STORE(model), &iter, 1, new_indexes[hindex], -1);
25141 			}
25142 		} while(gtk_tree_model_iter_next(model, &iter));
25143 	}
25144 	hindex2 = (gint) inhistory.size() - indexes.size() + 1;
25145 	for(size_t i = 0; i < indexes.size(); i++) {
25146 		hindex = indexes[i];
25147 		inhistory.push_back(inhistory[hindex]);
25148 		inhistory_protected.push_back(inhistory_protected[hindex]);
25149 		inhistory_type.push_back(inhistory_type[hindex]);
25150 		inhistory_value.push_back(inhistory_value[hindex]);
25151 	}
25152 	for(size_t i = indexes.size() - 1; ; i--) {
25153 		hindex = indexes[i];
25154 		inhistory.erase(inhistory.begin() + hindex);
25155 		inhistory_protected.erase(inhistory_protected.begin() + hindex);
25156 		inhistory_type.erase(inhistory_type.begin() + hindex);
25157 		inhistory_value.erase(inhistory_value.begin() + hindex);
25158 		if(i == 0) break;
25159 	}
25160 	current_inhistory_index = inhistory.size() - 1;
25161 	history_index = -1;
25162 	initial_inhistory_index = inhistory.size() - 1;
25163 	on_expressionbuffer_changed(NULL, NULL);
25164 	reload_history(hindex2);
25165 	g_list_free_full(selected_list, (GDestroyNotify) gtk_tree_path_free);
25166 	if(persistent_keypad) gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(historyview)));
25167 }
on_popup_menu_item_history_delete_activate(GtkMenuItem *,gpointer)25168 void on_popup_menu_item_history_delete_activate(GtkMenuItem*, gpointer) {
25169 	if(b_busy) return;
25170 	GtkTreeModel *model;
25171 	GtkTreeIter iter, iter2, iter3;
25172 	GList *selected_list;
25173 	gint hindex = -1, hindex2 = -1;
25174 	bool del_prev = false;
25175 	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(historyview));
25176 	selected_list = gtk_tree_selection_get_selected_rows(select, &model);
25177 	if(!selected_list) return;
25178 	GList *list_i = g_list_last(selected_list);
25179 	vector<int> indexes;
25180 	while(list_i || del_prev) {
25181 		if(list_i) {
25182 			gtk_tree_model_get_iter(model, &iter, (GtkTreePath*) list_i->data);
25183 			gtk_tree_model_get(model, &iter, 1, &hindex, -1);
25184 		}
25185 		if(del_prev && (!list_i || hindex != hindex2)) {
25186 			gtk_list_store_remove(GTK_LIST_STORE(model), &iter2);
25187 			if(HISTORY_IS_EXPRESSION(hindex2)) indexes.push_back(hindex2 - 1);
25188 			indexes.push_back(hindex2);
25189 			if(HISTORY_IS_PARSE(hindex2)) {indexes.push_back(hindex2 + 1); hindex2++;}
25190 			if(hindex2 + 1 != hindex && (size_t) hindex2 + 1 < inhistory.size() && inhistory_type[hindex2 + 1] == QALCULATE_HISTORY_BOOKMARK) {
25191 				if(gtk_tree_model_iter_previous(model, &iter2)) {
25192 					indexes.push_back(hindex2);
25193 					gtk_list_store_remove(GTK_LIST_STORE(model), &iter2);
25194 				}
25195 			}
25196 		}
25197 		if(!list_i) break;
25198 		del_prev = false;
25199 		if(hindex >= 0 && (ITEM_IS_EXPRESSION(hindex) || inhistory_type[hindex] == QALCULATE_HISTORY_BOOKMARK)) {
25200 			iter3 = iter;
25201 			if(inhistory_type[hindex] == QALCULATE_HISTORY_BOOKMARK) gtk_tree_model_iter_next(model, &iter3);
25202 			bool b = false;
25203 			while(gtk_tree_model_iter_next(model, &iter3)) {
25204 				gtk_tree_model_get(model, &iter3, 1, &hindex2, -1);
25205 				if(hindex2 >= 0 && (ITEM_IS_EXPRESSION(hindex2) || inhistory_type[hindex2] == QALCULATE_HISTORY_OLD)) break;
25206 				b = true;
25207 				iter2 = iter3;
25208 			}
25209 			if(b) {
25210 				while(true) {
25211 					gtk_tree_model_get(model, &iter2, 1, &hindex2, -1);
25212 					if(hindex2 == hindex) break;
25213 					if(hindex2 >= 0) {
25214 						if(inhistory_type[hindex2] == QALCULATE_HISTORY_TRANSFORMATION) indexes.push_back(hindex2 - 1);
25215 						indexes.push_back(hindex2);
25216 					}
25217 					iter3 = iter2;
25218 					gtk_tree_model_iter_previous(model, &iter2);
25219 					gtk_list_store_remove(GTK_LIST_STORE(model), &iter3);
25220 				}
25221 			}
25222 			if(HISTORY_IS_EXPRESSION(hindex)) indexes.push_back(hindex - 1);
25223 		} else if(hindex >= 0 && inhistory_type[hindex] != QALCULATE_HISTORY_OLD) {
25224 			iter2 = iter;
25225 			if(gtk_tree_model_iter_next(model, &iter2)) {
25226 				gtk_tree_model_get(model, &iter2, 1, &hindex2, -1);
25227 				if(hindex2 < 0 || ITEM_IS_EXPRESSION(hindex2) || inhistory_type[hindex2] == QALCULATE_HISTORY_OLD) {
25228 					iter2 = iter;
25229 					if(gtk_tree_model_iter_previous(model, &iter2)) {
25230 						gtk_tree_model_get(model, &iter2, 1, &hindex2, -1);
25231 						if(hindex2 >= 0 && (ITEM_IS_EXPRESSION(hindex2) || inhistory_type[hindex2] == QALCULATE_HISTORY_OLD)) {
25232 							del_prev = true;
25233 						}
25234 					}
25235 				}
25236 			}
25237 		}
25238 		gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
25239 		if(hindex >= 0) {
25240 			if(inhistory_type[hindex] == QALCULATE_HISTORY_TRANSFORMATION) indexes.push_back(hindex - 1);
25241 			indexes.push_back(hindex);
25242 			if(HISTORY_IS_MESSAGE(hindex) && ITEM_IS_EXPRESSION(hindex)) {
25243 				indexes.push_back(hindex + 1); hindex++;
25244 				indexes.push_back(hindex + 1); hindex++;
25245 			}
25246 			if(HISTORY_IS_PARSE(hindex)) {indexes.push_back(hindex + 1); hindex++;}
25247 			if(!del_prev && (size_t) hindex + 1 < inhistory.size() && inhistory_type[hindex + 1] == QALCULATE_HISTORY_BOOKMARK) {
25248 				iter2 = iter;
25249 				if(gtk_tree_model_iter_previous(model, &iter2)) {
25250 					hindex2 = hindex + 1;
25251 					del_prev = true;
25252 				}
25253 			}
25254 		}
25255 		list_i = list_i->prev;
25256 	}
25257 	unordered_map<int, int> new_indexes;
25258 	hindex2 = -1;
25259 	int n = 0;
25260 	for(size_t i = 0; i < indexes.size(); i++) {
25261 		hindex = indexes[i];
25262 		if(hindex >= 0) {
25263 			while(hindex2 >= 0 && hindex2 < hindex) {
25264 				new_indexes[hindex2] = hindex2 - n;
25265 				hindex2++;
25266 			}
25267 			n++;
25268 			hindex2 = hindex + 1;
25269 		}
25270 	}
25271 	while(hindex2 >= 0 && hindex2 < (gint) inhistory.size()) {
25272 		new_indexes[hindex2] = hindex2 - n;
25273 		hindex2++;
25274 	}
25275 	hindex2 = indexes[0];
25276 	if(gtk_tree_model_get_iter_first(model, &iter)) {
25277 		do {
25278 			gtk_tree_model_get(model, &iter, 1, &hindex, -1);
25279 			if(hindex >= 0) {
25280 				if(hindex < hindex2) break;
25281 				gtk_list_store_set(GTK_LIST_STORE(model), &iter, 1, new_indexes[hindex], -1);
25282 			}
25283 		} while(gtk_tree_model_iter_next(model, &iter));
25284 	}
25285 	for(size_t i = indexes.size() - 1; ; i--) {
25286 		hindex = indexes[i];
25287 		inhistory.erase(inhistory.begin() + hindex);
25288 		inhistory_protected.erase(inhistory_protected.begin() + hindex);
25289 		inhistory_type.erase(inhistory_type.begin() + hindex);
25290 		inhistory_value.erase(inhistory_value.begin() + hindex);
25291 		if(i == 0) break;
25292 	}
25293 	initial_inhistory_index = inhistory.size() - 1;
25294 	if(new_indexes.count(current_inhistory_index) > 0) {
25295 		current_inhistory_index = new_indexes[current_inhistory_index];
25296 	} else {
25297 		current_inhistory_index = inhistory.size() - 1;
25298 		history_index = -1;
25299 		on_expressionbuffer_changed(NULL, NULL);
25300 	}
25301 	g_list_free_full(selected_list, (GDestroyNotify) gtk_tree_path_free);
25302 }
on_popup_menu_item_history_insert_value_activate(GtkMenuItem *,gpointer)25303 void on_popup_menu_item_history_insert_value_activate(GtkMenuItem*, gpointer) {
25304 	on_button_history_insert_value_clicked(NULL, NULL);
25305 }
on_popup_menu_item_history_insert_text_activate(GtkMenuItem *,gpointer)25306 void on_popup_menu_item_history_insert_text_activate(GtkMenuItem*, gpointer) {
25307 	on_button_history_insert_text_clicked(NULL, NULL);
25308 }
on_popup_menu_item_history_insert_parsed_text_activate(GtkMenuItem *,gpointer)25309 void on_popup_menu_item_history_insert_parsed_text_activate(GtkMenuItem*, gpointer) {
25310 	on_button_history_insert_parsed_text_clicked(NULL, NULL);
25311 }
on_popup_menu_item_history_copy_text_activate(GtkMenuItem *,gpointer)25312 void on_popup_menu_item_history_copy_text_activate(GtkMenuItem*, gpointer) {
25313 	history_copy(false);
25314 }
on_popup_menu_item_history_copy_full_text_activate(GtkMenuItem *,gpointer)25315 void on_popup_menu_item_history_copy_full_text_activate(GtkMenuItem*, gpointer) {
25316 	history_copy(true);
25317 }
find_history_bookmark(string str,GtkTreeIter * iter2)25318 bool find_history_bookmark(string str, GtkTreeIter *iter2) {
25319 	GtkTreeIter iter;
25320 	gint hindex = -1;
25321 	if(!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(historystore), &iter)) return false;
25322 	while(true) {
25323 		gtk_tree_model_get(GTK_TREE_MODEL(historystore), &iter, 1, &hindex, -1);
25324 		if(hindex >= 0 && inhistory_type[hindex] == QALCULATE_HISTORY_BOOKMARK && inhistory[hindex] == str) {
25325 			*iter2 = iter;
25326 			return true;
25327 		}
25328 		if(!gtk_tree_model_iter_next(GTK_TREE_MODEL(historystore), &iter)) break;
25329 	}
25330 	return false;
25331 }
goto_history_bookmark(GtkMenuItem * w,gpointer)25332 void goto_history_bookmark(GtkMenuItem *w, gpointer) {
25333 	string str = gtk_menu_item_get_label(w);
25334 	if(history_bookmark_titles.count(str) > 0) str = history_bookmarks[history_bookmark_titles[str]];
25335 	GtkTreeIter iter;
25336 	if(find_history_bookmark(str, &iter)) {
25337 		GtkTreePath *path = gtk_tree_model_get_path(GTK_TREE_MODEL(historystore), &iter);
25338 		gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(historyview), path, history_index_column, TRUE, 0.0, 0.0);
25339 		gtk_tree_path_free(path);
25340 	}
25341 }
remove_history_bookmark(string str)25342 void remove_history_bookmark(string str) {
25343 	for(vector<string>::iterator it = history_bookmarks.begin(); it != history_bookmarks.end(); ++it) {
25344 		if(equalsIgnoreCase(str, *it)) {
25345 			history_bookmarks.erase(it);
25346 			break;
25347 		}
25348 	}
25349 	GtkTreeIter iter;
25350 	gint hindex = 0;
25351 	if(!find_history_bookmark(str, &iter)) return;
25352 	gtk_tree_model_get(GTK_TREE_MODEL(historystore), &iter, 1, &hindex, -1);
25353 	inhistory.erase(inhistory.begin() + hindex);
25354 	inhistory_protected.erase(inhistory_protected.begin() + hindex);
25355 	inhistory_type.erase(inhistory_type.begin() + hindex);
25356 	inhistory_value.erase(inhistory_value.begin() + hindex);
25357 	GtkTreeIter history_iter = iter;
25358 	if(gtk_tree_model_iter_next(GTK_TREE_MODEL(historystore), &history_iter)) {
25359 		gtk_tree_model_get(GTK_TREE_MODEL(historystore), &history_iter, 1, &hindex, -1);
25360 		if(hindex >= 0 && !history_protected(hindex)) {
25361 			gchar *gstr;
25362 			gtk_tree_model_get(GTK_TREE_MODEL(historystore), &history_iter, 0, &gstr, -1);
25363 			string str = gstr;
25364 			size_t i = str.rfind("<span size=\"small\"><sup> ");
25365 			if(i == string::npos) i = str.rfind("<span size=\"x-small\"><sup> ");
25366 			if(i != string::npos) str = str.substr(0, i);
25367 			gtk_list_store_set(historystore, &history_iter, 0, str.c_str(), -1);
25368 			g_free(gstr);
25369 		}
25370 	}
25371 	history_iter = iter;
25372 	while(gtk_tree_model_iter_previous(GTK_TREE_MODEL(historystore), &history_iter)) {
25373 		gtk_tree_model_get(GTK_TREE_MODEL(historystore), &history_iter, 1, &hindex, -1);
25374 		if(hindex >= 0) gtk_list_store_set(historystore, &history_iter, 1, hindex - 1, -1);
25375 	}
25376 	gtk_list_store_remove(historystore, &iter);
25377 }
add_history_bookmark(string history_message)25378 void add_history_bookmark(string history_message) {
25379 	GtkTreeModel *model;
25380 	GtkTreeIter iter;
25381 	GList *selected_list;
25382 	gint hindex = -1;
25383 	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(historyview));
25384 	selected_list = gtk_tree_selection_get_selected_rows(select, &model);
25385 	if(!selected_list) return;
25386 	gtk_tree_model_get_iter(model, &iter, (GtkTreePath*) selected_list->data);
25387 	while(true) {
25388 		gtk_tree_model_get(model, &iter, 1, &hindex, -1);
25389 		if(hindex >= 0 && ITEM_IS_EXPRESSION(hindex)) break;
25390 		if((hindex >= 0 && inhistory_type[hindex] == QALCULATE_HISTORY_OLD) || !gtk_tree_model_iter_previous(model, &iter)) {
25391 			hindex = -1;
25392 			break;
25393 		}
25394 	}
25395 	if(hindex >= 0) {
25396 		bool b = false;
25397 		for(vector<string>::iterator it = history_bookmarks.begin(); it != history_bookmarks.end(); ++it) {
25398 			if(string_is_less(history_message, *it)) {
25399 				history_bookmarks.insert(it, history_message);
25400 				b = true;
25401 				break;
25402 			}
25403 		}
25404 		if(!b) history_bookmarks.push_back(history_message);
25405 		if(HISTORY_IS_PARSE(hindex)) hindex++;
25406 		hindex++;
25407 		inhistory.insert(inhistory.begin() + hindex, history_message);
25408 		inhistory_type.insert(inhistory_type.begin() + hindex, QALCULATE_HISTORY_BOOKMARK);
25409 		inhistory_protected.insert(inhistory_protected.begin() + hindex, false);
25410 		inhistory_value.insert(inhistory_value.begin() + hindex, 0);
25411 		add_line_breaks(history_message, false);
25412 		string history_str = "<span foreground=\"";
25413 		history_str += history_bookmark_color;
25414 		history_str += "\">";
25415 		history_str += fix_history_string(history_message);
25416 		history_str += ":";
25417 		history_str += "</span>";
25418 		gchar *gstr;
25419 		gtk_tree_model_get(model, &iter, 0, &gstr, -1);
25420 		string str = gstr;
25421 		if(str.find("<span size=\"x-small\"><sup> ") == string::npos && str.rfind("<span size=\"small\"><sup> ") == string::npos) {
25422 			if(can_display_unicode_string_function_exact("��", historyview)) str += "<span size=\"small\"><sup> ��</sup></span>";
25423 			else str += "<span size=\"x-small\"><sup> P</sup></span>";
25424 			gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, str.c_str(), -1);
25425 		}
25426 		g_free(gstr);
25427 		gtk_list_store_insert_before(historystore, &iter, &iter);
25428 		while(gtk_events_pending()) gtk_main_iteration();
25429 		GtkTreePath *path = gtk_tree_model_get_path(model, &iter);
25430 		gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(historyview), path, NULL, FALSE, 0, 0);
25431 		gtk_tree_path_free(path);
25432 		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);
25433 		while(gtk_tree_model_iter_previous(GTK_TREE_MODEL(historystore), &iter)) {
25434 			gtk_tree_model_get(GTK_TREE_MODEL(historystore), &iter, 1, &hindex, -1);
25435 			if(hindex >= 0) gtk_list_store_set(historystore, &iter, 1, hindex + 1, -1);
25436 		}
25437 	}
25438 	on_expressionbuffer_changed(expressionbuffer, NULL);
25439 	g_list_free_full(selected_list, (GDestroyNotify) gtk_tree_path_free);
25440 }
25441 GtkWidget *history_search_dialog = NULL;
25442 GtkWidget *history_search_entry = NULL;
on_history_search_response(GtkDialog * w,gint reponse_id,gpointer)25443 void on_history_search_response(GtkDialog *w, gint reponse_id, gpointer) {
25444 	if(reponse_id == GTK_RESPONSE_ACCEPT) {
25445 		if(inhistory.empty()) return;
25446 		string str = gtk_entry_get_text(GTK_ENTRY(history_search_entry));
25447 		GtkTreeIter iter;
25448 		GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(historyview));
25449 		GList *selected_list = gtk_tree_selection_get_selected_rows(select, NULL);
25450 		GList *selected = NULL;
25451 		if(selected_list) selected = g_list_last(selected_list);
25452 		gint hi_first = inhistory.size() - 1;
25453 		int b_wrap = -1;
25454 		if(selected) {
25455 			gtk_tree_model_get_iter(GTK_TREE_MODEL(historystore), &iter, (GtkTreePath*) selected->data);
25456 			while(gtk_tree_model_iter_next(GTK_TREE_MODEL(historystore), &iter)) {
25457 				gtk_tree_model_get(GTK_TREE_MODEL(historystore), &iter, 1, &hi_first, -1);
25458 				if(hi_first >= 0) {
25459 					b_wrap = 0;
25460 					break;
25461 				}
25462 			}
25463 			if(hi_first < 0) hi_first = inhistory.size() - 1;
25464 		}
25465 		if(!selected) {
25466 			if(!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(historystore), &iter)) {
25467 				g_list_free_full(selected_list, (GDestroyNotify) gtk_tree_path_free);
25468 				return;
25469 			}
25470 		}
25471 		for(gint i = hi_first; ; i--) {
25472 			if(b_wrap == 1 && i == hi_first) {
25473 				break;
25474 			} else if(inhistory[(size_t) i].find(str) != string::npos) {
25475 				do {
25476 					gint hi = -1;
25477 					gtk_tree_model_get(GTK_TREE_MODEL(historystore), &iter, 1, &hi, -1);
25478 					if(hi >= 0 && hi <= i) {
25479 						GtkTreePath *path = gtk_tree_model_get_path(GTK_TREE_MODEL(historystore), &iter);
25480 						gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(historyview), path, history_index_column, FALSE, 0.0, 0.0);
25481 						gtk_tree_selection_unselect_all(select);
25482 						gtk_tree_selection_select_iter(select, &iter);
25483 						gtk_tree_path_free(path);
25484 						break;
25485 					}
25486 				} while(gtk_tree_model_iter_next(GTK_TREE_MODEL(historystore), &iter));
25487 				break;
25488 			} else if(i == 0) {
25489 				if(b_wrap == 0) {
25490 					b_wrap = 1;
25491 					i = inhistory.size() - 1;
25492 					gtk_tree_model_get_iter_first(GTK_TREE_MODEL(historystore), &iter);
25493 				} else {
25494 					break;
25495 				}
25496 			}
25497 		}
25498 		g_list_free_full(selected_list, (GDestroyNotify) gtk_tree_path_free);
25499 	} else {
25500 		history_search_dialog = NULL;
25501 		gtk_widget_destroy(GTK_WIDGET(w));
25502 	}
25503 }
on_history_search_activate(GtkEntry *,gpointer)25504 void on_history_search_activate(GtkEntry*, gpointer) {
25505 	on_history_search_response(GTK_DIALOG(history_search_dialog), GTK_RESPONSE_ACCEPT, NULL);
25506 }
on_history_search_changed(GtkEditable *,gpointer)25507 void on_history_search_changed(GtkEditable*, gpointer) {
25508 	gtk_widget_set_sensitive(gtk_dialog_get_widget_for_response(GTK_DIALOG(history_search_dialog), GTK_RESPONSE_ACCEPT), strlen(gtk_entry_get_text(GTK_ENTRY(history_search_entry))) > 0);
25509 }
on_popup_menu_item_history_search_activate(GtkMenuItem *,gpointer)25510 void on_popup_menu_item_history_search_activate(GtkMenuItem*, gpointer) {
25511 	set_minimal_mode(false);
25512 	gtk_expander_set_expanded(GTK_EXPANDER(expander_history), TRUE);
25513 	if(history_search_dialog) {
25514 		gtk_widget_show(history_search_dialog);
25515 		gtk_window_present_with_time(GTK_WINDOW(history_search_dialog), GDK_CURRENT_TIME);
25516 		gtk_widget_grab_focus(history_search_entry);
25517 		return;
25518 	}
25519 	history_search_dialog = gtk_dialog_new_with_buttons(_("Search"), GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")), (GtkDialogFlags) GTK_DIALOG_DESTROY_WITH_PARENT, _("_Close"), GTK_RESPONSE_REJECT, _("_Search"), GTK_RESPONSE_ACCEPT, NULL);
25520 	gtk_container_set_border_width(GTK_CONTAINER(history_search_dialog), 6);
25521 	GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 12);
25522 	gtk_container_set_border_width(GTK_CONTAINER(hbox), 6);
25523 	gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(history_search_dialog))), hbox);
25524 	GtkWidget *label = gtk_label_new(_("Text"));
25525 	gtk_widget_set_halign(label, GTK_ALIGN_START);
25526 	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 0);
25527 	history_search_entry = gtk_entry_new();
25528 	gtk_entry_set_width_chars(GTK_ENTRY(history_search_entry), 35);
25529 	gtk_box_pack_end(GTK_BOX(hbox), history_search_entry, TRUE, TRUE, 0);
25530 	gtk_widget_set_sensitive(gtk_dialog_get_widget_for_response(GTK_DIALOG(history_search_dialog), GTK_RESPONSE_ACCEPT), FALSE);
25531 	g_signal_connect(G_OBJECT(history_search_entry), "activate", G_CALLBACK(on_history_search_activate), NULL);
25532 	g_signal_connect(G_OBJECT(history_search_dialog), "response", G_CALLBACK(on_history_search_response), NULL);
25533 	g_signal_connect(G_OBJECT(history_search_entry), "changed", G_CALLBACK(on_history_search_changed), NULL);
25534 	gtk_widget_show_all(history_search_dialog);
25535 	gtk_widget_grab_focus(history_search_entry);
25536 }
on_popup_menu_item_history_bookmark_activate(GtkMenuItem * w,gpointer)25537 void on_popup_menu_item_history_bookmark_activate(GtkMenuItem *w, gpointer) {
25538 	if(b_busy) return;
25539 	if(strcmp(gtk_menu_item_get_label(w), _("Remove Bookmark")) == 0) {
25540 		GtkTreeModel *model;
25541 		GtkTreeIter iter;
25542 		GList *selected_list;
25543 		gint hindex = -1;
25544 		GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(historyview));
25545 		selected_list = gtk_tree_selection_get_selected_rows(select, &model);
25546 		if(!selected_list) return;
25547 		gtk_tree_model_get_iter(model, &iter, (GtkTreePath*) selected_list->data);
25548 		while(true) {
25549 			gtk_tree_model_get(model, &iter, 1, &hindex, -1);
25550 			if(hindex >= 0 && inhistory_type[hindex] == QALCULATE_HISTORY_BOOKMARK) break;
25551 			if(!gtk_tree_model_iter_previous(model, &iter)) {
25552 				hindex = -1;
25553 				break;
25554 			}
25555 		}
25556 		if(hindex >= 0) {
25557 			for(vector<string>::iterator it = history_bookmarks.begin(); it != history_bookmarks.end(); ++it) {
25558 				if(equalsIgnoreCase(inhistory[hindex], *it)) {
25559 					history_bookmarks.erase(it);
25560 					break;
25561 				}
25562 			}
25563 			inhistory.erase(inhistory.begin() + hindex);
25564 			inhistory_protected.erase(inhistory_protected.begin() + hindex);
25565 			inhistory_type.erase(inhistory_type.begin() + hindex);
25566 			inhistory_value.erase(inhistory_value.begin() + hindex);
25567 			GtkTreeIter history_iter = iter;
25568 			if(gtk_tree_model_iter_next(GTK_TREE_MODEL(historystore), &history_iter)) {
25569 				gtk_tree_model_get(GTK_TREE_MODEL(historystore), &history_iter, 1, &hindex, -1);
25570 				if(!history_protected(hindex)) {
25571 					gchar *gstr;
25572 					gtk_tree_model_get(GTK_TREE_MODEL(historystore), &history_iter, 0, &gstr, -1);
25573 					string str = gstr;
25574 					size_t i = str.rfind("<span size=\"small\"><sup> ");
25575 					if(i == string::npos) i = str.rfind("<span size=\"x-small\"><sup> ");
25576 					if(i != string::npos) str = str.substr(0, i);
25577 					gtk_list_store_set(historystore, &history_iter, 0, str.c_str(), -1);
25578 					g_free(gstr);
25579 				}
25580 			}
25581 			history_iter = iter;
25582 			while(gtk_tree_model_iter_previous(GTK_TREE_MODEL(historystore), &history_iter)) {
25583 				gtk_tree_model_get(GTK_TREE_MODEL(historystore), &history_iter, 1, &hindex, -1);
25584 				if(hindex >= 0) gtk_list_store_set(historystore, &history_iter, 1, hindex - 1, -1);
25585 			}
25586 			gtk_list_store_remove(historystore, &iter);
25587 			on_expressionbuffer_changed(expressionbuffer, NULL);
25588 			if(persistent_keypad) gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(historyview)));
25589 		}
25590 		g_list_free_full(selected_list, (GDestroyNotify) gtk_tree_path_free);
25591 	} else {
25592 		string history_message;
25593 		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), _("_Cancel"), GTK_RESPONSE_REJECT, _("_OK"), GTK_RESPONSE_ACCEPT, NULL);
25594 		gtk_container_set_border_width(GTK_CONTAINER(dialog), 6);
25595 		GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 12);
25596 		gtk_container_set_border_width(GTK_CONTAINER(hbox), 6);
25597 		gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), hbox);
25598 		gtk_widget_show(hbox);
25599 		GtkWidget *label = gtk_label_new(_("Name"));
25600 		gtk_widget_set_halign(label, GTK_ALIGN_START);
25601 		gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 0);
25602 		gtk_widget_show(label);
25603 		GtkWidget *entry = gtk_entry_new();
25604 		gtk_entry_set_width_chars(GTK_ENTRY(entry), 35);
25605 		gtk_box_pack_end(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
25606 		gtk_widget_show(entry);
25607 		if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
25608 			string history_message = gtk_entry_get_text(GTK_ENTRY(entry));
25609 			remove_blank_ends(history_message);
25610 			bool b = false;
25611 			for(vector<string>::iterator it = history_bookmarks.begin(); it != history_bookmarks.end(); ++it) {
25612 				if(equalsIgnoreCase(history_message, *it)) {
25613 					b = true;
25614 					break;
25615 				}
25616 			}
25617 			if(b) {
25618 				if(ask_question(_("A bookmark with the selected name already exists.\nDo you want to overwrite it?"), dialog)) {
25619 					remove_history_bookmark(history_message);
25620 				} else {
25621 					history_message = "";
25622 				}
25623 			}
25624 			if(!history_message.empty()) {
25625 				add_history_bookmark(history_message);
25626 				if(persistent_keypad) gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(historyview)));
25627 			}
25628 		}
25629 		gtk_widget_destroy(dialog);
25630 	}
25631 }
history_protected_by_bookmark(size_t hi)25632 bool history_protected_by_bookmark(size_t hi) {
25633 	if(inhistory_type[hi] == QALCULATE_HISTORY_BOOKMARK) return true;
25634 	while(hi + 1 < inhistory_type.size() && HISTORY_NOT_EXPRESSION(hi)) {
25635 		hi++;
25636 		if(inhistory_type[hi] == QALCULATE_HISTORY_BOOKMARK) return true;
25637 	}
25638 	if(hi + 1 < inhistory_type.size() && inhistory_type[hi + 1] == QALCULATE_HISTORY_BOOKMARK) return true;
25639 	return false;
25640 }
history_protected(size_t hi)25641 bool history_protected(size_t hi) {
25642 	if(inhistory_protected[hi]) return true;
25643 	while(hi + 1 < inhistory_type.size() && HISTORY_NOT_EXPRESSION(hi) && inhistory_type[hi] != QALCULATE_HISTORY_OLD) {
25644 		hi++;
25645 	}
25646 	return inhistory_protected[hi];
25647 }
on_popup_menu_item_history_protect_toggled(GtkCheckMenuItem * w,gpointer)25648 void on_popup_menu_item_history_protect_toggled(GtkCheckMenuItem *w, gpointer) {
25649 	if(b_busy) return;
25650 	bool b = gtk_check_menu_item_get_active(w);
25651 	GtkTreeModel *model;
25652 	GtkTreeIter iter;
25653 	GList *selected_list;
25654 	gint hi = -1, hi_pre = 0, hi_pre_next;
25655 	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(historyview));
25656 	selected_list = gtk_tree_selection_get_selected_rows(select, &model);
25657 	GList *current_selected_list = selected_list;
25658 	while(current_selected_list) {
25659 		gtk_tree_model_get_iter(model, &iter, (GtkTreePath*) current_selected_list->data);
25660 		gtk_tree_model_get(model, &iter, 1, &hi, -1);
25661 		hi_pre_next = hi;
25662 		bool b2 = true;
25663 		while(hi >= 0 && (size_t) hi + 1 < inhistory_type.size() && ITEM_NOT_EXPRESSION(hi)) {
25664 			if(!gtk_tree_model_iter_previous(model, &iter)) {
25665 				b2 = false;
25666 				break;
25667 			}
25668 			gtk_tree_model_get(model, &iter, 1, &hi, -1);
25669 			if(hi == hi_pre) {
25670 				b2 = false;
25671 				break;
25672 			}
25673 		}
25674 		if(hi >= 0 && b2) {
25675 			if(HISTORY_IS_MESSAGE(hi)) hi++;
25676 			if(HISTORY_IS_PARSE(hi)) hi++;
25677 			if(b != inhistory_protected[hi]) {
25678 				inhistory_protected[hi] = b;
25679 				gchar *gstr;
25680 				gtk_tree_model_get(model, &iter, 0, &gstr, -1);
25681 				string str = gstr;
25682 				if((size_t) hi + 1 >= inhistory_type.size() || inhistory_type[hi + 1] != QALCULATE_HISTORY_BOOKMARK) {
25683 					if(b) {
25684 						if(str.find("<span size=\"x-small\"><sup> ") == string::npos && str.find("<span size=\"small\"><sup> ") == string::npos) {
25685 							if(can_display_unicode_string_function_exact("��", historyview)) str += "<span size=\"small\"><sup> ��</sup></span>";
25686 							else str += "<span size=\"x-small\"><sup> P</sup></span>";
25687 						}
25688 					} else {
25689 						size_t i = str.rfind("<span size=\"small\"><sup> ");
25690 						if(i == string::npos) i = str.rfind("<span size=\"x-small\"><sup> ");
25691 						if(i != string::npos) str = str.substr(0, i);
25692 					}
25693 					gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, str.c_str(), -1);
25694 				}
25695 				g_free(gstr);
25696 			}
25697 		}
25698 		hi_pre = hi_pre_next;
25699 		current_selected_list = current_selected_list->next;
25700 	}
25701 	g_list_free_full(selected_list, (GDestroyNotify) gtk_tree_path_free);
25702 	if(persistent_keypad) gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(historyview)));
25703 }
on_popup_menu_history_bookmark_update_activate(GtkMenuItem *,gpointer data)25704 void on_popup_menu_history_bookmark_update_activate(GtkMenuItem*, gpointer data) {
25705 	string str = gtk_menu_item_get_label(GTK_MENU_ITEM(data));
25706 	if(history_bookmark_titles.count(str) > 0) str = history_bookmarks[history_bookmark_titles[str]];
25707 	remove_history_bookmark(str);
25708 	add_history_bookmark(str);
25709 	gtk_menu_popdown(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_historyview")));
25710 	if(persistent_keypad) gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(historyview)));
25711 }
on_popup_menu_history_bookmark_delete_activate(GtkMenuItem *,gpointer data)25712 void on_popup_menu_history_bookmark_delete_activate(GtkMenuItem*, gpointer data) {
25713 	string str = gtk_menu_item_get_label(GTK_MENU_ITEM(data));
25714 	if(history_bookmark_titles.count(str) > 0) str = history_bookmarks[history_bookmark_titles[str]];
25715 	remove_history_bookmark(str);
25716 	gtk_menu_popdown(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_historyview")));
25717 	if(persistent_keypad) gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(historyview)));
25718 }
25719 
25720 gulong on_popup_menu_history_bookmark_update_activate_handler = 0, on_popup_menu_history_bookmark_delete_activate_handler = 0;
25721 
on_menu_history_bookmark_popup_menu(GtkWidget *,gpointer data)25722 gboolean on_menu_history_bookmark_popup_menu(GtkWidget*, gpointer data) {
25723 	if(b_busy) return TRUE;
25724 	vector<size_t> selected_rows;
25725 	process_history_selection(&selected_rows, NULL, NULL);
25726 	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);
25727 	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);
25728 	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);
25729 	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);
25730 	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);
25731 #if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 22
25732 	gtk_menu_popup_at_pointer(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_history_bookmark")), NULL);
25733 #else
25734 	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());
25735 #endif
25736 	return TRUE;
25737 }
25738 
on_menu_history_bookmark_button_press(GtkWidget * widget,GdkEventButton * event,gpointer data)25739 gboolean on_menu_history_bookmark_button_press(GtkWidget *widget, GdkEventButton *event, gpointer data) {
25740 	/* Ignore double-clicks and triple-clicks */
25741 	if(gdk_event_triggers_context_menu((GdkEvent *) event) && event->type == GDK_BUTTON_PRESS) {
25742 		on_menu_history_bookmark_popup_menu(widget, data);
25743 		return TRUE;
25744 	}
25745 	return FALSE;
25746 }
25747 
update_historyview_popup()25748 void update_historyview_popup() {
25749 	GtkTreeIter iter;
25750 	vector<size_t> selected_rows;
25751 	vector<size_t> selected_indeces;
25752 	vector<int> selected_index_type;
25753 	size_t hi = 0;
25754 	process_history_selection(&selected_rows, &selected_indeces, &selected_index_type);
25755 	if(selected_rows.size() == 1) {
25756 		hi = selected_rows[0];
25757 		if(HISTORY_IS_PARSE(hi)) {
25758 			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_history_insert_parsed_text")), TRUE);
25759 			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);
25760 		} else {
25761 			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_MESSAGE && inhistory_type[hi] != QALCULATE_HISTORY_BOOKMARK && inhistory_type[hi] != QALCULATE_HISTORY_RPN_OPERATION && inhistory_type[hi] != QALCULATE_HISTORY_REGISTER_MOVED);
25762 			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));
25763 		}
25764 	} else {
25765 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_history_insert_text")), FALSE);
25766 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_history_insert_parsed_text")), FALSE);
25767 	}
25768 	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);
25769 	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);
25770 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_history_copy_full_text")), !selected_rows.empty());
25771 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_history_movetotop")), !selected_rows.empty());
25772 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_history_delete")), !selected_rows.empty());
25773 	bool protected_by_bookmark = true, b_protected = true, b_old = false;
25774 	for(size_t i = 0; i < selected_rows.size(); i++) {
25775 		if(!b_old && inhistory_type[selected_rows[i]] == QALCULATE_HISTORY_OLD) {b_old = true; b_protected = false; break;}
25776 		if(b_protected) {
25777 			if(history_protected(selected_rows[i])) {
25778 				protected_by_bookmark = false;
25779 			} else if(!history_protected_by_bookmark(selected_rows[i])) {
25780 				protected_by_bookmark = false;
25781 				b_protected = false;
25782 			}
25783 		}
25784 	}
25785 	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);
25786 	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);
25787 	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);
25788 	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);
25789 	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 && (HISTORY_NOT_MESSAGE(hi) || ITEM_NOT_EXPRESSION(hi)));
25790 	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"));
25791 	else gtk_menu_item_set_label(GTK_MENU_ITEM(gtk_builder_get_object(main_builder, "popup_menu_item_history_bookmark")), _("Add Bookmark…"));
25792 	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));
25793 	gtk_container_foreach(GTK_CONTAINER(gtk_builder_get_object(main_builder, "popup_menu_history_bookmarks")), (GtkCallback) gtk_widget_destroy, NULL);
25794 	GtkWidget *item;
25795 	GtkWidget *sub = GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_history_bookmarks"));
25796 	history_bookmark_titles.clear();
25797 	for(size_t i = 0; i < history_bookmarks.size(); i++) {
25798 		if(history_bookmarks[i].length() > 70) {
25799 			string label = history_bookmarks[i].substr(0, 70);
25800 			label += "…";
25801 			MENU_ITEM(label.c_str(), goto_history_bookmark)
25802 			history_bookmark_titles[label] = i;
25803 		} else {
25804 			MENU_ITEM(history_bookmarks[i].c_str(), goto_history_bookmark)
25805 		}
25806 		g_signal_connect(G_OBJECT(item), "button-press-event", G_CALLBACK(on_menu_history_bookmark_button_press), (gpointer) item);
25807 		g_signal_connect(G_OBJECT(item), "popup-menu", G_CALLBACK(on_menu_history_bookmark_popup_menu), (gpointer) item);
25808 	}
25809 	if(history_bookmarks.empty()) {MENU_NO_ITEMS(_("No items found"))}
25810 }
on_historyview_button_press_event(GtkWidget *,GdkEventButton * event,gpointer)25811 gboolean on_historyview_button_press_event(GtkWidget*, GdkEventButton *event, gpointer) {
25812 	GtkTreePath *path = NULL;
25813 	GtkTreeSelection *select = NULL;
25814 	if(gdk_event_triggers_context_menu((GdkEvent*) event) && event->type == GDK_BUTTON_PRESS) {
25815 		if(b_busy) return TRUE;
25816 		if(gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(historyview), event->x, event->y, &path, NULL, NULL, NULL)) {
25817 			select = gtk_tree_view_get_selection(GTK_TREE_VIEW(historyview));
25818 			if(!gtk_tree_selection_path_is_selected(select, path)) {
25819 				gtk_tree_selection_unselect_all(select);
25820 				gtk_tree_selection_select_path(select, path);
25821 			}
25822 			gtk_tree_path_free(path);
25823 		}
25824 		update_historyview_popup();
25825 #if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 22
25826 		gtk_menu_popup_at_pointer(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_historyview")), (GdkEvent*) event);
25827 #else
25828 		gtk_menu_popup(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_historyview")), NULL, NULL, NULL, NULL, event->button, event->time);
25829 #endif
25830 		return TRUE;
25831 	}
25832 	return FALSE;
25833 }
25834 Unit *popup_convert_unit = NULL;
update_convert_popup()25835 void update_convert_popup() {
25836 	GtkTreeIter iter_sel;
25837 	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitSelector));
25838 	GtkTreeModel *model;
25839 	Unit *u_sel = popup_convert_unit;
25840 	if(!u_sel && gtk_tree_selection_get_selected(select, &model, &iter_sel)) gtk_tree_model_get(model, &iter_sel, 1, &u_sel, -1);
25841 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_convert_insert")), u_sel != NULL);
25842 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_convert_convert")), u_sel != NULL);
25843 }
on_popup_menu_convert_insert_activate(GtkMenuItem *,gpointer)25844 void on_popup_menu_convert_insert_activate(GtkMenuItem*, gpointer) {
25845 	GtkTreeIter iter_sel;
25846 	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitSelector));
25847 	GtkTreeModel *model;
25848 	Unit *u = popup_convert_unit;
25849 	if(!u && gtk_tree_selection_get_selected(select, &model, &iter_sel)) gtk_tree_model_get(model, &iter_sel, 1, &u, -1);
25850 	if(u) {
25851 		if(u->subtype() == SUBTYPE_COMPOSITE_UNIT) {
25852 			string str = ((CompositeUnit*) u)->print(true, printops.abbreviate_names, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) expressiontext);
25853 			if(printops.multiplication_sign == MULTIPLICATION_SIGN_DOT) gsub(saltdot, sdot, str);
25854 			insert_text(str.c_str());
25855 		} else {
25856 			insert_text(u->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, true, false, &can_display_unicode_string_function, (void*) expressiontext).name.c_str());
25857 		}
25858 		unit_inserted(u);
25859 	}
25860 }
on_popup_menu_convert_convert_activate(GtkMenuItem *,gpointer)25861 void on_popup_menu_convert_convert_activate(GtkMenuItem*, gpointer) {
25862 	GtkTreeIter iter_sel;
25863 	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnitSelector));
25864 	GtkTreeModel *model;
25865 	Unit *u = popup_convert_unit;
25866 	if(!u && gtk_tree_selection_get_selected(select, &model, &iter_sel)) gtk_tree_model_get(model, &iter_sel, 1, &u, -1);
25867 	if(u) {
25868 		keep_unit_selection = true;
25869 		for(size_t i = 0; i < CALCULATOR->units.size(); i++) {
25870 			if(CALCULATOR->units[i] == u) {
25871 				if(u->subtype() == SUBTYPE_COMPOSITE_UNIT) {
25872 					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());
25873 				} else {
25874 					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());
25875 				}
25876 				if(!block_unit_selector_convert) convert_from_convert_entry_unit();
25877 			}
25878 		}
25879 		keep_unit_selection = false;
25880 	}
25881 }
on_convert_treeview_unit_button_press_event(GtkWidget * w,GdkEventButton * event,gpointer)25882 gboolean on_convert_treeview_unit_button_press_event(GtkWidget *w, GdkEventButton *event, gpointer) {
25883 	GtkTreePath *path = NULL;
25884 	if(event->type == GDK_BUTTON_PRESS && event->button == 2) {
25885 		if(b_busy) return TRUE;
25886 		if(gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(w), event->x, event->y, &path, NULL, NULL, NULL)) {
25887 			GtkTreeIter iter;
25888 			if(gtk_tree_model_get_iter(tUnitSelector_store_filter, &iter, path)) {
25889 				Unit *u = NULL;
25890 				gtk_tree_model_get(tUnitSelector_store_filter, &iter, 1, &u, -1);
25891 				if(u) {
25892 					if(u->subtype() == SUBTYPE_COMPOSITE_UNIT) {
25893 						string str = ((CompositeUnit*) u)->print(true, printops.abbreviate_names, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) expressiontext);
25894 						if(printops.multiplication_sign == MULTIPLICATION_SIGN_DOT) gsub(saltdot, sdot, str);
25895 						insert_text(str.c_str());
25896 					} else {
25897 						insert_text(u->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, true, false, &can_display_unicode_string_function, (void*) expressiontext).name.c_str());
25898 					}
25899 					unit_inserted(u);
25900 				}
25901 				gtk_tree_path_free(path);
25902 				return TRUE;
25903 			}
25904 			gtk_tree_path_free(path);
25905 		}
25906 	} else if(gdk_event_triggers_context_menu((GdkEvent*) event) && event->type == GDK_BUTTON_PRESS) {
25907 		if(b_busy) return TRUE;
25908 		if(gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(w), event->x, event->y, &path, NULL, NULL, NULL)) {
25909 			GtkTreeIter iter;
25910 			if(gtk_tree_model_get_iter(tUnitSelector_store_filter, &iter, path)) {
25911 				gtk_tree_model_get(tUnitSelector_store_filter, &iter, 1, &popup_convert_unit, -1);
25912 			} else {
25913 				popup_convert_unit = NULL;
25914 			}
25915 			gtk_tree_path_free(path);
25916 		}
25917 
25918 		update_convert_popup();
25919 #if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 22
25920 		gtk_menu_popup_at_pointer(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_convert")), (GdkEvent*) event);
25921 #else
25922 		gtk_menu_popup(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_convert")), NULL, NULL, NULL, NULL, event->button, event->time);
25923 #endif
25924 		return TRUE;
25925 	}
25926 	return FALSE;
25927 }
on_convert_treeview_unit_popup_menu(GtkWidget *,gpointer)25928 gboolean on_convert_treeview_unit_popup_menu(GtkWidget*, gpointer) {
25929 	if(b_busy) return TRUE;
25930 	popup_convert_unit = NULL;
25931 	update_convert_popup();
25932 #if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 22
25933 	gtk_menu_popup_at_pointer(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_convert")), NULL);
25934 #else
25935 	gtk_menu_popup(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_convert")), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time());
25936 #endif
25937 	return TRUE;
25938 }
on_historyview_popup_menu(GtkWidget *,gpointer)25939 gboolean on_historyview_popup_menu(GtkWidget*, gpointer) {
25940 	if(b_busy) return TRUE;
25941 	update_historyview_popup();
25942 #if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 22
25943 	gtk_menu_popup_at_pointer(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_historyview")), NULL);
25944 #else
25945 	gtk_menu_popup(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_historyview")), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time());
25946 #endif
25947 	return TRUE;
25948 }
on_historyview_selection_changed(GtkTreeSelection *,gpointer)25949 void on_historyview_selection_changed(GtkTreeSelection*, gpointer) {
25950 	vector<size_t> selected_rows;
25951 	vector<size_t> selected_indeces;
25952 	vector<int> selected_index_type;
25953 	process_history_selection(&selected_rows, &selected_indeces, &selected_index_type);
25954 	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);
25955 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_history_insert_text")), selected_indeces.size() == 1);
25956 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_history_copy")), !selected_rows.empty());
25957 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_history_sqrt")), selected_indeces.size() <= 1);
25958 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_history_xy")), selected_indeces.size() <= 2);
25959 }
on_historyview_row_activated(GtkTreeView *,GtkTreePath * path,GtkTreeViewColumn * column,gpointer)25960 void on_historyview_row_activated(GtkTreeView*, GtkTreePath *path, GtkTreeViewColumn *column, gpointer) {
25961 	GtkTreeIter iter;
25962 	gint index = -1, hindex = -1;
25963 	if(!gtk_tree_model_get_iter(GTK_TREE_MODEL(historystore), &iter, path)) return;
25964 	gtk_tree_model_get(GTK_TREE_MODEL(historystore), &iter, 1, &hindex, 3, &index, -1);
25965 	if(index > 0 && hindex >= 0 && evalops.parse_options.functions_enabled && evalops.parse_options.base <= BASE_DECIMAL && evalops.parse_options.base > 0) {
25966 		const ExpressionName *ename = NULL;
25967 		switch(inhistory_type[(size_t) hindex]) {
25968 			case QALCULATE_HISTORY_RPN_OPERATION: {}
25969 			case QALCULATE_HISTORY_REGISTER_MOVED: {
25970 				if(hindex == 0 || column == history_index_column) {
25971 					ename = &f_expression->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext);
25972 				} else {
25973 					insert_text(inhistory[(size_t) hindex - 1].c_str());
25974 					return;
25975 				}
25976 				break;
25977 			}
25978 			case QALCULATE_HISTORY_PARSE: {}
25979 			case QALCULATE_HISTORY_PARSE_APPROXIMATE: {
25980 				if(column != history_index_column && (size_t) hindex < inhistory_type.size() - 1 && inhistory_type[hindex + 1] == QALCULATE_HISTORY_EXPRESSION) hindex++;
25981 			}
25982 			case QALCULATE_HISTORY_EXPRESSION: {
25983 				if(column == history_index_column) {
25984 					ename = &f_expression->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext);
25985 				} else {
25986 					insert_text(inhistory[(size_t) hindex].c_str());
25987 					return;
25988 				}
25989 				break;
25990 			}
25991 			default: {
25992 				ename = &f_answer->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext);
25993 			}
25994 		}
25995 		string str = ename->name;
25996 		str += "(";
25997 		Number nr(index, 1);
25998 		str += print_with_evalops(nr);
25999 		str += ")";
26000 		if(rpn_mode) {
26001 			block_add_to_undo++;
26002 			insert_text(str.c_str());
26003 			block_add_to_undo--;
26004 			execute_expression();
26005 		} else {
26006 			insert_text(str.c_str());
26007 		}
26008 	} else if(hindex >= 0) {
26009 		if(hindex > 0 && (inhistory_type[hindex] == QALCULATE_HISTORY_TRANSFORMATION || inhistory_type[hindex] == QALCULATE_HISTORY_RPN_OPERATION || inhistory_type[hindex] == QALCULATE_HISTORY_REGISTER_MOVED)) hindex--;
26010 		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++;
26011 		if(HISTORY_NOT_MESSAGE(hindex) && inhistory_type[hindex] != QALCULATE_HISTORY_BOOKMARK) {
26012 			if(rpn_mode && ITEM_NOT_EXPRESSION(hindex) && inhistory_type[hindex] != QALCULATE_HISTORY_OLD) {
26013 				block_add_to_undo++;
26014 				insert_text(inhistory[(size_t) hindex].c_str());
26015 				block_add_to_undo--;
26016 				execute_expression();
26017 			} else {
26018 				insert_text(inhistory[(size_t) hindex].c_str());
26019 			}
26020 		}
26021 	}
26022 	if(persistent_keypad) gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(historyview)));
26023 }
26024 
on_menu_item_manage_variables_activate(GtkMenuItem *,gpointer)26025 void on_menu_item_manage_variables_activate(GtkMenuItem*, gpointer) {
26026 	manage_variables();
26027 }
on_menu_item_manage_functions_activate(GtkMenuItem *,gpointer)26028 void on_menu_item_manage_functions_activate(GtkMenuItem*, gpointer) {
26029 	manage_functions();
26030 }
on_menu_item_manage_units_activate(GtkMenuItem *,gpointer)26031 void on_menu_item_manage_units_activate(GtkMenuItem*, gpointer) {
26032 	manage_units();
26033 }
26034 
on_menu_item_datasets_activate(GtkMenuItem *,gpointer)26035 void on_menu_item_datasets_activate(GtkMenuItem*, gpointer) {
26036 	GtkWidget *dialog = get_datasets_dialog();
26037 	gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")));
26038 	gtk_widget_show(dialog);
26039 	gtk_window_present_with_time(GTK_WINDOW(dialog), GDK_CURRENT_TIME);
26040 }
26041 
on_menu_item_import_csv_file_activate(GtkMenuItem *,gpointer)26042 void on_menu_item_import_csv_file_activate(GtkMenuItem*, gpointer) {
26043 	import_csv_file(GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")));
26044 }
26045 
on_menu_item_export_csv_file_activate(GtkMenuItem *,gpointer)26046 void on_menu_item_export_csv_file_activate(GtkMenuItem*, gpointer) {
26047 	export_csv_file(NULL, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")));
26048 }
26049 
on_expander_convert_activate(GtkExpander * o,gpointer)26050 void on_expander_convert_activate(GtkExpander *o, gpointer) {
26051 	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(main_builder, "convert_entry_unit")));
26052 }
on_menu_item_convert_to_unit_expression_activate(GtkMenuItem *,gpointer)26053 void on_menu_item_convert_to_unit_expression_activate(GtkMenuItem*, gpointer) {
26054 	gtk_expander_set_expanded(GTK_EXPANDER(expander_convert), TRUE);
26055 	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(main_builder, "convert_entry_unit")));
26056 }
on_menu_item_convert_to_best_unit_activate(GtkMenuItem *,gpointer)26057 void on_menu_item_convert_to_best_unit_activate(GtkMenuItem*, gpointer) {
26058 	executeCommand(COMMAND_CONVERT_OPTIMAL);
26059 }
on_menu_item_convert_to_base_units_activate(GtkMenuItem *,gpointer)26060 void on_menu_item_convert_to_base_units_activate(GtkMenuItem*, gpointer) {
26061 	executeCommand(COMMAND_CONVERT_BASE);
26062 }
26063 
on_menu_item_set_prefix_activate(GtkMenuItem *,gpointer user_data)26064 void on_menu_item_set_prefix_activate(GtkMenuItem*, gpointer user_data) {
26065 	result_prefix_changed((Prefix*) user_data);
26066 	focus_keeping_selection();
26067 }
26068 
on_menu_item_insert_date_activate(GtkMenuItem *,gpointer)26069 void on_menu_item_insert_date_activate(GtkMenuItem*, gpointer) {
26070 	GtkWidget *d = gtk_dialog_new_with_buttons(_("Select date"), GTK_WINDOW(mainwindow), (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT), _("_Cancel"), GTK_RESPONSE_CANCEL, _("_OK"), GTK_RESPONSE_OK, NULL);
26071 	GtkWidget *date_w = gtk_calendar_new();
26072 	string str = get_selected_expression_text(), str2;
26073 	CALCULATOR->separateToExpression(str, str2, evalops, true);
26074 	remove_blank_ends(str);
26075 	int b_quote = -1;
26076 	if(str.length() > 2 && ((str[0] == '\"' && str[str.length() - 1] == '\"') || (str[0] == '\'' && str[str.length() - 1] == '\''))) {
26077 		str = str.substr(1, str.length() - 2);
26078 		remove_blank_ends(str);
26079 		b_quote = 1;
26080 	}
26081 	if(!str.empty()) {
26082 		QalculateDateTime date;
26083 		if(date.set(str)) {
26084 			if(b_quote < 0) b_quote = 0;
26085 			gtk_calendar_select_month(GTK_CALENDAR(date_w), date.month() - 1, date.year());
26086 			gtk_calendar_select_day(GTK_CALENDAR(date_w), date.day());
26087 		}
26088 	}
26089 	gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(d))), date_w);
26090 	gtk_widget_show_all(d);
26091 	if(gtk_dialog_run(GTK_DIALOG(d)) == GTK_RESPONSE_OK) {
26092 		guint year = 0, month = 0, day = 0;
26093 		gtk_calendar_get_date(GTK_CALENDAR(date_w), &year, &month, &day);
26094 		gchar *gstr;
26095 		if(b_quote == 0) gstr = g_strdup_printf("%i-%02i-%02i", year, month + 1, day);
26096 		else gstr = g_strdup_printf("\"%i-%02i-%02i\"", year, month + 1, day);
26097 		insert_text(gstr);
26098 		g_free(gstr);
26099 	}
26100 	gtk_widget_destroy(d);
26101 }
26102 
on_menu_item_insert_matrix_activate(GtkMenuItem *,gpointer)26103 void on_menu_item_insert_matrix_activate(GtkMenuItem*, gpointer) {
26104 	string str = get_selected_expression_text(), str2;
26105 	CALCULATOR->separateToExpression(str, str2, evalops, true);
26106 	remove_blank_ends(str);
26107 	if(!str.empty()) {
26108 		MathStructure mstruct_sel;
26109 		CALCULATOR->beginTemporaryStopMessages();
26110 		CALCULATOR->parse(&mstruct_sel, CALCULATOR->unlocalizeExpression(str, evalops.parse_options), evalops.parse_options);
26111 		CALCULATOR->endTemporaryStopMessages();
26112 		if(mstruct_sel.isMatrix() && mstruct_sel[0].size() > 0) {
26113 			insert_matrix(&mstruct_sel, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")), false);
26114 			return;
26115 		}
26116 	}
26117 	insert_matrix(NULL, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")), false);
26118 }
on_menu_item_insert_vector_activate(GtkMenuItem *,gpointer)26119 void on_menu_item_insert_vector_activate(GtkMenuItem*, gpointer) {
26120 	string str = get_selected_expression_text(), str2;
26121 	CALCULATOR->separateToExpression(str, str2, evalops, true);
26122 	remove_blank_ends(str);
26123 	if(!str.empty()) {
26124 		MathStructure mstruct_sel;
26125 		CALCULATOR->beginTemporaryStopMessages();
26126 		CALCULATOR->parse(&mstruct_sel, CALCULATOR->unlocalizeExpression(str, evalops.parse_options), evalops.parse_options);
26127 		CALCULATOR->endTemporaryStopMessages();
26128 		if(mstruct_sel.isVector() && !mstruct_sel.isMatrix()) {
26129 			insert_matrix(&mstruct_sel, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")), true);
26130 			return;
26131 		}
26132 	}
26133 	insert_matrix(NULL, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")), true);
26134 }
26135 
update_assumptions_items()26136 void update_assumptions_items() {
26137 	block_expression_execution++;
26138 	set_assumptions_items(CALCULATOR->defaultAssumptions()->type(), CALCULATOR->defaultAssumptions()->sign());
26139 	block_expression_execution--;
26140 }
26141 
on_menu_item_assumptions_integer_activate(GtkMenuItem * w,gpointer)26142 void on_menu_item_assumptions_integer_activate(GtkMenuItem *w, gpointer) {
26143 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26144 	CALCULATOR->defaultAssumptions()->setType(ASSUMPTION_TYPE_INTEGER);
26145 	update_assumptions_items();
26146 	expression_calculation_updated();
26147 }
on_menu_item_assumptions_rational_activate(GtkMenuItem * w,gpointer)26148 void on_menu_item_assumptions_rational_activate(GtkMenuItem *w, gpointer) {
26149 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26150 	CALCULATOR->defaultAssumptions()->setType(ASSUMPTION_TYPE_RATIONAL);
26151 	update_assumptions_items();
26152 	expression_calculation_updated();
26153 }
on_menu_item_assumptions_real_activate(GtkMenuItem * w,gpointer)26154 void on_menu_item_assumptions_real_activate(GtkMenuItem *w, gpointer) {
26155 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26156 	CALCULATOR->defaultAssumptions()->setType(ASSUMPTION_TYPE_REAL);
26157 	update_assumptions_items();
26158 	expression_calculation_updated();
26159 }
on_menu_item_assumptions_complex_activate(GtkMenuItem * w,gpointer)26160 void on_menu_item_assumptions_complex_activate(GtkMenuItem *w, gpointer) {
26161 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26162 	CALCULATOR->defaultAssumptions()->setType(ASSUMPTION_TYPE_COMPLEX);
26163 	update_assumptions_items();
26164 	expression_calculation_updated();
26165 }
on_menu_item_assumptions_number_activate(GtkMenuItem * w,gpointer)26166 void on_menu_item_assumptions_number_activate(GtkMenuItem *w, gpointer) {
26167 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26168 	CALCULATOR->defaultAssumptions()->setType(ASSUMPTION_TYPE_NUMBER);
26169 	update_assumptions_items();
26170 	expression_calculation_updated();
26171 }
on_menu_item_assumptions_none_activate(GtkMenuItem * w,gpointer)26172 void on_menu_item_assumptions_none_activate(GtkMenuItem *w, gpointer) {
26173 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26174 	CALCULATOR->defaultAssumptions()->setType(ASSUMPTION_TYPE_NONE);
26175 	update_assumptions_items();
26176 	expression_calculation_updated();
26177 }
on_menu_item_assumptions_nonmatrix_activate(GtkMenuItem * w,gpointer)26178 void on_menu_item_assumptions_nonmatrix_activate(GtkMenuItem *w, gpointer) {
26179 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26180 	CALCULATOR->defaultAssumptions()->setType(ASSUMPTION_TYPE_NONMATRIX);
26181 	update_assumptions_items();
26182 	expression_calculation_updated();
26183 }
on_menu_item_assumptions_nonzero_activate(GtkMenuItem * w,gpointer)26184 void on_menu_item_assumptions_nonzero_activate(GtkMenuItem *w, gpointer) {
26185 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26186 	CALCULATOR->defaultAssumptions()->setSign(ASSUMPTION_SIGN_NONZERO);
26187 	update_assumptions_items();
26188 	expression_calculation_updated();
26189 }
on_menu_item_assumptions_positive_activate(GtkMenuItem * w,gpointer)26190 void on_menu_item_assumptions_positive_activate(GtkMenuItem *w, gpointer) {
26191 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26192 	CALCULATOR->defaultAssumptions()->setSign(ASSUMPTION_SIGN_POSITIVE);
26193 	update_assumptions_items();
26194 	expression_calculation_updated();
26195 }
on_menu_item_assumptions_nonnegative_activate(GtkMenuItem * w,gpointer)26196 void on_menu_item_assumptions_nonnegative_activate(GtkMenuItem *w, gpointer) {
26197 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26198 	CALCULATOR->defaultAssumptions()->setSign(ASSUMPTION_SIGN_NONNEGATIVE);
26199 	update_assumptions_items();
26200 	expression_calculation_updated();
26201 }
on_menu_item_assumptions_negative_activate(GtkMenuItem * w,gpointer)26202 void on_menu_item_assumptions_negative_activate(GtkMenuItem *w, gpointer) {
26203 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26204 	CALCULATOR->defaultAssumptions()->setSign(ASSUMPTION_SIGN_NEGATIVE);
26205 	update_assumptions_items();
26206 	expression_calculation_updated();
26207 }
on_menu_item_assumptions_nonpositive_activate(GtkMenuItem * w,gpointer)26208 void on_menu_item_assumptions_nonpositive_activate(GtkMenuItem *w, gpointer) {
26209 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26210 	CALCULATOR->defaultAssumptions()->setSign(ASSUMPTION_SIGN_NONPOSITIVE);
26211 	update_assumptions_items();
26212 	expression_calculation_updated();
26213 }
on_menu_item_assumptions_unknown_activate(GtkMenuItem * w,gpointer)26214 void on_menu_item_assumptions_unknown_activate(GtkMenuItem *w, gpointer) {
26215 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26216 	CALCULATOR->defaultAssumptions()->setSign(ASSUMPTION_SIGN_UNKNOWN);
26217 	update_assumptions_items();
26218 	expression_calculation_updated();
26219 }
26220 
set_type(const char * var,AssumptionType at)26221 void set_type(const char *var, AssumptionType at) {
26222 	if(block_expression_execution) return;
26223 	Variable *v = CALCULATOR->getActiveVariable(var);
26224 	if(!v || v->isKnown()) return;
26225 	UnknownVariable *uv = (UnknownVariable*) v;
26226 	if(!uv->assumptions()) uv->setAssumptions(new Assumptions());
26227 	uv->assumptions()->setType(at);
26228 	expression_calculation_updated();
26229 }
set_sign(const char * var,AssumptionSign as)26230 void set_sign(const char *var, AssumptionSign as) {
26231 	if(block_expression_execution) return;
26232 	Variable *v = CALCULATOR->getActiveVariable(var);
26233 	if(!v || v->isKnown()) return;
26234 	UnknownVariable *uv = (UnknownVariable*) v;
26235 	if(!uv->assumptions()) uv->setAssumptions(new Assumptions());
26236 	uv->assumptions()->setSign(as);
26237 	expression_calculation_updated();
26238 }
reset_assumptions(const char * var)26239 void reset_assumptions(const char *var) {
26240 	Variable *v = CALCULATOR->getActiveVariable(var);
26241 	if(!v || v->isKnown()) return;
26242 	UnknownVariable *uv = (UnknownVariable*) v;
26243 	uv->setAssumptions(NULL);
26244 	expression_calculation_updated();
26245 }
26246 
set_x_assumptions_items()26247 void set_x_assumptions_items() {
26248 	Variable *v = CALCULATOR->getActiveVariable("x");
26249 	if(!v || v->isKnown()) return;
26250 	UnknownVariable *uv = (UnknownVariable*) v;
26251 	block_expression_execution++;
26252 	Assumptions *ass = uv->assumptions();
26253 	if(!ass) ass = CALCULATOR->defaultAssumptions();
26254 	switch(ass->sign()) {
26255 		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;}
26256 		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;}
26257 		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;}
26258 		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;}
26259 		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;}
26260 		default: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_x_unknown")), TRUE);}
26261 	}
26262 	switch(ass->type()) {
26263 		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;}
26264 		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;}
26265 		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;}
26266 		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;}
26267 		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;}
26268 		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;}
26269 		default: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_x_none")), TRUE);}
26270 	}
26271 	block_expression_execution--;
26272 }
on_mb_x_toggled(GtkToggleButton * w,gpointer)26273 void on_mb_x_toggled(GtkToggleButton *w, gpointer) {
26274 	if(!gtk_toggle_button_get_active(w)) return;
26275 	set_x_assumptions_items();
26276 }
26277 
on_menu_item_x_default_activate()26278 void on_menu_item_x_default_activate() {
26279 	reset_assumptions("x");
26280 }
on_menu_item_x_integer_activate(GtkMenuItem * w,gpointer)26281 void on_menu_item_x_integer_activate(GtkMenuItem *w, gpointer) {
26282 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26283 	set_type("x", ASSUMPTION_TYPE_INTEGER);
26284 }
on_menu_item_x_rational_activate(GtkMenuItem * w,gpointer)26285 void on_menu_item_x_rational_activate(GtkMenuItem *w, gpointer) {
26286 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26287 	set_type("x", ASSUMPTION_TYPE_RATIONAL);
26288 }
on_menu_item_x_real_activate(GtkMenuItem * w,gpointer)26289 void on_menu_item_x_real_activate(GtkMenuItem *w, gpointer) {
26290 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26291 	set_type("x", ASSUMPTION_TYPE_REAL);
26292 }
on_menu_item_x_complex_activate(GtkMenuItem * w,gpointer)26293 void on_menu_item_x_complex_activate(GtkMenuItem *w, gpointer) {
26294 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26295 	set_type("x", ASSUMPTION_TYPE_COMPLEX);
26296 }
on_menu_item_x_number_activate(GtkMenuItem * w,gpointer)26297 void on_menu_item_x_number_activate(GtkMenuItem *w, gpointer) {
26298 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26299 	set_type("x", ASSUMPTION_TYPE_NUMBER);
26300 }
on_menu_item_x_none_activate(GtkMenuItem * w,gpointer)26301 void on_menu_item_x_none_activate(GtkMenuItem *w, gpointer) {
26302 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26303 	set_type("x", ASSUMPTION_TYPE_NONE);
26304 }
on_menu_item_x_nonmatrix_activate(GtkMenuItem * w,gpointer)26305 void on_menu_item_x_nonmatrix_activate(GtkMenuItem *w, gpointer) {
26306 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26307 	set_type("x", ASSUMPTION_TYPE_NONMATRIX);
26308 }
on_menu_item_x_nonzero_activate(GtkMenuItem * w,gpointer)26309 void on_menu_item_x_nonzero_activate(GtkMenuItem *w, gpointer) {
26310 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26311 	set_sign("x", ASSUMPTION_SIGN_NONZERO);
26312 }
on_menu_item_x_positive_activate(GtkMenuItem * w,gpointer)26313 void on_menu_item_x_positive_activate(GtkMenuItem *w, gpointer) {
26314 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26315 	set_sign("x", ASSUMPTION_SIGN_POSITIVE);
26316 }
on_menu_item_x_nonnegative_activate(GtkMenuItem * w,gpointer)26317 void on_menu_item_x_nonnegative_activate(GtkMenuItem *w, gpointer) {
26318 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26319 	set_sign("x", ASSUMPTION_SIGN_NONNEGATIVE);
26320 }
on_menu_item_x_negative_activate(GtkMenuItem * w,gpointer)26321 void on_menu_item_x_negative_activate(GtkMenuItem *w, gpointer) {
26322 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26323 	set_sign("x", ASSUMPTION_SIGN_NEGATIVE);
26324 }
on_menu_item_x_nonpositive_activate(GtkMenuItem * w,gpointer)26325 void on_menu_item_x_nonpositive_activate(GtkMenuItem *w, gpointer) {
26326 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26327 	set_sign("x", ASSUMPTION_SIGN_NONPOSITIVE);
26328 }
on_menu_item_x_unknown_activate(GtkMenuItem * w,gpointer)26329 void on_menu_item_x_unknown_activate(GtkMenuItem *w, gpointer) {
26330 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26331 	set_sign("x", ASSUMPTION_SIGN_UNKNOWN);
26332 }
26333 
set_y_assumptions_items()26334 void set_y_assumptions_items() {
26335 	Variable *v = CALCULATOR->getActiveVariable("y");
26336 	if(!v || v->isKnown()) return;
26337 	UnknownVariable *uv = (UnknownVariable*) v;
26338 	block_expression_execution++;
26339 	Assumptions *ass = uv->assumptions();
26340 	if(!ass) ass = CALCULATOR->defaultAssumptions();
26341 	switch(ass->sign()) {
26342 		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;}
26343 		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;}
26344 		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;}
26345 		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;}
26346 		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;}
26347 		default: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_y_unknown")), TRUE);}
26348 	}
26349 	switch(ass->type()) {
26350 		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;}
26351 		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;}
26352 		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;}
26353 		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;}
26354 		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;}
26355 		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;}
26356 		default: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_y_none")), TRUE);}
26357 	}
26358 	block_expression_execution--;
26359 }
on_mb_y_toggled(GtkToggleButton * w,gpointer)26360 void on_mb_y_toggled(GtkToggleButton *w, gpointer) {
26361 	if(!gtk_toggle_button_get_active(w)) return;
26362 	set_y_assumptions_items();
26363 }
26364 
on_menu_item_y_default_activate()26365 void on_menu_item_y_default_activate() {
26366 	reset_assumptions("y");
26367 }
on_menu_item_y_integer_activate(GtkMenuItem * w,gpointer)26368 void on_menu_item_y_integer_activate(GtkMenuItem *w, gpointer) {
26369 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26370 	set_type("y", ASSUMPTION_TYPE_INTEGER);
26371 }
on_menu_item_y_rational_activate(GtkMenuItem * w,gpointer)26372 void on_menu_item_y_rational_activate(GtkMenuItem *w, gpointer) {
26373 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26374 	set_type("y", ASSUMPTION_TYPE_RATIONAL);
26375 }
on_menu_item_y_real_activate(GtkMenuItem * w,gpointer)26376 void on_menu_item_y_real_activate(GtkMenuItem *w, gpointer) {
26377 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26378 	set_type("y", ASSUMPTION_TYPE_REAL);
26379 }
on_menu_item_y_complex_activate(GtkMenuItem * w,gpointer)26380 void on_menu_item_y_complex_activate(GtkMenuItem *w, gpointer) {
26381 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26382 	set_type("y", ASSUMPTION_TYPE_COMPLEX);
26383 }
on_menu_item_y_number_activate(GtkMenuItem * w,gpointer)26384 void on_menu_item_y_number_activate(GtkMenuItem *w, gpointer) {
26385 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26386 	set_type("y", ASSUMPTION_TYPE_NUMBER);
26387 }
on_menu_item_y_none_activate(GtkMenuItem * w,gpointer)26388 void on_menu_item_y_none_activate(GtkMenuItem *w, gpointer) {
26389 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26390 	set_type("y", ASSUMPTION_TYPE_NONE);
26391 }
on_menu_item_y_nonmatrix_activate(GtkMenuItem * w,gpointer)26392 void on_menu_item_y_nonmatrix_activate(GtkMenuItem *w, gpointer) {
26393 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26394 	set_type("y", ASSUMPTION_TYPE_NONMATRIX);
26395 }
on_menu_item_y_nonzero_activate(GtkMenuItem * w,gpointer)26396 void on_menu_item_y_nonzero_activate(GtkMenuItem *w, gpointer) {
26397 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26398 	set_sign("y", ASSUMPTION_SIGN_NONZERO);
26399 }
on_menu_item_y_positive_activate(GtkMenuItem * w,gpointer)26400 void on_menu_item_y_positive_activate(GtkMenuItem *w, gpointer) {
26401 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26402 	set_sign("y", ASSUMPTION_SIGN_POSITIVE);
26403 }
on_menu_item_y_nonnegative_activate(GtkMenuItem * w,gpointer)26404 void on_menu_item_y_nonnegative_activate(GtkMenuItem *w, gpointer) {
26405 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26406 	set_sign("y", ASSUMPTION_SIGN_NONNEGATIVE);
26407 }
on_menu_item_y_negative_activate(GtkMenuItem * w,gpointer)26408 void on_menu_item_y_negative_activate(GtkMenuItem *w, gpointer) {
26409 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26410 	set_sign("y", ASSUMPTION_SIGN_NEGATIVE);
26411 }
on_menu_item_y_nonpositive_activate(GtkMenuItem * w,gpointer)26412 void on_menu_item_y_nonpositive_activate(GtkMenuItem *w, gpointer) {
26413 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26414 	set_sign("y", ASSUMPTION_SIGN_NONPOSITIVE);
26415 }
on_menu_item_y_unknown_activate(GtkMenuItem * w,gpointer)26416 void on_menu_item_y_unknown_activate(GtkMenuItem *w, gpointer) {
26417 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26418 	set_sign("y", ASSUMPTION_SIGN_UNKNOWN);
26419 }
26420 
set_z_assumptions_items()26421 void set_z_assumptions_items() {
26422 	Variable *v = CALCULATOR->getActiveVariable("z");
26423 	if(!v || v->isKnown()) return;
26424 	UnknownVariable *uv = (UnknownVariable*) v;
26425 	block_expression_execution++;
26426 	Assumptions *ass = uv->assumptions();
26427 	if(!ass) ass = CALCULATOR->defaultAssumptions();
26428 	switch(ass->sign()) {
26429 		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;}
26430 		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;}
26431 		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;}
26432 		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;}
26433 		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;}
26434 		default: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_z_unknown")), TRUE);}
26435 	}
26436 	switch(ass->type()) {
26437 		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;}
26438 		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;}
26439 		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;}
26440 		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;}
26441 		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;}
26442 		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;}
26443 		default: {gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_z_none")), TRUE);}
26444 	}
26445 	block_expression_execution--;
26446 }
on_mb_z_toggled(GtkToggleButton * w,gpointer)26447 void on_mb_z_toggled(GtkToggleButton *w, gpointer) {
26448 	if(!gtk_toggle_button_get_active(w)) return;
26449 	set_z_assumptions_items();
26450 }
26451 
on_menu_item_z_default_activate()26452 void on_menu_item_z_default_activate() {
26453 	reset_assumptions("z");
26454 }
on_menu_item_z_integer_activate(GtkMenuItem * w,gpointer)26455 void on_menu_item_z_integer_activate(GtkMenuItem *w, gpointer) {
26456 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26457 	set_type("z", ASSUMPTION_TYPE_INTEGER);
26458 }
on_menu_item_z_rational_activate(GtkMenuItem * w,gpointer)26459 void on_menu_item_z_rational_activate(GtkMenuItem *w, gpointer) {
26460 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26461 	set_type("z", ASSUMPTION_TYPE_RATIONAL);
26462 }
on_menu_item_z_real_activate(GtkMenuItem * w,gpointer)26463 void on_menu_item_z_real_activate(GtkMenuItem *w, gpointer) {
26464 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26465 	set_type("z", ASSUMPTION_TYPE_REAL);
26466 }
on_menu_item_z_complex_activate(GtkMenuItem * w,gpointer)26467 void on_menu_item_z_complex_activate(GtkMenuItem *w, gpointer) {
26468 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26469 	set_type("z", ASSUMPTION_TYPE_COMPLEX);
26470 }
on_menu_item_z_number_activate(GtkMenuItem * w,gpointer)26471 void on_menu_item_z_number_activate(GtkMenuItem *w, gpointer) {
26472 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26473 	set_type("z", ASSUMPTION_TYPE_NUMBER);
26474 }
on_menu_item_z_none_activate(GtkMenuItem * w,gpointer)26475 void on_menu_item_z_none_activate(GtkMenuItem *w, gpointer) {
26476 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26477 	set_type("z", ASSUMPTION_TYPE_NONE);
26478 }
on_menu_item_z_nonmatrix_activate(GtkMenuItem * w,gpointer)26479 void on_menu_item_z_nonmatrix_activate(GtkMenuItem *w, gpointer) {
26480 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26481 	set_type("z", ASSUMPTION_TYPE_NONMATRIX);
26482 }
on_menu_item_z_nonzero_activate(GtkMenuItem * w,gpointer)26483 void on_menu_item_z_nonzero_activate(GtkMenuItem *w, gpointer) {
26484 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26485 	set_sign("z", ASSUMPTION_SIGN_NONZERO);
26486 }
on_menu_item_z_positive_activate(GtkMenuItem * w,gpointer)26487 void on_menu_item_z_positive_activate(GtkMenuItem *w, gpointer) {
26488 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26489 	set_sign("z", ASSUMPTION_SIGN_POSITIVE);
26490 }
on_menu_item_z_nonnegative_activate(GtkMenuItem * w,gpointer)26491 void on_menu_item_z_nonnegative_activate(GtkMenuItem *w, gpointer) {
26492 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26493 	set_sign("z", ASSUMPTION_SIGN_NONNEGATIVE);
26494 }
on_menu_item_z_negative_activate(GtkMenuItem * w,gpointer)26495 void on_menu_item_z_negative_activate(GtkMenuItem *w, gpointer) {
26496 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26497 	set_sign("z", ASSUMPTION_SIGN_NEGATIVE);
26498 }
on_menu_item_z_nonpositive_activate(GtkMenuItem * w,gpointer)26499 void on_menu_item_z_nonpositive_activate(GtkMenuItem *w, gpointer) {
26500 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26501 	set_sign("z", ASSUMPTION_SIGN_NONPOSITIVE);
26502 }
on_menu_item_z_unknown_activate(GtkMenuItem * w,gpointer)26503 void on_menu_item_z_unknown_activate(GtkMenuItem *w, gpointer) {
26504 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
26505 	set_sign("z", ASSUMPTION_SIGN_UNKNOWN);
26506 }
26507 
menu_to_bin(GtkMenuItem *,gpointer)26508 void menu_to_bin(GtkMenuItem*, gpointer) {
26509 	int save_base = printops.base;
26510 	to_base = 0;
26511 	to_bits = 0;
26512 	printops.base = BASE_BINARY;
26513 	result_format_updated();
26514 	printops.base = save_base;
26515 }
menu_to_oct(GtkMenuItem *,gpointer)26516 void menu_to_oct(GtkMenuItem*, gpointer) {
26517 	int save_base = printops.base;
26518 	to_base = 0;
26519 	to_bits = 0;
26520 	printops.base = BASE_OCTAL;
26521 	result_format_updated();
26522 	printops.base = save_base;
26523 }
menu_to_dec(GtkMenuItem *,gpointer)26524 void menu_to_dec(GtkMenuItem*, gpointer) {
26525 	int save_base = printops.base;
26526 	to_base = 0;
26527 	to_bits = 0;
26528 	printops.base = BASE_DECIMAL;
26529 	result_format_updated();
26530 	printops.base = save_base;
26531 }
menu_to_duo(GtkMenuItem *,gpointer)26532 void menu_to_duo(GtkMenuItem*, gpointer) {
26533 	int save_base = printops.base;
26534 	to_base = 0;
26535 	to_bits = 0;
26536 	printops.base = 12;
26537 	result_format_updated();
26538 	printops.base = save_base;
26539 }
menu_to_hex(GtkMenuItem *,gpointer)26540 void menu_to_hex(GtkMenuItem*, gpointer) {
26541 	int save_base = printops.base;
26542 	to_base = 0;
26543 	to_bits = 0;
26544 	printops.base = BASE_HEXADECIMAL;
26545 	result_format_updated();
26546 	printops.base = save_base;
26547 }
menu_to_roman(GtkMenuItem *,gpointer)26548 void menu_to_roman(GtkMenuItem*, gpointer) {
26549 	int save_base = printops.base;
26550 	to_base = 0;
26551 	to_bits = 0;
26552 	printops.base = BASE_ROMAN_NUMERALS;
26553 	result_format_updated();
26554 	printops.base = save_base;
26555 }
menu_to_utc(GtkMenuItem *,gpointer)26556 void menu_to_utc(GtkMenuItem*, gpointer) {
26557 	printops.time_zone = TIME_ZONE_UTC;
26558 	result_format_updated();
26559 	printops.time_zone = TIME_ZONE_LOCAL;
26560 }
menu_to_fraction(GtkMenuItem *,gpointer)26561 void menu_to_fraction(GtkMenuItem*, gpointer) {
26562 	NumberFractionFormat save_format = printops.number_fraction_format;
26563 	bool save_restrict_fraction_length = printops.restrict_fraction_length;
26564 	printops.restrict_fraction_length = false;
26565 	to_fraction = false;
26566 	printops.number_fraction_format = FRACTION_COMBINED;
26567 	result_format_updated();
26568 	printops.number_fraction_format = save_format;
26569 	printops.restrict_fraction_length = save_restrict_fraction_length;
26570 }
menu_to_rectangular(GtkMenuItem *,gpointer)26571 void menu_to_rectangular(GtkMenuItem*, gpointer) {
26572 	ComplexNumberForm cnf_bak = evalops.complex_number_form;
26573 	to_caf = 0;
26574 	evalops.complex_number_form = COMPLEX_NUMBER_FORM_RECTANGULAR;
26575 	executeCommand(COMMAND_EVAL);
26576 	evalops.complex_number_form = cnf_bak;
26577 }
menu_to_exponential(GtkMenuItem *,gpointer)26578 void menu_to_exponential(GtkMenuItem*, gpointer) {
26579 	ComplexNumberForm cnf_bak = evalops.complex_number_form;
26580 	to_caf = 0;
26581 	evalops.complex_number_form = COMPLEX_NUMBER_FORM_EXPONENTIAL;
26582 	executeCommand(COMMAND_EVAL);
26583 	evalops.complex_number_form = cnf_bak;
26584 }
menu_to_polar(GtkMenuItem *,gpointer)26585 void menu_to_polar(GtkMenuItem*, gpointer) {
26586 	ComplexNumberForm cnf_bak = evalops.complex_number_form;
26587 	to_caf = 0;
26588 	evalops.complex_number_form = COMPLEX_NUMBER_FORM_POLAR;
26589 	executeCommand(COMMAND_EVAL);
26590 	evalops.complex_number_form = cnf_bak;
26591 }
menu_to_angle(GtkMenuItem *,gpointer)26592 void menu_to_angle(GtkMenuItem*, gpointer) {
26593 	ComplexNumberForm cnf_bak = evalops.complex_number_form;
26594 	to_caf = 1;
26595 	evalops.complex_number_form = COMPLEX_NUMBER_FORM_CIS;
26596 	executeCommand(COMMAND_EVAL);
26597 	evalops.complex_number_form = cnf_bak;
26598 }
update_mb_to_menu()26599 void update_mb_to_menu() {
26600 	GtkWidget *sub = GTK_WIDGET(gtk_builder_get_object(main_builder, "menu_to"));
26601 	if(expression_has_changed && !rpn_mode && !auto_calculate) execute_expression(true);
26602 	GtkWidget *item;
26603 	GList *list = gtk_container_get_children(GTK_CONTAINER(sub));
26604 	for(GList *l = list; l != NULL; l = l->next) {
26605 		gtk_widget_destroy(GTK_WIDGET(l->data));
26606 	}
26607 	g_list_free(list);
26608 	if(!mstruct || !displayed_mstruct || !contains_convertable_unit(*displayed_mstruct)) {
26609 		bool b_date = (mstruct && displayed_mstruct && mstruct->isDateTime());
26610 		bool b_integ = (mstruct && displayed_mstruct && mstruct->isInteger());
26611 		bool b_complex = (mstruct && displayed_mstruct && (contains_imaginary_number(*mstruct) || mstruct->containsFunctionId(FUNCTION_ID_CIS)));
26612 		bool b_rational = (mstruct && displayed_mstruct && contains_rational_number(*displayed_mstruct));
26613 		if(b_date) {
26614 			MENU_ITEM(_("Calendars"), on_popup_menu_item_calendarconversion_activate)
26615 			MENU_ITEM("UTC", menu_to_utc)
26616 			return;
26617 		}
26618 		bool base_sep = false;
26619 		if(!b_complex) {
26620 			MENU_ITEM(_("Number bases"), on_menu_item_convert_number_bases_activate)
26621 			if(displayed_printops.base != BASE_BINARY) {MENU_ITEM(_("Binary"), menu_to_bin)}
26622 			if(displayed_printops.base != BASE_OCTAL) {MENU_ITEM(_("Octal"), menu_to_oct)}
26623 			if(displayed_printops.base != BASE_DECIMAL) {MENU_ITEM(_("Decimal"), menu_to_dec)}
26624 			if(displayed_printops.base != BASE_DUODECIMAL) {MENU_ITEM(_("Duodecimal"), menu_to_duo)}
26625 			if(displayed_printops.base != BASE_HEXADECIMAL) {MENU_ITEM(_("Hexadecimal"), menu_to_hex)}
26626 			if(b_integ) {
26627 				if(displayed_printops.base != BASE_ROMAN_NUMERALS) {MENU_ITEM(_("Roman"), menu_to_roman)}
26628 				MENU_SEPARATOR
26629 				base_sep = true;
26630 				MENU_ITEM(_("Factors"), on_menu_item_factorize_activate)
26631 			} else if(displayed_mstruct && displayed_mstruct->containsType(STRUCT_ADDITION)) {
26632 				MENU_SEPARATOR
26633 				base_sep = true;
26634 				MENU_ITEM(_("Factors"), on_menu_item_factorize_activate)
26635 			}
26636 		}
26637 		if(b_rational) {
26638 			if(!base_sep) {
26639 				MENU_SEPARATOR
26640 				base_sep = true;
26641 			}
26642 			MENU_ITEM(_("Fraction"), menu_to_fraction)
26643 			if(b_complex) {
26644 				MENU_SEPARATOR
26645 			}
26646 		}
26647 		if(b_complex && evalops.complex_number_form != COMPLEX_NUMBER_FORM_RECTANGULAR) {MENU_ITEM(_("Rectangular form"), menu_to_rectangular)}
26648 		if(b_complex && evalops.complex_number_form != COMPLEX_NUMBER_FORM_EXPONENTIAL) {MENU_ITEM(_("Exponential form"), menu_to_exponential)}
26649 		if(b_complex && evalops.complex_number_form != COMPLEX_NUMBER_FORM_POLAR) {MENU_ITEM(_("Polar form"), menu_to_polar)}
26650 		if(b_complex && (evalops.complex_number_form != COMPLEX_NUMBER_FORM_CIS || !complex_angle_form)) {MENU_ITEM(_("Angle/phasor notation"), menu_to_angle)}
26651 		return;
26652 	}
26653 	MENU_ITEM(_("Base units"), on_menu_item_convert_to_base_units_activate);
26654 	MENU_ITEM(_("Optimal unit"), on_menu_item_convert_to_best_unit_activate);
26655 	MENU_ITEM(_("Optimal prefix"), on_menu_item_set_prefix_activate);
26656 	MENU_SEPARATOR
26657 	string s_cat;
26658 	Unit *u_result = NULL;
26659 	if(displayed_mstruct) u_result = find_exact_matching_unit(*displayed_mstruct);
26660 	bool b_exact = (u_result != NULL);
26661 	if(!u_result) u_result = CALCULATOR->findMatchingUnit(*mstruct);
26662 	if(u_result) s_cat = u_result->category();
26663 	bool b_prefix = false;
26664 	if(b_exact && u_result && u_result->subtype() != SUBTYPE_COMPOSITE_UNIT) b_prefix = has_prefix(*displayed_mstruct);
26665 	vector<Unit*> to_us;
26666 	size_t i_added = 0;
26667 	if(u_result && u_result->isCurrency()) {
26668 		Unit *u_local_currency = CALCULATOR->getLocalCurrency();
26669 		const char *currency_units[] = {"USD", "GBP", "JPY", "CNY", "INR", "CAD", "BRL"};
26670 		to_us.clear();
26671 		if(latest_button_currency && (!b_exact || b_prefix || latest_button_currency != u_result)) to_us.push_back(latest_button_currency);
26672 		for(size_t i = 0; i < 9 && to_us.size() < 6; i++) {
26673 			Unit * u;
26674 			if(i == 0) u = CALCULATOR->u_euro;
26675 			else if(i == 1) u = u_local_currency;
26676 			else u = CALCULATOR->getActiveUnit(currency_units[i - 2]);
26677 			if(u && (!b_exact || b_prefix || u != u_result) && (i == 1 || !u->isHidden())) {
26678 				bool b = false;
26679 				for(size_t i2 = 0; i2 < to_us.size(); i2++) {
26680 					if(u == to_us[i2]) {
26681 						b = true;
26682 						break;
26683 					}
26684 					if(string_is_less(u->title(true), to_us[i2]->title(true))) {
26685 						to_us.insert(to_us.begin() + i2, u);
26686 						b = true;
26687 						break;
26688 					}
26689 				}
26690 				if(!b) to_us.push_back(u);
26691 			}
26692 		}
26693 		for(size_t i = 0; i < to_us.size(); i++) {
26694 			MENU_ITEM_WITH_POINTER_AND_FLAG(to_us[i]->title(true).c_str(), convert_to_unit, to_us[i])
26695 		}
26696 		i_added = to_us.size();
26697 		vector<Unit*> to_us2;
26698 		for(size_t i = 0; i < CALCULATOR->units.size(); i++) {
26699 			if(CALCULATOR->units[i]->isCurrency()) {
26700 				Unit *u = CALCULATOR->units[i];
26701 				if(u->isActive()) {
26702 					bool b = false;
26703 					if(u->isHidden() && (!b_exact || b_prefix || u != u_result) && u != u_local_currency) {
26704 						for(int i2 = to_us2.size() - 1; i2 >= 0; i2--) {
26705 							if(u->title(true) > to_us2[(size_t) i2]->title(true)) {
26706 								if((size_t) i2 == to_us2.size() - 1) to_us2.push_back(u);
26707 								else to_us2.insert(to_us2.begin() + (size_t) i2 + 1, u);
26708 								b = true;
26709 								break;
26710 							}
26711 						}
26712 						if(!b) to_us2.insert(to_us2.begin(), u);
26713 					} else {
26714 						for(size_t i2 = 0; i2 < i_added; i2++) {
26715 							if(u == to_us[i2]) {
26716 								b = true;
26717 								break;
26718 							}
26719 						}
26720 						for(size_t i2 = to_us.size() - 1; !b && i2 >= i_added; i2--) {
26721 							if(u->title(true) > to_us[i2]->title(true)) {
26722 								if(i2 == to_us.size() - 1) to_us.push_back(u);
26723 								else to_us.insert(to_us.begin() + i2 + 1, u);
26724 								b = true;
26725 							}
26726 						}
26727 						if(!b) to_us.insert(to_us.begin() + i_added, u);
26728 					}
26729 				}
26730 			}
26731 		}
26732 		for(size_t i = i_added; i < to_us.size(); i++) {
26733 			// Show further items in a submenu
26734 			if(i == i_added) {SUBMENU_ITEM(_("more"), sub);}
26735 			MENU_ITEM_WITH_POINTER_AND_FLAG(to_us[i]->title(true).c_str(), convert_to_unit, to_us[i])
26736 		}
26737 		if(to_us2.size() > 0) {SUBMENU_ITEM(_("more"), sub);}
26738 		for(size_t i = 0; i < to_us2.size(); i++) {
26739 			// Show further items in a submenu
26740 			MENU_ITEM_WITH_POINTER_AND_FLAG(to_us2[i]->title(true).c_str(), convert_to_unit, to_us2[i])
26741 		}
26742 	} else if(!s_cat.empty()) {
26743 		for(size_t i = 0; i < CALCULATOR->units.size(); i++) {
26744 			if(CALCULATOR->units[i]->category() == s_cat) {
26745 				Unit *u = CALCULATOR->units[i];
26746 				if(u->isActive() && (!b_exact || b_prefix || u != u_result) && !u->isHidden()) {
26747 					bool b = false;
26748 					for(size_t i2 = 0; i2 < to_us.size(); i2++) {
26749 						if(string_is_less(u->title(true), to_us[i2]->title(true))) {
26750 							to_us.insert(to_us.begin() + i2, u);
26751 							b = true;
26752 							break;
26753 						}
26754 					}
26755 					if(!b) to_us.push_back(u);
26756 					i_added++;
26757 				}
26758 			}
26759 		}
26760 		for(size_t i = 0; i < to_us.size(); i++) {
26761 			if(i + 4 == 10 && i + 1 != to_us.size()) {SUBMENU_ITEM(_("more"), sub);}
26762 			MENU_ITEM_WITH_POINTER(to_us[i]->title(true).c_str(), convert_to_unit_noprefix, to_us[i])
26763 		}
26764 	}
26765 	if(!i_added) {
26766 		const char *si_units[] = {"m", "g", "s", "A", "K", "L", "J", "N"};
26767 		vector<Unit*> to_us2;
26768 		for(size_t i = 0; i < 8 && i_added + 3 < 10; i++) {
26769 			Unit * u = CALCULATOR->getActiveUnit(si_units[i]);
26770 			if(!u->isHidden() && (!b_exact || b_prefix || u != u_result)) {
26771 				bool b = false;
26772 				for(size_t i2 = 0; i2 < to_us.size(); i2++) {
26773 					if(u == to_us[i2]) {
26774 						b = true;
26775 						break;
26776 					}
26777 				}
26778 				for(size_t i2 = 0; !b && i2 < to_us2.size(); i2++) {
26779 					if(string_is_less(u->title(true), to_us2[i2]->title(true))) {
26780 						to_us2.insert(to_us2.begin() + i2, u);
26781 						b = true;
26782 						i_added++;
26783 						break;
26784 					}
26785 				}
26786 				if(!b) {
26787 					to_us2.push_back(u);
26788 					i_added++;
26789 				}
26790 			}
26791 		}
26792 		for(size_t i = 0; i < to_us2.size(); i++) {
26793 			MENU_ITEM_WITH_POINTER(to_us2[i]->title(true).c_str(), convert_to_unit, to_us2[i])
26794 		}
26795 	}
26796 }
on_mb_to_button_release_event(GtkWidget,GdkEventButton * event,gpointer)26797 gboolean on_mb_to_button_release_event(GtkWidget, GdkEventButton *event, gpointer) {
26798 	if(b_busy) return TRUE;
26799 	update_mb_to_menu();
26800 	return FALSE;
26801 }
26802 
update_mb_units_menu()26803 void update_mb_units_menu() {
26804 	GtkMenu *sub = GTK_MENU(gtk_builder_get_object(main_builder, "menu_units"));
26805 	GtkWidget *item;
26806 	GList *list = gtk_container_get_children(GTK_CONTAINER(sub));
26807 	for(GList *l = list; l != NULL; l = l->next) {
26808 		gtk_widget_destroy(GTK_WIDGET(l->data));
26809 	}
26810 	g_list_free(list);
26811 	const char *si_units[] = {"m", "g", "s", "A", "K"};
26812 	size_t i_added = 0;
26813 	for(size_t i = recent_units.size(); i > 0; i--) {
26814 		if(!recent_units[i - 1]->isLocal() && CALCULATOR->stillHasUnit(recent_units[i - 1])) {
26815 			MENU_ITEM_WITH_POINTER(recent_units[i - 1]->title(true).c_str(), insert_unit, recent_units[i - 1])
26816 			i_added++;
26817 		}
26818 	}
26819 	for(size_t i = 0; i_added < 5 && i < 5; i++) {
26820 		Unit * u = CALCULATOR->getActiveUnit(si_units[i]);
26821 		if(u && !u->isHidden()) {
26822 			MENU_ITEM_WITH_POINTER(u->title(true).c_str(), insert_unit, u)
26823 			i_added++;
26824 		}
26825 	}
26826 
26827 	MENU_SEPARATOR
26828 	Prefix *p = CALCULATOR->getPrefix("giga");
26829 	if(p) {MENU_ITEM_WITH_POINTER(p->longName(true, printops.use_unicode_signs).c_str(), insert_prefix, p);}
26830 	p = CALCULATOR->getPrefix("mega");
26831 	if(p) {MENU_ITEM_WITH_POINTER(p->longName(true, printops.use_unicode_signs).c_str(), insert_prefix, p);}
26832 	p = CALCULATOR->getPrefix("kilo");
26833 	if(p) {MENU_ITEM_WITH_POINTER(p->longName(true, printops.use_unicode_signs).c_str(), insert_prefix, p);}
26834 	p = CALCULATOR->getPrefix("milli");
26835 	if(p) {MENU_ITEM_WITH_POINTER(p->longName(true, printops.use_unicode_signs).c_str(), insert_prefix, p);}
26836 	p = CALCULATOR->getPrefix("micro");
26837 	if(p) {MENU_ITEM_WITH_POINTER(p->longName(true, printops.use_unicode_signs).c_str(), insert_prefix, p);}
26838 }
26839 
on_popup_menu_fx_edit_activate(GtkMenuItem * w,gpointer data)26840 void on_popup_menu_fx_edit_activate(GtkMenuItem *w, gpointer data) {
26841 	edit_function_simple("", (MathFunction*) data, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")));
26842 }
on_popup_menu_fx_delete_activate(GtkMenuItem * w,gpointer data)26843 void on_popup_menu_fx_delete_activate(GtkMenuItem *w, gpointer data) {
26844 	delete_function((MathFunction*) data);
26845 	gtk_menu_popdown(GTK_MENU(gtk_builder_get_object(main_builder, "menu_fx")));
26846 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "mb_fx")), FALSE);
26847 	focus_keeping_selection();
26848 }
26849 
26850 gulong on_popup_menu_fx_edit_activate_handler = 0, on_popup_menu_fx_delete_activate_handler = 0;
26851 
on_menu_fx_popup_menu(GtkWidget *,gpointer data)26852 gboolean on_menu_fx_popup_menu(GtkWidget*, gpointer data) {
26853 	if(b_busy) return TRUE;
26854 	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);
26855 	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);
26856 	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);
26857 	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);
26858 #if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 22
26859 	gtk_menu_popup_at_pointer(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_fx")), NULL);
26860 #else
26861 	gtk_menu_popup(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_fx")), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time());
26862 #endif
26863 	return TRUE;
26864 }
26865 
on_menu_fx_button_press(GtkWidget * widget,GdkEventButton * event,gpointer data)26866 gboolean on_menu_fx_button_press(GtkWidget *widget, GdkEventButton *event, gpointer data) {
26867 	/* Ignore double-clicks and triple-clicks */
26868 	if(gdk_event_triggers_context_menu((GdkEvent *) event) && event->type == GDK_BUTTON_PRESS) {
26869 		on_menu_fx_popup_menu(widget, data);
26870 		return TRUE;
26871 	}
26872 	return FALSE;
26873 }
26874 
update_mb_fx_menu()26875 void update_mb_fx_menu() {
26876 	GtkMenu *sub = GTK_MENU(gtk_builder_get_object(main_builder, "menu_fx"));
26877 	GtkWidget *item;
26878 	GList *list = gtk_container_get_children(GTK_CONTAINER(sub));
26879 	for(GList *l = list; l != NULL; l = l->next) {
26880 		gtk_widget_destroy(GTK_WIDGET(l->data));
26881 	}
26882 	g_list_free(list);
26883 	bool b = false;
26884 	for(size_t i = 0; i < CALCULATOR->functions.size(); i++) {
26885 		if(CALCULATOR->functions[i]->isLocal() && !CALCULATOR->functions[i]->isBuiltin() && CALCULATOR->functions[i]->isActive() && !CALCULATOR->functions[i]->isHidden()) {
26886 			MENU_ITEM_WITH_POINTER(CALCULATOR->functions[i]->title(true).c_str(), insert_button_function, CALCULATOR->functions[i])
26887 			g_signal_connect(G_OBJECT(item), "button-press-event", G_CALLBACK(on_menu_fx_button_press), CALCULATOR->functions[i]);
26888 			g_signal_connect(G_OBJECT(item), "popup-menu", G_CALLBACK(on_menu_fx_popup_menu), (gpointer) CALCULATOR->functions[i]);
26889 			b = true;
26890 		}
26891 	}
26892 	bool b2 = false;
26893 	for(size_t i = recent_functions.size(); i > 0; i--) {
26894 		if(!recent_functions[i - 1]->isLocal() && CALCULATOR->stillHasFunction(recent_functions[i - 1])) {
26895 			if(!b2 && b) {MENU_SEPARATOR}
26896 			b2 = true;
26897 			MENU_ITEM_WITH_POINTER(recent_functions[i - 1]->title(true).c_str(), insert_button_function_save, recent_functions[i - 1])
26898 		}
26899 	}
26900 	if(b2 || b) {MENU_SEPARATOR}
26901 	MENU_ITEM(_("All functions"), on_menu_item_manage_functions_activate);
26902 }
26903 
insert_button_sqrt2()26904 void insert_button_sqrt2() {
26905 	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());
26906 }
update_mb_pi_menu()26907 void update_mb_pi_menu() {
26908 
26909 	GtkMenu *sub = GTK_MENU(gtk_builder_get_object(main_builder, "menu_pi"));
26910 	GtkWidget *item;
26911 	GList *list = gtk_container_get_children(GTK_CONTAINER(sub));
26912 	for(GList *l = list; l != NULL; l = l->next) {
26913 		gtk_widget_destroy(GTK_WIDGET(l->data));
26914 	}
26915 	g_list_free(list);
26916 
26917 	Variable *v = CALCULATOR->getActiveVariable("pythagoras");
26918 	MENU_ITEM(v ? v->title(true).c_str() : SIGN_SQRT "2", insert_button_sqrt2)
26919 	MENU_ITEM_WITH_POINTER(CALCULATOR->v_euler->title(true).c_str(), insert_button_variable, CALCULATOR->v_euler);
26920 	v = CALCULATOR->getActiveVariable("golden");
26921 	if(v) {MENU_ITEM_WITH_POINTER(v->title(true).c_str(), insert_button_variable, v);}
26922 	MENU_SEPARATOR
26923 
26924 	int i_added = 0;
26925 	for(size_t i = recent_variables.size(); i > 0; i--) {
26926 		if(!recent_variables[i - 1]->isLocal() && CALCULATOR->stillHasVariable(recent_variables[i - 1])) {
26927 			MENU_ITEM_WITH_POINTER(recent_variables[i - 1]->title(true).c_str(), insert_variable, recent_variables[i - 1])
26928 			i_added++;
26929 		}
26930 	}
26931 	if(i_added < 5)	{
26932 		v = CALCULATOR->getActiveVariable("c");
26933 		if(v) {MENU_ITEM_WITH_POINTER(v->title(true).c_str(), insert_button_variable, v); i_added++;}
26934 	}
26935 	if(i_added < 5)	{
26936 		v = CALCULATOR->getActiveVariable("newtonian_constant");
26937 		if(v) {MENU_ITEM_WITH_POINTER(v->title(true).c_str(), insert_button_variable, v); i_added++;}
26938 	}
26939 	if(i_added < 5)	{
26940 		v = CALCULATOR->getActiveVariable("planck");
26941 		if(v) {MENU_ITEM_WITH_POINTER(v->title(true).c_str(), insert_button_variable, v); i_added++;}
26942 	}
26943 	if(i_added < 5)	{
26944 		v = CALCULATOR->getActiveVariable("boltzmann");
26945 		if(v) {MENU_ITEM_WITH_POINTER(v->title(true).c_str(), insert_button_variable, v); i_added++;}
26946 	}
26947 	if(i_added < 5)	{
26948 		v = CALCULATOR->getActiveVariable("avogadro");
26949 		if(v) {MENU_ITEM_WITH_POINTER(v->title(true).c_str(), insert_button_variable, v); i_added++;}
26950 	}
26951 
26952 	MENU_SEPARATOR
26953 	MENU_ITEM(_("All variables"), on_menu_item_manage_variables_activate);
26954 
26955 }
26956 
on_popup_menu_sto_set_activate(GtkMenuItem * w,gpointer data)26957 void on_popup_menu_sto_set_activate(GtkMenuItem *w, gpointer data) {
26958 	((KnownVariable*) data)->set(*mstruct);
26959 	gtk_menu_popdown(GTK_MENU(gtk_builder_get_object(main_builder, "menu_sto")));
26960 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "mb_sto")), FALSE);
26961 	focus_keeping_selection();
26962 }
on_popup_menu_sto_add_activate(GtkMenuItem * w,gpointer data)26963 void on_popup_menu_sto_add_activate(GtkMenuItem *w, gpointer data) {
26964 	MathStructure m(((KnownVariable*) data)->get());
26965 	m.calculateAdd(*mstruct, evalops);
26966 	((KnownVariable*) data)->set(m);
26967 	gtk_menu_popdown(GTK_MENU(gtk_builder_get_object(main_builder, "menu_sto")));
26968 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "mb_sto")), FALSE);
26969 	focus_keeping_selection();
26970 }
on_popup_menu_sto_sub_activate(GtkMenuItem * w,gpointer data)26971 void on_popup_menu_sto_sub_activate(GtkMenuItem *w, gpointer data) {
26972 	MathStructure m(((KnownVariable*) data)->get());
26973 	m.calculateSubtract(*mstruct, evalops);
26974 	((KnownVariable*) data)->set(m);
26975 	gtk_menu_popdown(GTK_MENU(gtk_builder_get_object(main_builder, "menu_sto")));
26976 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "mb_sto")), FALSE);
26977 	focus_keeping_selection();
26978 }
on_popup_menu_sto_edit_activate(GtkMenuItem * w,gpointer data)26979 void on_popup_menu_sto_edit_activate(GtkMenuItem *w, gpointer data) {
26980 	edit_variable("", (Variable*) data, NULL, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")));
26981 }
on_popup_menu_sto_delete_activate(GtkMenuItem * w,gpointer data)26982 void on_popup_menu_sto_delete_activate(GtkMenuItem *w, gpointer data) {
26983 	delete_variable((Variable*) data);
26984 	gtk_menu_popdown(GTK_MENU(gtk_builder_get_object(main_builder, "menu_sto")));
26985 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "mb_sto")), FALSE);
26986 	focus_keeping_selection();
26987 }
26988 
26989 gulong on_popup_menu_sto_set_activate_handler = 0, on_popup_menu_sto_add_activate_handler = 0, on_popup_menu_sto_sub_activate_handler = 0, on_popup_menu_sto_edit_activate_handler = 0, on_popup_menu_sto_delete_activate_handler = 0;
26990 
on_menu_sto_popup_menu(GtkWidget *,gpointer data)26991 gboolean on_menu_sto_popup_menu(GtkWidget*, gpointer data) {
26992 	if(b_busy) return TRUE;
26993 	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);
26994 	if(on_popup_menu_sto_add_activate_handler != 0) g_signal_handler_disconnect(gtk_builder_get_object(main_builder, "popup_menu_sto_add"), on_popup_menu_sto_add_activate_handler);
26995 	if(on_popup_menu_sto_sub_activate_handler != 0) g_signal_handler_disconnect(gtk_builder_get_object(main_builder, "popup_menu_sto_sub"), on_popup_menu_sto_sub_activate_handler);
26996 	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);
26997 	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);
26998 	if(((Variable*) data)->isKnown() && mstruct && displayed_mstruct) {
26999 		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);
27000 		on_popup_menu_sto_add_activate_handler = g_signal_connect(gtk_builder_get_object(main_builder, "popup_menu_sto_add"), "activate", G_CALLBACK(on_popup_menu_sto_add_activate), data);
27001 		on_popup_menu_sto_sub_activate_handler = g_signal_connect(gtk_builder_get_object(main_builder, "popup_menu_sto_sub"), "activate", G_CALLBACK(on_popup_menu_sto_sub_activate), data);
27002 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_sto_set")), TRUE);
27003 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_sto_add")), TRUE);
27004 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_sto_sub")), TRUE);
27005 	} else {
27006 		on_popup_menu_sto_set_activate_handler = 0;
27007 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_sto_set")), FALSE);
27008 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_sto_add")), FALSE);
27009 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_sto_sub")), FALSE);
27010 	}
27011 	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);
27012 	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);
27013 #if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 22
27014 	gtk_menu_popup_at_pointer(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_sto")), NULL);
27015 #else
27016 	gtk_menu_popup(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_sto")), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time());
27017 #endif
27018 	return TRUE;
27019 }
27020 
on_menu_sto_button_press(GtkWidget * widget,GdkEventButton * event,gpointer data)27021 gboolean on_menu_sto_button_press(GtkWidget *widget, GdkEventButton *event, gpointer data) {
27022 	/* Ignore double-clicks and triple-clicks */
27023 	if(gdk_event_triggers_context_menu((GdkEvent *) event) && event->type == GDK_BUTTON_PRESS) {
27024 		on_menu_sto_popup_menu(widget, data);
27025 		return TRUE;
27026 	}
27027 	return FALSE;
27028 }
update_mb_sto_menu()27029 void update_mb_sto_menu() {
27030 	GtkMenu *sub = GTK_MENU(gtk_builder_get_object(main_builder, "menu_sto"));
27031 	GtkWidget *item;
27032 	GList *list = gtk_container_get_children(GTK_CONTAINER(sub));
27033 	for(GList *l = list; l != NULL; l = l->next) {
27034 		gtk_widget_destroy(GTK_WIDGET(l->data));
27035 	}
27036 	g_list_free(list);
27037 	bool b = false;
27038 	for(size_t i = 0; i < CALCULATOR->variables.size(); i++) {
27039 		if(CALCULATOR->variables[i]->isLocal() && !CALCULATOR->variables[i]->isBuiltin() && CALCULATOR->variables[i]->isActive() && !CALCULATOR->variables[i]->isHidden()) {
27040 			MENU_ITEM_WITH_POINTER(CALCULATOR->variables[i]->title(true).c_str(), insert_button_variable, CALCULATOR->variables[i])
27041 			g_signal_connect(G_OBJECT(item), "button-press-event", G_CALLBACK(on_menu_sto_button_press), CALCULATOR->variables[i]);
27042 			g_signal_connect(G_OBJECT(item), "popup-menu", G_CALLBACK(on_menu_sto_popup_menu), (gpointer) CALCULATOR->variables[i]);
27043 			b = true;
27044 		}
27045 	}
27046 	//if(!b) {MENU_NO_ITEMS(_("No items found"))}
27047 	if(b) {MENU_SEPARATOR}
27048 	MENU_ITEM(_("MC (memory clear)"), memory_clear);
27049 	MENU_ITEM(_("MR (memory recall)"), memory_recall);
27050 	MENU_ITEM(_("MS (memory store)"), memory_store);
27051 	MENU_ITEM(_("M+ (memory plus)"), memory_add);
27052 	MENU_ITEM(_("M− (memory minus)"), memory_subtract);
27053 }
27054 
on_menu_item_status_exact_activate(GtkMenuItem * w,gpointer)27055 void on_menu_item_status_exact_activate(GtkMenuItem *w, gpointer) {
27056 	if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_always_exact")), TRUE);
27057 	else gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_try_exact")), TRUE);
27058 }
on_menu_item_status_read_precision_activate(GtkMenuItem * w,gpointer)27059 void on_menu_item_status_read_precision_activate(GtkMenuItem *w, gpointer) {
27060 	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)));
27061 }
on_menu_item_status_rpn_syntax_activate(GtkMenuItem * w,gpointer)27062 void on_menu_item_status_rpn_syntax_activate(GtkMenuItem *w, gpointer) {
27063 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
27064 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_rpn_syntax")), TRUE);
27065 }
on_menu_item_status_chain_syntax_activate(GtkMenuItem * w,gpointer)27066 void on_menu_item_status_chain_syntax_activate(GtkMenuItem *w, gpointer) {
27067 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
27068 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_chain_syntax")), TRUE);
27069 }
on_menu_item_status_adaptive_parsing_activate(GtkMenuItem * w,gpointer)27070 void on_menu_item_status_adaptive_parsing_activate(GtkMenuItem *w, gpointer) {
27071 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
27072 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_adaptive_parsing")), TRUE);
27073 }
on_menu_item_status_ignore_whitespace_activate(GtkMenuItem * w,gpointer)27074 void on_menu_item_status_ignore_whitespace_activate(GtkMenuItem *w, gpointer) {
27075 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
27076 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_ignore_whitespace")), TRUE);
27077 }
on_menu_item_status_no_special_implicit_multiplication_activate(GtkMenuItem * w,gpointer)27078 void on_menu_item_status_no_special_implicit_multiplication_activate(GtkMenuItem *w, gpointer) {
27079 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
27080 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_no_special_implicit_multiplication")), TRUE);
27081 }
27082 
on_menu_item_enable_variables_activate(GtkMenuItem * w,gpointer)27083 void on_menu_item_enable_variables_activate(GtkMenuItem *w, gpointer) {
27084 	evalops.parse_options.variables_enabled = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
27085 	expression_format_updated(evalops.parse_options.variables_enabled);
27086 }
on_menu_item_enable_functions_activate(GtkMenuItem * w,gpointer)27087 void on_menu_item_enable_functions_activate(GtkMenuItem *w, gpointer) {
27088 	evalops.parse_options.functions_enabled = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
27089 	expression_format_updated(evalops.parse_options.functions_enabled);
27090 }
on_menu_item_enable_units_activate(GtkMenuItem * w,gpointer)27091 void on_menu_item_enable_units_activate(GtkMenuItem *w, gpointer) {
27092 	evalops.parse_options.units_enabled = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
27093 	expression_format_updated(evalops.parse_options.units_enabled);
27094 }
on_menu_item_enable_unknown_variables_activate(GtkMenuItem * w,gpointer)27095 void on_menu_item_enable_unknown_variables_activate(GtkMenuItem *w, gpointer) {
27096 	evalops.parse_options.unknowns_enabled = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
27097 	expression_format_updated(evalops.parse_options.unknowns_enabled);
27098 }
on_menu_item_calculate_variables_activate(GtkMenuItem * w,gpointer)27099 void on_menu_item_calculate_variables_activate(GtkMenuItem *w, gpointer) {
27100 	evalops.calculate_variables = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
27101 	expression_calculation_updated();
27102 }
on_menu_item_enable_variable_units_activate(GtkMenuItem * w,gpointer)27103 void on_menu_item_enable_variable_units_activate(GtkMenuItem *w, gpointer) {
27104 	CALCULATOR->setVariableUnitsEnabled(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)));
27105 	expression_calculation_updated();
27106 }
on_menu_item_allow_complex_activate(GtkMenuItem * w,gpointer)27107 void on_menu_item_allow_complex_activate(GtkMenuItem *w, gpointer) {
27108 	evalops.allow_complex = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
27109 	expression_calculation_updated();
27110 }
on_menu_item_allow_infinite_activate(GtkMenuItem * w,gpointer)27111 void on_menu_item_allow_infinite_activate(GtkMenuItem *w, gpointer) {
27112 	evalops.allow_infinite = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
27113 	expression_calculation_updated();
27114 }
on_menu_item_assume_nonzero_denominators_activate(GtkMenuItem * w,gpointer)27115 void on_menu_item_assume_nonzero_denominators_activate(GtkMenuItem *w, gpointer) {
27116 	evalops.assume_denominators_nonzero = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
27117 	expression_calculation_updated();
27118 }
on_menu_item_warn_about_denominators_assumed_nonzero_activate(GtkMenuItem * w,gpointer)27119 void on_menu_item_warn_about_denominators_assumed_nonzero_activate(GtkMenuItem *w, gpointer) {
27120 	evalops.warn_about_denominators_assumed_nonzero = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
27121 	if(evalops.warn_about_denominators_assumed_nonzero) expression_calculation_updated();
27122 }
on_menu_item_algebraic_mode_simplify_activate(GtkMenuItem * w,gpointer)27123 void on_menu_item_algebraic_mode_simplify_activate(GtkMenuItem *w, gpointer) {
27124 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
27125 	evalops.structuring = STRUCTURING_SIMPLIFY;
27126 	printops.allow_factorization = false;
27127 	gtk_widget_hide(item_factorize);
27128 	gtk_widget_show(item_simplify);
27129 	PangoFontDescription *font_desc;
27130 	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);
27131 	gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "label_factorize")), (string("a(x)") + SUP_STRING("b")).c_str());
27132 	pango_font_description_free(font_desc);
27133 	gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_factorize")), _("Factorize"));
27134 	expression_calculation_updated();
27135 }
on_menu_item_algebraic_mode_factorize_activate(GtkMenuItem * w,gpointer)27136 void on_menu_item_algebraic_mode_factorize_activate(GtkMenuItem *w, gpointer) {
27137 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
27138 	evalops.structuring = STRUCTURING_FACTORIZE;
27139 	printops.allow_factorization = true;
27140 	gtk_widget_show(item_factorize);
27141 	gtk_widget_hide(item_simplify);
27142 	PangoFontDescription *font_desc;
27143 	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);
27144 	gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(main_builder, "label_factorize")), (string("x+x") + SUP_STRING("b")).c_str());
27145 	pango_font_description_free(font_desc);
27146 	gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_factorize")), _("Expand"));
27147 	expression_calculation_updated();
27148 }
on_menu_item_read_precision_activate(GtkMenuItem * w,gpointer)27149 void on_menu_item_read_precision_activate(GtkMenuItem *w, gpointer) {
27150 	 if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) evalops.parse_options.read_precision = READ_PRECISION_WHEN_DECIMALS;
27151 	 else evalops.parse_options.read_precision = DONT_READ_PRECISION;
27152 	 expression_format_updated(true);
27153 	 g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_status_read_precision"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_status_read_precision_activate, NULL);
27154 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_status_read_precision")), evalops.parse_options.read_precision != DONT_READ_PRECISION);
27155 	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_status_read_precision"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_status_read_precision_activate, NULL);
27156 }
on_menu_item_new_unknown_activate(GtkMenuItem *,gpointer)27157 void on_menu_item_new_unknown_activate(GtkMenuItem*, gpointer) {
27158 	edit_unknown(_("My Variables"), NULL, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")));
27159 }
on_menu_item_new_variable_activate(GtkMenuItem *,gpointer)27160 void on_menu_item_new_variable_activate(GtkMenuItem*, gpointer) {
27161 	edit_variable(_("My Variables"), NULL, NULL, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")));
27162 }
on_menu_item_new_matrix_activate(GtkMenuItem *,gpointer)27163 void on_menu_item_new_matrix_activate(GtkMenuItem*, gpointer) {
27164 	edit_matrix(_("Matrices"), NULL, NULL, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")), FALSE);
27165 }
on_menu_item_new_vector_activate(GtkMenuItem *,gpointer)27166 void on_menu_item_new_vector_activate(GtkMenuItem*, gpointer) {
27167 	edit_matrix(_("Vectors"), NULL, NULL, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")), TRUE);
27168 }
on_menu_item_new_function_activate(GtkMenuItem *,gpointer)27169 void on_menu_item_new_function_activate(GtkMenuItem*, gpointer) {
27170 	edit_function("", NULL, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")));
27171 }
on_menu_item_new_function_simple_activate(GtkMenuItem *,gpointer)27172 void on_menu_item_new_function_simple_activate(GtkMenuItem*, gpointer) {
27173 	edit_function_simple("", NULL, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")));
27174 }
on_menu_item_new_dataset_activate(GtkMenuItem *,gpointer)27175 void on_menu_item_new_dataset_activate(GtkMenuItem*, gpointer) {
27176 	edit_dataset(NULL, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")));
27177 }
on_menu_item_new_unit_activate(GtkMenuItem *,gpointer)27178 void on_menu_item_new_unit_activate(GtkMenuItem*, gpointer) {
27179 	edit_unit("", NULL, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")));
27180 }
27181 
on_menu_item_autocalc_activate(GtkMenuItem * w,gpointer)27182 void on_menu_item_autocalc_activate(GtkMenuItem *w, gpointer) {
27183 	if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)) == auto_calculate) return;
27184 	auto_calculate = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
27185 	if(auto_calculate && !rpn_mode) do_auto_calc();
27186 }
on_menu_item_chain_mode_activate(GtkMenuItem * w,gpointer)27187 void on_menu_item_chain_mode_activate(GtkMenuItem *w, gpointer) {
27188 	if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)) == chain_mode) return;
27189 	chain_mode = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
27190 }
on_menu_item_rpn_mode_activate(GtkMenuItem * w,gpointer)27191 void on_menu_item_rpn_mode_activate(GtkMenuItem *w, gpointer) {
27192 	set_rpn_mode(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)));
27193 }
on_menu_item_rpn_syntax_activate(GtkMenuItem * w,gpointer)27194 void on_menu_item_rpn_syntax_activate(GtkMenuItem *w, gpointer) {
27195 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
27196 	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_status_rpn_syntax"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_status_rpn_syntax_activate, NULL);
27197 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_status_rpn_syntax")), TRUE);
27198 	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_status_rpn_syntax"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_status_rpn_syntax_activate, NULL);
27199 	evalops.parse_options.parsing_mode = PARSING_MODE_RPN;
27200 	expression_format_updated(false);
27201 }
on_menu_item_limit_implicit_multiplication_activate(GtkMenuItem * w,gpointer)27202 void on_menu_item_limit_implicit_multiplication_activate(GtkMenuItem *w, gpointer) {
27203 	evalops.parse_options.limit_implicit_multiplication = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
27204 	printops.limit_implicit_multiplication = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
27205 	expression_format_updated(true);
27206 	result_format_updated();
27207 }
on_menu_item_adaptive_parsing_activate(GtkMenuItem * w,gpointer)27208 void on_menu_item_adaptive_parsing_activate(GtkMenuItem *w, gpointer) {
27209 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
27210 	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_status_adaptive_parsing"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_status_adaptive_parsing_activate, NULL);
27211 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_status_adaptive_parsing")), TRUE);
27212 	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_status_adaptive_parsing"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_status_adaptive_parsing_activate, NULL);
27213 	evalops.parse_options.parsing_mode = PARSING_MODE_ADAPTIVE;
27214 	expression_format_updated(true);
27215 }
on_menu_item_ignore_whitespace_activate(GtkMenuItem * w,gpointer)27216 void on_menu_item_ignore_whitespace_activate(GtkMenuItem *w, gpointer) {
27217 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
27218 	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_status_ignore_whitespace"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_status_ignore_whitespace_activate, NULL);
27219 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_status_ignore_whitespace")), TRUE);
27220 	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_status_ignore_whitespace"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_status_ignore_whitespace_activate, NULL);
27221 	evalops.parse_options.parsing_mode = PARSING_MODE_IMPLICIT_MULTIPLICATION_FIRST;
27222 	expression_format_updated(true);
27223 }
on_menu_item_no_special_implicit_multiplication_activate(GtkMenuItem * w,gpointer)27224 void on_menu_item_no_special_implicit_multiplication_activate(GtkMenuItem *w, gpointer) {
27225 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
27226 	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_status_no_special_implicit_multiplication"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_status_no_special_implicit_multiplication_activate, NULL);
27227 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_status_no_special_implicit_multiplication")), TRUE);
27228 	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_status_no_special_implicit_multiplication"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_status_no_special_implicit_multiplication_activate, NULL);
27229 	evalops.parse_options.parsing_mode = PARSING_MODE_CONVENTIONAL;
27230 	expression_format_updated(true);
27231 }
on_menu_item_chain_syntax_activate(GtkMenuItem * w,gpointer)27232 void on_menu_item_chain_syntax_activate(GtkMenuItem *w, gpointer) {
27233 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
27234 	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_status_chain_syntax"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_status_chain_syntax_activate, NULL);
27235 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_status_chain_syntax")), TRUE);
27236 	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_status_chain_syntax"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_status_chain_syntax_activate, NULL);
27237 	evalops.parse_options.parsing_mode = PARSING_MODE_CHAIN;
27238 	expression_format_updated(true);
27239 }
27240 
on_menu_item_fetch_exchange_rates_activate(GtkMenuItem *,gpointer)27241 void on_menu_item_fetch_exchange_rates_activate(GtkMenuItem*, gpointer) {
27242 	do_timeout = false;
27243 	fetch_exchange_rates(15);
27244 	CALCULATOR->loadExchangeRates();
27245 	display_errors(NULL, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")));
27246 	do_timeout = true;
27247 	while(gtk_events_pending()) gtk_main_iteration();
27248 	expression_calculation_updated();
27249 }
on_menu_item_save_defs_activate(GtkMenuItem *,gpointer)27250 void on_menu_item_save_defs_activate(GtkMenuItem*, gpointer) {
27251 	save_defs();
27252 }
on_menu_item_import_definitions_activate(GtkMenuItem *,gpointer)27253 void on_menu_item_import_definitions_activate(GtkMenuItem*, gpointer) {
27254 	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);
27255 	gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(d), TRUE);
27256 	GtkFileFilter *filter = gtk_file_filter_new();
27257 	//gtk_file_filter_set_name(filter, _("XML Files"));
27258 	gtk_file_filter_add_mime_type(filter, "text/xml");
27259 	gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(d), filter);
27260 	if(gtk_dialog_run(GTK_DIALOG(d)) == GTK_RESPONSE_ACCEPT) {
27261 		GFile *file = gtk_file_chooser_get_file(GTK_FILE_CHOOSER(d));
27262 		char *str = g_file_get_basename(file);
27263 		char *from_file = g_file_get_path(file);
27264 		string homedir = buildPath(getLocalDataDir(), "definitions");
27265 		recursiveMakeDir(homedir);
27266 #ifdef _WIN32
27267 		if(CopyFile(from_file, buildPath(homedir, str).c_str(), false) != 0) {
27268 			CALCULATOR->loadDefinitions(buildPath(homedir, str).c_str(), false, true);
27269 			update_fmenu();
27270 			update_vmenu();
27271 			update_umenus();
27272 		} else {
27273 			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());
27274 			gtk_dialog_run(GTK_DIALOG(dialog));
27275 			gtk_widget_destroy(dialog);
27276 		}
27277 #else
27278 		ifstream source(from_file);
27279 		if(source.fail()) {
27280 			source.close();
27281 			GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(mainwindow), (GtkDialogFlags) 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("Could not read %s."), from_file);
27282 			gtk_dialog_run(GTK_DIALOG(dialog));
27283 			gtk_widget_destroy(dialog);
27284 		} else {
27285 			ofstream dest(buildPath(homedir, str).c_str());
27286 			if(dest.fail()) {
27287 				source.close();
27288 				dest.close();
27289 				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());
27290 				gtk_dialog_run(GTK_DIALOG(dialog));
27291 				gtk_widget_destroy(dialog);
27292 			} else {
27293 				dest << source.rdbuf();
27294 				source.close();
27295 				dest.close();
27296 				CALCULATOR->loadDefinitions(buildPath(homedir, str).c_str(), false, true);
27297 				update_fmenu();
27298 				update_vmenu();
27299 				update_umenus();
27300 			}
27301 		}
27302 #endif
27303 		g_free(str);
27304 		g_free(from_file);
27305 		g_object_unref(file);
27306 	}
27307 	gtk_widget_destroy(d);
27308 }
on_menu_item_save_mode_activate(GtkMenuItem *,gpointer)27309 void on_menu_item_save_mode_activate(GtkMenuItem*, gpointer) {
27310 	save_mode();
27311 }
on_menu_item_edit_prefs_activate(GtkMenuItem *,gpointer)27312 void on_menu_item_edit_prefs_activate(GtkMenuItem*, gpointer) {
27313 	edit_preferences();
27314 }
on_menu_item_degrees_activate(GtkMenuItem * w,gpointer)27315 void on_menu_item_degrees_activate(GtkMenuItem *w, gpointer) {
27316 	if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) {
27317 		evalops.parse_options.angle_unit = ANGLE_UNIT_DEGREES;
27318 		expression_format_updated(true);
27319 		update_mb_angles(evalops.parse_options.angle_unit);
27320 	}
27321 }
on_menu_item_radians_activate(GtkMenuItem * w,gpointer)27322 void on_menu_item_radians_activate(GtkMenuItem *w, gpointer) {
27323 	if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) {
27324 		evalops.parse_options.angle_unit = ANGLE_UNIT_RADIANS;
27325 		expression_format_updated(true);
27326 		update_mb_angles(evalops.parse_options.angle_unit);
27327 	}
27328 }
on_menu_item_gradians_activate(GtkMenuItem * w,gpointer)27329 void on_menu_item_gradians_activate(GtkMenuItem *w, gpointer) {
27330 	if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) {
27331 		evalops.parse_options.angle_unit = ANGLE_UNIT_GRADIANS;
27332 		expression_format_updated(true);
27333 		update_mb_angles(evalops.parse_options.angle_unit);
27334 	}
27335 }
on_menu_item_no_default_angle_unit_activate(GtkMenuItem * w,gpointer)27336 void on_menu_item_no_default_angle_unit_activate(GtkMenuItem *w, gpointer) {
27337 	if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) {
27338 		evalops.parse_options.angle_unit = ANGLE_UNIT_NONE;
27339 		expression_format_updated(true);
27340 		update_mb_angles(evalops.parse_options.angle_unit);
27341 	}
27342 }
on_menu_item_mb_degrees_activate(GtkMenuItem * w,gpointer)27343 void on_menu_item_mb_degrees_activate(GtkMenuItem *w, gpointer) {
27344 	if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_degrees")), TRUE);
27345 }
on_menu_item_mb_radians_activate(GtkMenuItem * w,gpointer)27346 void on_menu_item_mb_radians_activate(GtkMenuItem *w, gpointer) {
27347 	if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_radians")), TRUE);
27348 }
on_menu_item_mb_gradians_activate(GtkMenuItem * w,gpointer)27349 void on_menu_item_mb_gradians_activate(GtkMenuItem *w, gpointer) {
27350 	if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_gradians")), TRUE);
27351 }
update_mb_angles(AngleUnit angle_unit)27352 void update_mb_angles(AngleUnit angle_unit) {
27353 	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_sin_degrees"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_mb_degrees_activate, NULL);
27354 	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_sin_gradians"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_mb_gradians_activate, NULL);
27355 	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_sin_radians"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_mb_radians_activate, NULL);
27356 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_sin_degrees")), angle_unit == ANGLE_UNIT_DEGREES);
27357 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_sin_gradians")), angle_unit == ANGLE_UNIT_GRADIANS);
27358 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_sin_radians")), angle_unit == ANGLE_UNIT_RADIANS);
27359 	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_sin_degrees"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_mb_degrees_activate, NULL);
27360 	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_sin_gradians"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_mb_gradians_activate, NULL);
27361 	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_sin_radians"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_mb_radians_activate, NULL);
27362 	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_cos_degrees"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_mb_degrees_activate, NULL);
27363 	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_cos_gradians"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_mb_gradians_activate, NULL);
27364 	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_cos_radians"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_mb_radians_activate, NULL);
27365 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_cos_degrees")), angle_unit == ANGLE_UNIT_DEGREES);
27366 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_cos_gradians")), angle_unit == ANGLE_UNIT_GRADIANS);
27367 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_cos_radians")), angle_unit == ANGLE_UNIT_RADIANS);
27368 	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_cos_degrees"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_mb_degrees_activate, NULL);
27369 	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_cos_gradians"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_mb_gradians_activate, NULL);
27370 	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_cos_radians"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_mb_radians_activate, NULL);
27371 	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_tan_degrees"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_mb_degrees_activate, NULL);
27372 	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_tan_gradians"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_mb_gradians_activate, NULL);
27373 	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_tan_radians"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_mb_radians_activate, NULL);
27374 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_tan_degrees")), angle_unit == ANGLE_UNIT_DEGREES);
27375 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_tan_gradians")), angle_unit == ANGLE_UNIT_GRADIANS);
27376 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_tan_radians")), angle_unit == ANGLE_UNIT_RADIANS);
27377 	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_tan_degrees"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_mb_degrees_activate, NULL);
27378 	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_tan_gradians"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_mb_gradians_activate, NULL);
27379 	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_tan_radians"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_mb_radians_activate, NULL);
27380 	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_status_degrees"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_mb_degrees_activate, NULL);
27381 	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_status_gradians"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_mb_gradians_activate, NULL);
27382 	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_status_radians"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_mb_radians_activate, NULL);
27383 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_status_degrees")), angle_unit == ANGLE_UNIT_DEGREES);
27384 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_status_gradians")), angle_unit == ANGLE_UNIT_GRADIANS);
27385 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_status_radians")), angle_unit == ANGLE_UNIT_RADIANS);
27386 	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_status_degrees"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_mb_degrees_activate, NULL);
27387 	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_status_gradians"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_mb_gradians_activate, NULL);
27388 	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_status_radians"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_mb_radians_activate, NULL);
27389 }
set_output_base_from_dialog(int base)27390 void set_output_base_from_dialog(int base) {
27391 	bool b = (printops.base == base && base != BASE_CUSTOM);
27392 	to_base = 0;
27393 	to_bits = 0;
27394 	printops.base = base;
27395 	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);
27396 	switch(printops.base) {
27397 		case BASE_BINARY: {
27398 			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);
27399 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_binary")), TRUE);
27400 			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);
27401 			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);
27402 			gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_base")), 0);
27403 			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);
27404 			output_base_updated_from_menu();
27405 			break;
27406 		}
27407 		case BASE_OCTAL: {
27408 			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);
27409 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_octal")), TRUE);
27410 			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);
27411 			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);
27412 			gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_base")), 1);
27413 			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);
27414 			output_base_updated_from_menu();
27415 			break;
27416 		}
27417 		case BASE_DECIMAL: {
27418 			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);
27419 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_decimal")), TRUE);
27420 			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);
27421 			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);
27422 			gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_base")), 2);
27423 			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);
27424 			output_base_updated_from_menu();
27425 			break;
27426 		}
27427 		case 12: {
27428 			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);
27429 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_duodecimal")), TRUE);
27430 			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);
27431 			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);
27432 			gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_base")), 3);
27433 			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);
27434 			output_base_updated_from_menu();
27435 			break;
27436 		}
27437 		case BASE_HEXADECIMAL: {
27438 			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);
27439 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_hexadecimal")), TRUE);
27440 			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);
27441 			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);
27442 			gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_base")), 4);
27443 			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);
27444 			output_base_updated_from_menu();
27445 			break;
27446 		}
27447 		case BASE_SEXAGESIMAL: {
27448 			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);
27449 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_sexagesimal")), TRUE);
27450 			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);
27451 			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);
27452 			gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_base")), 5);
27453 			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);
27454 			break;
27455 		}
27456 		case BASE_TIME: {
27457 			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);
27458 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_time_format")), TRUE);
27459 			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);
27460 			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);
27461 			gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_base")), 6);
27462 			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);
27463 			break;
27464 		}
27465 		case BASE_ROMAN_NUMERALS: {
27466 			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);
27467 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_roman")), TRUE);
27468 			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);
27469 			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);
27470 			gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_base")), 7);
27471 			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);
27472 			break;
27473 		}
27474 		default: {
27475 			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);
27476 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_custom_base")), TRUE);
27477 			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);
27478 			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);
27479 			gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_base")), 8);
27480 			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);
27481 			if(setbase_builder) {
27482 				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);
27483 				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other")), TRUE);
27484 				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);
27485 			}
27486 			break;
27487 		}
27488 	}
27489 	if(setbase_builder) 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);
27490 	update_keypad_bases();
27491 	if(!b) result_format_updated();
27492 }
output_base_updated_from_menu()27493 void output_base_updated_from_menu() {
27494 	if(setbase_builder) {
27495 		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);
27496 		switch(printops.base) {
27497 			case BASE_BINARY: {
27498 				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);
27499 				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_binary")), TRUE);
27500 				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);
27501 				break;
27502 			}
27503 			case BASE_OCTAL: {
27504 				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);
27505 				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_octal")), TRUE);
27506 				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);
27507 				break;
27508 			}
27509 			case BASE_DECIMAL: {
27510 				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);
27511 				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_decimal")), TRUE);
27512 				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);
27513 				break;
27514 			}
27515 			case 12: {
27516 				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);
27517 				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_duodecimal")), TRUE);
27518 				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);
27519 				break;
27520 			}
27521 			case BASE_HEXADECIMAL: {
27522 				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);
27523 				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_hexadecimal")), TRUE);
27524 				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);
27525 				break;
27526 			}
27527 			case BASE_SEXAGESIMAL: {
27528 				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);
27529 				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_sexagesimal")), TRUE);
27530 				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);
27531 				break;
27532 			}
27533 			case BASE_TIME: {
27534 				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);
27535 				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_time")), TRUE);
27536 				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);
27537 				break;
27538 			}
27539 			case BASE_ROMAN_NUMERALS: {
27540 				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);
27541 				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_roman")), TRUE);
27542 				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);
27543 				break;
27544 			}
27545 			case BASE_UNICODE: {
27546 				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);
27547 				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other")), TRUE);
27548 				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);
27549 				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_output_other")), "Unicode");
27550 				break;
27551 			}
27552 			case BASE_E: {
27553 				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);
27554 				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other")), TRUE);
27555 				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);
27556 				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_output_other")), "e");
27557 				break;
27558 			}
27559 			case BASE_PI: {
27560 				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);
27561 				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other")), TRUE);
27562 				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);
27563 				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_output_other")), "π");
27564 				break;
27565 			}
27566 			case BASE_GOLDEN_RATIO: {
27567 				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);
27568 				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other")), TRUE);
27569 				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);
27570 				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_output_other")), "φ");
27571 				break;
27572 			}
27573 			case BASE_SUPER_GOLDEN_RATIO: {
27574 				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);
27575 				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other")), TRUE);
27576 				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);
27577 				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_output_other")), "ψ");
27578 				break;
27579 			}
27580 			case BASE_SQRT2: {
27581 				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);
27582 				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other")), TRUE);
27583 				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);
27584 				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_output_other")), "√2");
27585 				break;
27586 			}
27587 			case BASE_BIJECTIVE_26: {
27588 				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);
27589 				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other")), TRUE);
27590 				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);
27591 				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_output_other")), _("Bijective base-26"));
27592 				break;
27593 			}
27594 			case BASE_FP16: {
27595 				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);
27596 				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other")), TRUE);
27597 				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);
27598 				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_output_other")), "fp16");
27599 				break;
27600 			}
27601 			case BASE_FP32: {
27602 				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);
27603 				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other")), TRUE);
27604 				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);
27605 				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_output_other")), "float");
27606 				break;
27607 			}
27608 			case BASE_FP64: {
27609 				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);
27610 				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other")), TRUE);
27611 				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);
27612 				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_output_other")), "double");
27613 				break;
27614 			}
27615 			case BASE_FP80: {
27616 				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);
27617 				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other")), TRUE);
27618 				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);
27619 				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_output_other")), "fp80");
27620 				break;
27621 			}
27622 			case BASE_FP128: {
27623 				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);
27624 				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other")), TRUE);
27625 				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);
27626 				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_output_other")), "fp128");
27627 				break;
27628 			}
27629 			case BASE_CUSTOM: {
27630 				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);
27631 				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other")), TRUE);
27632 				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);
27633 				PrintOptions po = printops;
27634 				po.number_fraction_format = FRACTION_DECIMAL_EXACT;
27635 				po.interval_display = INTERVAL_DISPLAY_PLUSMINUS;
27636 				po.preserve_precision = true;
27637 				po.base = 10;
27638 				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_output_other")), CALCULATOR->customOutputBase().print(po).c_str());
27639 				break;
27640 			}
27641 			default: {
27642 				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);
27643 				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other")), TRUE);
27644 				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);
27645 				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_output_other")), i2s(printops.base).c_str());
27646 			}
27647 		}
27648 		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);
27649 	}
27650 }
input_base_updated_from_menu()27651 void input_base_updated_from_menu() {
27652 	if(setbase_builder) {
27653 		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);
27654 		switch(evalops.parse_options.base) {
27655 			case BASE_BINARY: {
27656 				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);
27657 				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_binary")), TRUE);
27658 				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);
27659 				break;
27660 			}
27661 			case BASE_OCTAL: {
27662 				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);
27663 				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_octal")), TRUE);
27664 				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);
27665 				break;
27666 			}
27667 			case BASE_DECIMAL: {
27668 				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);
27669 				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_decimal")), TRUE);
27670 				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);
27671 				break;
27672 			}
27673 			case 12: {
27674 				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);
27675 				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_duodecimal")), TRUE);
27676 				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);
27677 				break;
27678 			}
27679 			case BASE_HEXADECIMAL: {
27680 				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);
27681 				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_hexadecimal")), TRUE);
27682 				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);
27683 				break;
27684 			}
27685 			case BASE_UNICODE: {
27686 				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);
27687 				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_other")), TRUE);
27688 				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);
27689 				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_input_other")), "Unicode");
27690 				break;
27691 			}
27692 			case BASE_E: {
27693 				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);
27694 				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_other")), TRUE);
27695 				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);
27696 				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_input_other")), "e");
27697 				break;
27698 			}
27699 			case BASE_PI: {
27700 				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);
27701 				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_other")), TRUE);
27702 				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);
27703 				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_input_other")), "π");
27704 				break;
27705 			}
27706 			case BASE_GOLDEN_RATIO: {
27707 				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);
27708 				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_other")), TRUE);
27709 				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);
27710 				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_input_other")), "φ");
27711 				break;
27712 			}
27713 			case BASE_SUPER_GOLDEN_RATIO: {
27714 				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);
27715 				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_other")), TRUE);
27716 				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);
27717 				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_input_other")), "ψ");
27718 				break;
27719 			}
27720 			case BASE_SQRT2: {
27721 				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);
27722 				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_other")), TRUE);
27723 				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);
27724 				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_input_other")), "√2");
27725 				break;
27726 			}
27727 			case BASE_BIJECTIVE_26: {
27728 				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);
27729 				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_other")), TRUE);
27730 				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);
27731 				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_input_other")), _("Bijective base-26"));
27732 				break;
27733 			}
27734 			case BASE_CUSTOM: {
27735 				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);
27736 				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_other")), TRUE);
27737 				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);
27738 				PrintOptions po = printops;
27739 				po.number_fraction_format = FRACTION_DECIMAL_EXACT;
27740 				po.interval_display = INTERVAL_DISPLAY_PLUSMINUS;
27741 				po.preserve_precision = true;
27742 				po.base = 10;
27743 				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_input_other")), CALCULATOR->customInputBase().print(po).c_str());
27744 				break;
27745 			}
27746 			default: {
27747 				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);
27748 				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_other")), TRUE);
27749 				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);
27750 				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_input_other")), i2s(evalops.parse_options.base).c_str());
27751 			}
27752 		}
27753 		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);
27754 	}
27755 }
27756 
27757 
on_menu_item_binary_activate(GtkMenuItem * w,gpointer)27758 void on_menu_item_binary_activate(GtkMenuItem *w, gpointer) {
27759 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
27760 	to_base = 0;
27761 	to_bits = 0;
27762 	printops.base = BASE_BINARY;
27763 	output_base_updated_from_menu();
27764 	update_keypad_bases();
27765 	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);
27766 	gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_base")), 0);
27767 	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);
27768 	result_format_updated();
27769 }
on_menu_item_octal_activate(GtkMenuItem * w,gpointer)27770 void on_menu_item_octal_activate(GtkMenuItem *w, gpointer) {
27771 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
27772 	to_base = 0;
27773 	to_bits = 0;
27774 	printops.base = BASE_OCTAL;
27775 	output_base_updated_from_menu();
27776 	update_keypad_bases();
27777 	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);
27778 	gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_base")), 1);
27779 	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);
27780 	result_format_updated();
27781 }
on_menu_item_decimal_activate(GtkMenuItem * w,gpointer)27782 void on_menu_item_decimal_activate(GtkMenuItem *w, gpointer) {
27783 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
27784 	to_base = 0;
27785 	to_bits = 0;
27786 	printops.base = BASE_DECIMAL;
27787 	output_base_updated_from_menu();
27788 	update_keypad_bases();
27789 	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);
27790 	gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_base")), 2);
27791 	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);
27792 	result_format_updated();
27793 }
on_menu_item_duodecimal_activate(GtkMenuItem * w,gpointer)27794 void on_menu_item_duodecimal_activate(GtkMenuItem *w, gpointer) {
27795 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
27796 	to_base = 0;
27797 	to_bits = 0;
27798 	printops.base = 12;
27799 	output_base_updated_from_menu();
27800 	update_keypad_bases();
27801 	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);
27802 	gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_base")), 3);
27803 	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);
27804 	result_format_updated();
27805 }
on_menu_item_hexadecimal_activate(GtkMenuItem * w,gpointer)27806 void on_menu_item_hexadecimal_activate(GtkMenuItem *w, gpointer) {
27807 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
27808 	to_base = 0;
27809 	to_bits = 0;
27810 	printops.base = BASE_HEXADECIMAL;
27811 	output_base_updated_from_menu();
27812 	update_keypad_bases();
27813 	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);
27814 	gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_base")), 4);
27815 	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);
27816 	result_format_updated();
27817 }
on_menu_item_custom_base_activate(GtkMenuItem * w,gpointer)27818 void on_menu_item_custom_base_activate(GtkMenuItem *w, gpointer) {
27819 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
27820 	GtkWidget *dialog = get_set_base_dialog();
27821 	gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")));
27822 	gtk_widget_show(dialog);
27823 	gtk_window_present_with_time(GTK_WINDOW(dialog), GDK_CURRENT_TIME);
27824 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other")), TRUE);
27825 	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(setbase_builder, "set_base_entry_output_other")));
27826 }
on_menu_item_roman_activate(GtkMenuItem * w,gpointer)27827 void on_menu_item_roman_activate(GtkMenuItem *w, gpointer) {
27828 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
27829 	to_base = 0;
27830 	to_bits = 0;
27831 	printops.base = BASE_ROMAN_NUMERALS;
27832 	output_base_updated_from_menu();
27833 	update_keypad_bases();
27834 	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);
27835 	gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_base")), 7);
27836 	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);
27837 	result_format_updated();
27838 }
on_menu_item_sexagesimal_activate(GtkMenuItem * w,gpointer)27839 void on_menu_item_sexagesimal_activate(GtkMenuItem *w, gpointer) {
27840 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
27841 	to_base = 0;
27842 	to_bits = 0;
27843 	printops.base = BASE_SEXAGESIMAL;
27844 	output_base_updated_from_menu();
27845 	update_keypad_bases();
27846 	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);
27847 	gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_base")), 5);
27848 	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);
27849 	result_format_updated();
27850 }
on_menu_item_time_format_activate(GtkMenuItem * w,gpointer)27851 void on_menu_item_time_format_activate(GtkMenuItem *w, gpointer) {
27852 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
27853 	to_base = 0;
27854 	to_bits = 0;
27855 	printops.base = BASE_TIME;
27856 	output_base_updated_from_menu();
27857 	update_keypad_bases();
27858 	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);
27859 	gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_base")), 6);
27860 	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);
27861 	result_format_updated();
27862 }
on_set_base_combo_output_other_changed(GtkComboBox *,gpointer)27863 void on_set_base_combo_output_other_changed(GtkComboBox*, gpointer) {
27864 	string str = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_output_other")));
27865 	remove_blank_ends(str);
27866 	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") || str == "fp16" || str == "float" || str == "double" || str == "fp80" || str == "fp128") on_set_base_entry_output_other_activate(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_output_other")), NULL);
27867 }
on_set_base_entry_output_other_activate(GtkEntry * w,gpointer)27868 void on_set_base_entry_output_other_activate(GtkEntry *w, gpointer) {
27869 	string str = gtk_entry_get_text(w);
27870 	remove_blank_ends(str);
27871 	if(str.empty() || str == prev_output_base) {prev_output_base = str; return;}
27872 	if(equalsIgnoreCase(str, "golden") || equalsIgnoreCase(str, "golden ratio") || str == "φ") {set_output_base_from_dialog(BASE_GOLDEN_RATIO); return;}
27873 	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;}
27874 	else if(equalsIgnoreCase(str, "unicode")) {set_output_base_from_dialog(BASE_UNICODE); return;}
27875 	else if(equalsIgnoreCase(str, "fp16") || equalsIgnoreCase(str, "binary16")) {set_output_base_from_dialog(BASE_FP16); return;}
27876 	else if(equalsIgnoreCase(str, "fp32") || equalsIgnoreCase(str, "binary32") || equalsIgnoreCase(str, "float")) {set_output_base_from_dialog(BASE_FP32); return;}
27877 	else if(equalsIgnoreCase(str, "fp64") || equalsIgnoreCase(str, "binary64") || equalsIgnoreCase(str, "double")) {set_output_base_from_dialog(BASE_FP64); return;}
27878 	else if(equalsIgnoreCase(str, "fp80")) {set_output_base_from_dialog(BASE_FP80); return;}
27879 	else if(equalsIgnoreCase(str, "fp128") || equalsIgnoreCase(str, "binary128")) {set_output_base_from_dialog(BASE_FP128); return;}
27880 	else if(equalsIgnoreCase(str, "supergolden") || equalsIgnoreCase(str, "supergolden ratio") || str == "ψ") {set_output_base_from_dialog(BASE_SUPER_GOLDEN_RATIO); return;}
27881 	else if(equalsIgnoreCase(str, "pi") || str == "π") {set_output_base_from_dialog(BASE_PI); return;}
27882 	else if(str == "e") {set_output_base_from_dialog(BASE_E); return;}
27883 	else if(str == "sqrt(2)" || str == "sqrt 2" || str == "sqrt2" || str == "√2") {set_output_base_from_dialog(BASE_SQRT2); return;}
27884 	EvaluationOptions eo = evalops;
27885 	eo.parse_options.base = 10;
27886 	eo.approximation = APPROXIMATION_TRY_EXACT;
27887 	int base;
27888 	MathStructure m;
27889 	CALCULATOR->beginTemporaryStopMessages();
27890 	CALCULATOR->calculate(&m, CALCULATOR->unlocalizeExpression(str, eo.parse_options), 500, eo);
27891 	if(CALCULATOR->endTemporaryStopMessages() || !m.isNumber() || !m.number().isReal() || (m.number().isNegative() && !m.number().isInteger()) || !(m.number() > 1 || m.number() < -1)) {
27892 		prev_output_base = str;
27893 		show_message(_("Unsupported base."), GTK_WIDGET(gtk_builder_get_object(setbase_builder, "set_base_dialog")));
27894 		return;
27895 	}
27896 	if(m.isInteger() && m.number() >= 2 && m.number() <= 36) {
27897 		base = m.number().intValue();
27898 	} else {
27899 		base = BASE_CUSTOM;
27900 		CALCULATOR->setCustomOutputBase(m.number());
27901 		prev_output_base = str;
27902 	}
27903 	set_output_base_from_dialog(base);
27904 	if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other")))) {
27905 		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);
27906 		gtk_entry_set_text(w, "");
27907 		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);
27908 	}
27909 }
on_set_base_entry_output_other_focus_out_event(GtkWidget * w,GdkEvent *,gpointer data)27910 gboolean on_set_base_entry_output_other_focus_out_event(GtkWidget *w, GdkEvent*, gpointer data) {
27911 	on_set_base_entry_output_other_activate(GTK_ENTRY(w), data);
27912 	return FALSE;
27913 }
on_set_base_radiobutton_output_binary_toggled(GtkToggleButton * w,gpointer)27914 void on_set_base_radiobutton_output_binary_toggled(GtkToggleButton *w, gpointer) {
27915 	if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) return;
27916 	set_output_base_from_dialog(BASE_BINARY);
27917 }
on_set_base_radiobutton_output_octal_toggled(GtkToggleButton * w,gpointer)27918 void on_set_base_radiobutton_output_octal_toggled(GtkToggleButton *w, gpointer) {
27919 	if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) return;
27920 	set_output_base_from_dialog(BASE_OCTAL);
27921 }
on_set_base_radiobutton_output_decimal_toggled(GtkToggleButton * w,gpointer)27922 void on_set_base_radiobutton_output_decimal_toggled(GtkToggleButton *w, gpointer) {
27923 	if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) return;
27924 	set_output_base_from_dialog(BASE_DECIMAL);
27925 }
on_set_base_radiobutton_output_duodecimal_toggled(GtkToggleButton * w,gpointer)27926 void on_set_base_radiobutton_output_duodecimal_toggled(GtkToggleButton *w, gpointer) {
27927 	if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) return;
27928 	set_output_base_from_dialog(12);
27929 }
on_set_base_radiobutton_output_hexadecimal_toggled(GtkToggleButton * w,gpointer)27930 void on_set_base_radiobutton_output_hexadecimal_toggled(GtkToggleButton *w, gpointer) {
27931 	if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) return;
27932 	set_output_base_from_dialog(BASE_HEXADECIMAL);
27933 }
on_set_base_radiobutton_output_sexagesimal_toggled(GtkToggleButton * w,gpointer)27934 void on_set_base_radiobutton_output_sexagesimal_toggled(GtkToggleButton *w, gpointer) {
27935 	if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) return;
27936 	set_output_base_from_dialog(BASE_SEXAGESIMAL);
27937 }
on_set_base_radiobutton_output_time_toggled(GtkToggleButton * w,gpointer)27938 void on_set_base_radiobutton_output_time_toggled(GtkToggleButton *w, gpointer) {
27939 	if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) return;
27940 	set_output_base_from_dialog(BASE_TIME);
27941 }
on_set_base_radiobutton_output_roman_toggled(GtkToggleButton * w,gpointer)27942 void on_set_base_radiobutton_output_roman_toggled(GtkToggleButton *w, gpointer) {
27943 	if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) return;
27944 	set_output_base_from_dialog(BASE_ROMAN_NUMERALS);
27945 }
on_set_base_radiobutton_output_other_toggled(GtkToggleButton * w,gpointer)27946 void on_set_base_radiobutton_output_other_toggled(GtkToggleButton *w, gpointer) {
27947 	if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) return;
27948 	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(setbase_builder, "set_base_entry_output_other")));
27949 	string str = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_output_other")));
27950 	remove_blank_ends(str);
27951 	if(str.empty()) {prev_output_base = str; return;}
27952 	if(equalsIgnoreCase(str, "golden") || equalsIgnoreCase(str, "golden ratio") || str == "φ") {set_output_base_from_dialog(BASE_GOLDEN_RATIO); return;}
27953 	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;}
27954 	else if(equalsIgnoreCase(str, "unicode")) {set_output_base_from_dialog(BASE_UNICODE); return;}
27955 	else if(equalsIgnoreCase(str, "fp16") || equalsIgnoreCase(str, "binary16")) {set_output_base_from_dialog(BASE_FP16); return;}
27956 	else if(equalsIgnoreCase(str, "fp32") || equalsIgnoreCase(str, "binary32") || equalsIgnoreCase(str, "float")) {set_output_base_from_dialog(BASE_FP32); return;}
27957 	else if(equalsIgnoreCase(str, "fp64") || equalsIgnoreCase(str, "binary64") || equalsIgnoreCase(str, "double")) {set_output_base_from_dialog(BASE_FP64); return;}
27958 	else if(equalsIgnoreCase(str, "fp80")) {set_output_base_from_dialog(BASE_FP80); return;}
27959 	else if(equalsIgnoreCase(str, "fp128") || equalsIgnoreCase(str, "binary128")) {set_output_base_from_dialog(BASE_FP128); return;}
27960 	else if(equalsIgnoreCase(str, "supergolden") || equalsIgnoreCase(str, "supergolden ratio") || str == "ψ") {set_output_base_from_dialog(BASE_SUPER_GOLDEN_RATIO); return;}
27961 	else if(equalsIgnoreCase(str, "pi") || str == "π") {set_output_base_from_dialog(BASE_PI); return;}
27962 	else if(str == "e") {set_output_base_from_dialog(BASE_E); return;}
27963 	else if(str == "sqrt(2)" || str == "sqrt 2" || str == "sqrt2" || str == "√2") {set_output_base_from_dialog(BASE_SQRT2); return;}
27964 	EvaluationOptions eo = evalops;
27965 	eo.parse_options.base = 10;
27966 	eo.approximation = APPROXIMATION_TRY_EXACT;
27967 	int base;
27968 	MathStructure m;
27969 	CALCULATOR->beginTemporaryStopMessages();
27970 	CALCULATOR->calculate(&m, CALCULATOR->unlocalizeExpression(str, eo.parse_options), 500, eo);
27971 	if(CALCULATOR->endTemporaryStopMessages() || !m.isNumber() || !m.number().isReal() || (m.number().isNegative() && !m.number().isInteger()) || !(m.number() > 1 || m.number() < -1)) {
27972 		prev_output_base = str;
27973 		show_message(_("Unsupported base."), GTK_WIDGET(gtk_builder_get_object(setbase_builder, "set_base_dialog")));
27974 		return;
27975 	}
27976 	if(m.isInteger() && m.number() >= 2 && m.number() <= 36) {
27977 		base = m.number().intValue();
27978 	} else {
27979 		base = BASE_CUSTOM;
27980 		CALCULATOR->setCustomOutputBase(m.number());
27981 		prev_output_base = str;
27982 	}
27983 	set_output_base_from_dialog(base);
27984 	if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_output_other")))) {
27985 		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);
27986 		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_output_other")), "");
27987 		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);
27988 	}
27989 }
on_menu_item_set_base_activate(GtkMenuItem *,gpointer)27990 void on_menu_item_set_base_activate(GtkMenuItem*, gpointer) {
27991 	GtkWidget *dialog = get_set_base_dialog();
27992 	gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")));
27993 	gtk_widget_show(dialog);
27994 	gtk_window_present_with_time(GTK_WINDOW(dialog), GDK_CURRENT_TIME);
27995 }
on_set_base_radiobutton_input_binary_toggled(GtkToggleButton * w,gpointer)27996 void on_set_base_radiobutton_input_binary_toggled(GtkToggleButton *w, gpointer) {
27997 	if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) return;
27998 	evalops.parse_options.base = BASE_BINARY;
27999 	on_historyview_selection_changed(NULL, NULL);
28000 	update_keypad_bases();
28001 	expression_format_updated(true);
28002 }
on_set_base_radiobutton_input_octal_toggled(GtkToggleButton * w,gpointer)28003 void on_set_base_radiobutton_input_octal_toggled(GtkToggleButton *w, gpointer) {
28004 	if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) return;
28005 	evalops.parse_options.base = BASE_OCTAL;
28006 	on_historyview_selection_changed(NULL, NULL);
28007 	update_keypad_bases();
28008 	expression_format_updated(true);
28009 }
on_set_base_radiobutton_input_decimal_toggled(GtkToggleButton * w,gpointer)28010 void on_set_base_radiobutton_input_decimal_toggled(GtkToggleButton *w, gpointer) {
28011 	if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) return;
28012 	evalops.parse_options.base = BASE_DECIMAL;
28013 	on_historyview_selection_changed(NULL, NULL);
28014 	update_keypad_bases();
28015 	expression_format_updated(true);
28016 }
on_set_base_radiobutton_input_duodecimal_toggled(GtkToggleButton * w,gpointer)28017 void on_set_base_radiobutton_input_duodecimal_toggled(GtkToggleButton *w, gpointer) {
28018 	if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) return;
28019 	evalops.parse_options.base = 12;
28020 	on_historyview_selection_changed(NULL, NULL);
28021 	update_keypad_bases();
28022 	expression_format_updated(true);
28023 }
on_set_base_radiobutton_input_hexadecimal_toggled(GtkToggleButton * w,gpointer)28024 void on_set_base_radiobutton_input_hexadecimal_toggled(GtkToggleButton *w, gpointer) {
28025 	if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) return;
28026 	evalops.parse_options.base = BASE_HEXADECIMAL;
28027 	on_historyview_selection_changed(NULL, NULL);
28028 	update_keypad_bases();
28029 	expression_format_updated(true);
28030 }
on_set_base_radiobutton_input_other_toggled(GtkToggleButton * w,gpointer)28031 void on_set_base_radiobutton_input_other_toggled(GtkToggleButton *w, gpointer) {
28032 	if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) return;
28033 	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(setbase_builder, "set_base_entry_input_other")));
28034 	string str = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_input_other")));
28035 	remove_blank_ends(str);
28036 	if(str.empty() || str == prev_input_base) {prev_input_base = str; return;}
28037 	if(equalsIgnoreCase(str, "golden") || equalsIgnoreCase(str, "golden ratio") || str == "φ") {evalops.parse_options.base = BASE_GOLDEN_RATIO;}
28038 	else if(equalsIgnoreCase(str, "Bijective base-26") || equalsIgnoreCase(str, _("Bijective base-26")) || str == "b26" || str == "B26") {evalops.parse_options.base = BASE_BIJECTIVE_26;}
28039 	else if(equalsIgnoreCase(str, "unicode")) {evalops.parse_options.base = BASE_UNICODE;}
28040 	else if(equalsIgnoreCase(str, "supergolden") || equalsIgnoreCase(str, "supergolden ratio") || str == "ψ") {evalops.parse_options.base = BASE_SUPER_GOLDEN_RATIO;}
28041 	else if(equalsIgnoreCase(str, "pi") || str == "π") {evalops.parse_options.base = BASE_PI;}
28042 	else if(str == "e") {evalops.parse_options.base = BASE_E;}
28043 	else if(str == "sqrt(2)" || str == "sqrt 2" || str == "sqrt2" || str == "√2") {evalops.parse_options.base = BASE_SQRT2;}
28044 	else {
28045 		EvaluationOptions eo = evalops;
28046 		eo.parse_options.base = 10;
28047 		eo.approximation = APPROXIMATION_TRY_EXACT;
28048 		MathStructure m;
28049 		CALCULATOR->beginTemporaryStopMessages();
28050 		CALCULATOR->calculate(&m, CALCULATOR->unlocalizeExpression(str, eo.parse_options), 500, eo);
28051 		if(CALCULATOR->endTemporaryStopMessages() || !m.isNumber()) {
28052 			prev_input_base = str;
28053 			show_message(_("Unsupported base."), GTK_WIDGET(gtk_builder_get_object(setbase_builder, "set_base_dialog")));
28054 			return;
28055 		}
28056 		if(m.isInteger() && m.number() >= 2 && m.number() <= 36) {
28057 			evalops.parse_options.base = m.number().intValue();
28058 			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();
28059 		} else {
28060 			evalops.parse_options.base = BASE_CUSTOM;
28061 			CALCULATOR->setCustomInputBase(m.number());
28062 		}
28063 	}
28064 	prev_input_base = str;
28065 	on_historyview_selection_changed(NULL, NULL);
28066 	update_keypad_bases();
28067 	expression_format_updated(true);
28068 	if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_other")))) {
28069 		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);
28070 		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_input_other")), "");
28071 		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);
28072 	}
28073 }
on_set_base_combo_input_other_changed(GtkComboBox *,gpointer)28074 void on_set_base_combo_input_other_changed(GtkComboBox*, gpointer) {
28075 	string str = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(setbase_builder, "set_base_entry_input_other")));
28076 	remove_blank_ends(str);
28077 	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);
28078 }
on_set_base_entry_input_other_activate(GtkEntry * w,gpointer)28079 void on_set_base_entry_input_other_activate(GtkEntry *w, gpointer) {
28080 	string str = gtk_entry_get_text(w);
28081 	remove_blank_ends(str);
28082 	if(str.empty() || str == prev_input_base) {prev_input_base = str; return;}
28083 	if(str.empty() || str == prev_input_base) {prev_input_base = str; return;}
28084 	if(equalsIgnoreCase(str, "golden") || equalsIgnoreCase(str, "golden ratio") || str == "φ") {evalops.parse_options.base = BASE_GOLDEN_RATIO;}
28085 	else if(equalsIgnoreCase(str, "Bijective base-26") || equalsIgnoreCase(str, _("Bijective base-26")) || str == "b26" || str == "B26") {evalops.parse_options.base = BASE_BIJECTIVE_26;}
28086 	else if(equalsIgnoreCase(str, "unicode")) {evalops.parse_options.base = BASE_UNICODE;}
28087 	else if(equalsIgnoreCase(str, "supergolden") || equalsIgnoreCase(str, "supergolden ratio") || str == "ψ") {evalops.parse_options.base = BASE_SUPER_GOLDEN_RATIO;}
28088 	else if(equalsIgnoreCase(str, "pi") || str == "π") {evalops.parse_options.base = BASE_PI;}
28089 	else if(str == "e") {evalops.parse_options.base = BASE_E;}
28090 	else if(str == "sqrt(2)" || str == "sqrt 2" || str == "sqrt2" || str == "√2") {evalops.parse_options.base = BASE_SQRT2;}
28091 	else {
28092 		EvaluationOptions eo = evalops;
28093 		eo.parse_options.base = 10;
28094 		eo.approximation = APPROXIMATION_TRY_EXACT;
28095 		MathStructure m;
28096 		CALCULATOR->beginTemporaryStopMessages();
28097 		CALCULATOR->calculate(&m, CALCULATOR->unlocalizeExpression(str, eo.parse_options), 500, eo);
28098 		if(CALCULATOR->endTemporaryStopMessages() || !m.isNumber()) {
28099 			prev_input_base = str;
28100 			show_message(_("Unsupported base."), GTK_WIDGET(gtk_builder_get_object(setbase_builder, "set_base_dialog")));
28101 			return;
28102 		}
28103 		if(m.isInteger() && m.number() >= 2 && m.number() <= 36) {
28104 			evalops.parse_options.base = m.number().intValue();
28105 			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) {
28106 				input_base_updated_from_menu();
28107 				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);
28108 				gtk_entry_set_text(w, "");
28109 				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);
28110 			}
28111 		} else {
28112 			evalops.parse_options.base = BASE_CUSTOM;
28113 			CALCULATOR->setCustomInputBase(m.number());
28114 		}
28115 	}
28116 	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) {
28117 		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);
28118 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(setbase_builder, "set_base_radiobutton_input_other")), TRUE);
28119 		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);
28120 	}
28121 	prev_input_base = str;
28122 	on_historyview_selection_changed(NULL, NULL);
28123 	update_keypad_bases();
28124 	expression_format_updated(true);
28125 }
on_set_base_entry_input_other_focus_out_event(GtkEntry * w,GdkEvent *,gpointer data)28126 gboolean on_set_base_entry_input_other_focus_out_event(GtkEntry *w, GdkEvent*, gpointer data) {
28127 	on_set_base_entry_input_other_activate(w, data);
28128 	return FALSE;
28129 }
on_set_base_radiobutton_input_roman_toggled(GtkToggleButton * w,gpointer)28130 void on_set_base_radiobutton_input_roman_toggled(GtkToggleButton *w, gpointer) {
28131 	if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) return;
28132 	evalops.parse_options.base = BASE_ROMAN_NUMERALS;
28133 	on_historyview_selection_changed(NULL, NULL);
28134 	update_keypad_bases();
28135 	expression_format_updated(true);
28136 }
on_menu_item_abbreviate_names_activate(GtkMenuItem * w,gpointer)28137 void on_menu_item_abbreviate_names_activate(GtkMenuItem *w, gpointer) {
28138 	printops.abbreviate_names = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
28139 	result_format_updated();
28140 }
on_menu_item_all_prefixes_activate(GtkMenuItem * w,gpointer)28141 void on_menu_item_all_prefixes_activate(GtkMenuItem *w, gpointer) {
28142 	to_prefix = 0;
28143 	printops.use_all_prefixes = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
28144 	result_format_updated();
28145 }
on_menu_item_denominator_prefixes_activate(GtkMenuItem * w,gpointer)28146 void on_menu_item_denominator_prefixes_activate(GtkMenuItem *w, gpointer) {
28147 	to_prefix = 0;
28148 	printops.use_denominator_prefix = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
28149 	result_format_updated();
28150 }
on_menu_item_place_units_separately_activate(GtkMenuItem * w,gpointer)28151 void on_menu_item_place_units_separately_activate(GtkMenuItem *w, gpointer) {
28152 	printops.place_units_separately = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
28153 	result_format_updated();
28154 }
on_menu_item_post_conversion_none_activate(GtkMenuItem * w,gpointer)28155 void on_menu_item_post_conversion_none_activate(GtkMenuItem *w, gpointer) {
28156 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28157 	evalops.auto_post_conversion = POST_CONVERSION_NONE;
28158 	expression_calculation_updated();
28159 }
on_menu_item_post_conversion_base_activate(GtkMenuItem * w,gpointer)28160 void on_menu_item_post_conversion_base_activate(GtkMenuItem *w, gpointer) {
28161 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28162 	evalops.auto_post_conversion = POST_CONVERSION_BASE;
28163 	expression_calculation_updated();
28164 }
on_menu_item_post_conversion_optimal_activate(GtkMenuItem * w,gpointer)28165 void on_menu_item_post_conversion_optimal_activate(GtkMenuItem *w, gpointer) {
28166 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28167 	evalops.auto_post_conversion = POST_CONVERSION_OPTIMAL;
28168 	expression_calculation_updated();
28169 }
on_menu_item_post_conversion_optimal_si_activate(GtkMenuItem * w,gpointer)28170 void on_menu_item_post_conversion_optimal_si_activate(GtkMenuItem *w, gpointer) {
28171 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28172 	evalops.auto_post_conversion = POST_CONVERSION_OPTIMAL_SI;
28173 	expression_calculation_updated();
28174 }
on_menu_item_mixed_units_conversion_activate(GtkMenuItem * w,gpointer)28175 void on_menu_item_mixed_units_conversion_activate(GtkMenuItem *w, gpointer) {
28176 	if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) evalops.mixed_units_conversion = MIXED_UNITS_CONVERSION_DEFAULT;
28177 	else evalops.mixed_units_conversion = MIXED_UNITS_CONVERSION_NONE;
28178 	expression_calculation_updated();
28179 }
on_menu_item_factorize_activate(GtkMenuItem *,gpointer)28180 void on_menu_item_factorize_activate(GtkMenuItem*, gpointer) {
28181 	executeCommand(COMMAND_FACTORIZE);
28182 }
on_menu_item_expand_partial_fractions_activate(GtkMenuItem *,gpointer)28183 void on_menu_item_expand_partial_fractions_activate(GtkMenuItem*, gpointer) {
28184 	executeCommand(COMMAND_EXPAND_PARTIAL_FRACTIONS);
28185 }
on_menu_item_simplify_activate(GtkMenuItem *,gpointer)28186 void on_menu_item_simplify_activate(GtkMenuItem*, gpointer) {
28187 	executeCommand(COMMAND_EXPAND);
28188 }
convert_number_bases(const gchar * initial_expression,bool b_result)28189 void convert_number_bases(const gchar *initial_expression, bool b_result) {
28190 	changing_in_nbases_dialog = false;
28191 	GtkWidget *dialog = get_nbases_dialog();
28192 	gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")));
28193 	switch(b_result ? displayed_printops.base : evalops.parse_options.base) {
28194 		case BASE_BINARY: {
28195 			gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(nbases_builder, "nbases_entry_binary")), initial_expression);
28196 			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_entry_binary")));
28197 			break;
28198 		}
28199 		case BASE_OCTAL: {
28200 			gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(nbases_builder, "nbases_entry_octal")), initial_expression);
28201 			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_entry_octal")));
28202 			break;
28203 		}
28204 		case BASE_HEXADECIMAL: {
28205 			gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(nbases_builder, "nbases_entry_hexadecimal")), initial_expression);
28206 			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_entry_hexadecimal")));
28207 			break;
28208 		}
28209 		case BASE_DUODECIMAL: {
28210 			gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(nbases_builder, "nbases_entry_duo")), initial_expression);
28211 			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_entry_duo")));
28212 			break;
28213 		}
28214 		case BASE_ROMAN_NUMERALS: {
28215 			gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(nbases_builder, "nbases_entry_roman")), initial_expression);
28216 			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_entry_roman")));
28217 			break;
28218 		}
28219 		default: {
28220 			gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(nbases_builder, "nbases_entry_decimal")), initial_expression);
28221 			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_entry_decimal")));
28222 		}
28223 	}
28224 	gtk_widget_show(dialog);
28225 	gtk_window_present_with_time(GTK_WINDOW(dialog), GDK_CURRENT_TIME);
28226 }
on_menu_item_convert_number_bases_activate(GtkMenuItem *,gpointer)28227 void on_menu_item_convert_number_bases_activate(GtkMenuItem*, gpointer) {
28228 	if(displayed_mstruct && !result_text_empty()) return convert_number_bases(((mstruct->isNumber() && !mstruct->number().hasImaginaryPart()) || mstruct->isUndefined()) ? get_result_text().c_str() : "", true);
28229 	string str = get_selected_expression_text(true), str2;
28230 	CALCULATOR->separateToExpression(str, str2, evalops, true);
28231 	remove_blank_ends(str);
28232 	convert_number_bases(str.c_str(), false);
28233 }
convert_floatingpoint(const gchar * initial_expression,bool b_result)28234 void convert_floatingpoint(const gchar *initial_expression, bool b_result) {
28235 	changing_in_fp_dialog = false;
28236 	GtkWidget *dialog = get_floatingpoint_dialog();
28237 	gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")));
28238 	switch(b_result ? displayed_printops.base : evalops.parse_options.base) {
28239 		case BASE_BINARY: {
28240 			gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(floatingpoint_builder, "fp_entry_bin")), initial_expression);
28241 			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(floatingpoint_builder, "fp_entry_bin")));
28242 			break;
28243 		}
28244 		case BASE_HEXADECIMAL: {
28245 			gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(floatingpoint_builder, "fp_entry_hex")), initial_expression);
28246 			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(floatingpoint_builder, "fp_entry_hex")));
28247 			break;
28248 		}
28249 		default: {
28250 			gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(floatingpoint_builder, "fp_entry_dec")), initial_expression);
28251 			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(floatingpoint_builder, "fp_entry_dec")));
28252 		}
28253 	}
28254 	gtk_widget_show(dialog);
28255 	gtk_window_present_with_time(GTK_WINDOW(dialog), GDK_CURRENT_TIME);
28256 }
on_menu_item_convert_floatingpoint_activate(GtkMenuItem *,gpointer)28257 void on_menu_item_convert_floatingpoint_activate(GtkMenuItem*, gpointer) {
28258 	if(displayed_mstruct && !result_text_empty()) return convert_floatingpoint(((mstruct->isNumber() && !mstruct->number().hasImaginaryPart()) || mstruct->isUndefined()) ? get_result_text().c_str() : "", true);
28259 	string str = get_selected_expression_text(true), str2;
28260 	CALCULATOR->separateToExpression(str, str2, evalops, true);
28261 	remove_blank_ends(str);
28262 	convert_floatingpoint(str.c_str(), false);
28263 }
on_button_fp_clicked(GtkWidget *,gpointer)28264 void on_button_fp_clicked(GtkWidget*, gpointer) {
28265 	on_menu_item_convert_floatingpoint_activate(NULL, NULL);
28266 }
show_percentage_dialog(const gchar * initial_expression)28267 void show_percentage_dialog(const gchar *initial_expression) {
28268 	GtkWidget *dialog = get_percentage_dialog();
28269 	gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")));
28270 	on_percentage_button_clear_clicked(NULL, NULL);
28271 	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);
28272 	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(percentage_builder, "percentage_entry_1")));
28273 	gtk_widget_show(dialog);
28274 	gtk_window_present_with_time(GTK_WINDOW(dialog), GDK_CURRENT_TIME);
28275 }
on_menu_item_show_percentage_dialog_activate(GtkMenuItem *,gpointer)28276 void on_menu_item_show_percentage_dialog_activate(GtkMenuItem*, gpointer) {
28277 	if(!result_text_empty()) return show_percentage_dialog(get_result_text().c_str());
28278 	string str = get_selected_expression_text(true), str2;
28279 	CALCULATOR->separateToExpression(str, str2, evalops, true);
28280 	remove_blank_ends(str);
28281 	show_percentage_dialog(str.c_str());
28282 }
show_calendarconversion_dialog()28283 void show_calendarconversion_dialog() {
28284 	GtkWidget *dialog = get_calendarconversion_dialog();
28285 	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(calendarconversion_builder, "year_1")));
28286 	gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")));
28287 	gtk_widget_show(dialog);
28288 	gtk_window_present_with_time(GTK_WINDOW(dialog), GDK_CURRENT_TIME);
28289 }
28290 bool block_calendar_conversion = false;
calendar_changed(GtkWidget *,gpointer data)28291 void calendar_changed(GtkWidget*, gpointer data) {
28292 	if(block_calendar_conversion) return;
28293 	block_calendar_conversion = true;
28294 	gint i = GPOINTER_TO_INT(data);
28295 	long int y;
28296 	if(i == CALENDAR_CHINESE) {
28297 		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);
28298 		if(cy <= 0) {
28299 			show_message(_("The selected Chinese year does not exist."), GTK_WIDGET(gtk_builder_get_object(calendarconversion_builder, "calendar_dialog")));
28300 			block_calendar_conversion = false;
28301 			return;
28302 		}
28303 		y = chineseCycleYearToYear(79, cy);
28304 	} else {
28305 		y = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(cal_year[(size_t) i]));
28306 	}
28307 	long int m = gtk_combo_box_get_active(GTK_COMBO_BOX(cal_month[(size_t) i])) + 1;
28308 	long int d = gtk_combo_box_get_active(GTK_COMBO_BOX(cal_day[(size_t) i])) + 1;
28309 	QalculateDateTime date;
28310 	if(!calendarToDate(date, y, m, d, (CalendarSystem) i)) {
28311 		show_message(_("Conversion to Gregorian calendar failed."), GTK_WIDGET(gtk_builder_get_object(calendarconversion_builder, "calendar_dialog")));
28312 		block_calendar_conversion = false;
28313 		return;
28314 	}
28315 	string failed_str;
28316 	for(size_t i2 = 0; i2 < NUMBER_OF_CALENDARS; i2++) {
28317 		if(cal_day.count(i2) > 0) {
28318 			if(dateToCalendar(date, y, m, d, (CalendarSystem) i2) && y <= G_MAXINT && y >= G_MININT && m <= numberOfMonths((CalendarSystem) i2) && d <= 31) {
28319 				if(i2 == CALENDAR_CHINESE) {
28320 					long int cy, yc, st, br;
28321 					chineseYearInfo(y, cy, yc, st, br);
28322 					gtk_combo_box_set_active(GTK_COMBO_BOX(chinese_stem), (st - 1) / 2);
28323 					gtk_combo_box_set_active(GTK_COMBO_BOX(chinese_branch), br - 1);
28324 				} else {
28325 					gtk_spin_button_set_value(GTK_SPIN_BUTTON(cal_year[i2]), y);
28326 				}
28327 				gtk_combo_box_set_active(GTK_COMBO_BOX(cal_month[i2]), m - 1);
28328 				gtk_combo_box_set_active(GTK_COMBO_BOX(cal_day[i2]), d - 1);
28329 			} else {
28330 				if(!failed_str.empty()) failed_str += ", ";
28331 				failed_str += gtk_label_get_text(GTK_LABEL(cal_label[i2]));
28332 			}
28333 		}
28334 	}
28335 	if(!failed_str.empty()) {
28336 		gchar *gstr = g_strdup_printf(_("Calendar conversion failed for: %s."), failed_str.c_str());
28337 		show_message(gstr, GTK_WIDGET(gtk_builder_get_object(calendarconversion_builder, "calendar_dialog")));
28338 		g_free(gstr);
28339 	}
28340 	block_calendar_conversion = false;
28341 }
28342 
on_menu_item_show_calendarconversion_dialog_activate(GtkMenuItem *,gpointer)28343 void on_menu_item_show_calendarconversion_dialog_activate(GtkMenuItem*, gpointer) {
28344 	show_calendarconversion_dialog();
28345 	if(displayed_mstruct && mstruct && mstruct->isDateTime()) {
28346 		gtk_spin_button_set_value(GTK_SPIN_BUTTON(cal_year[CALENDAR_GREGORIAN]), mstruct->datetime()->year());
28347 		gtk_combo_box_set_active(GTK_COMBO_BOX(cal_month[CALENDAR_GREGORIAN]), mstruct->datetime()->month() - 1);
28348 		gtk_combo_box_set_active(GTK_COMBO_BOX(cal_day[CALENDAR_GREGORIAN]), mstruct->datetime()->day() - 1);
28349 	}
28350 }
on_popup_menu_item_calendarconversion_activate(GtkMenuItem * w,gpointer)28351 void on_popup_menu_item_calendarconversion_activate(GtkMenuItem *w, gpointer) {
28352 	show_calendarconversion_dialog();
28353 	if(mstruct && mstruct->isDateTime()) {
28354 		gtk_spin_button_set_value(GTK_SPIN_BUTTON(cal_year[CALENDAR_GREGORIAN]), mstruct->datetime()->year());
28355 		gtk_combo_box_set_active(GTK_COMBO_BOX(cal_month[CALENDAR_GREGORIAN]), mstruct->datetime()->month() - 1);
28356 		gtk_combo_box_set_active(GTK_COMBO_BOX(cal_day[CALENDAR_GREGORIAN]), mstruct->datetime()->day() - 1);
28357 	}
28358 }
on_popup_menu_item_to_utc_activate(GtkMenuItem * w,gpointer)28359 void on_popup_menu_item_to_utc_activate(GtkMenuItem *w, gpointer) {
28360 	menu_to_utc(w, NULL);
28361 }
on_menu_item_periodic_table_activate(GtkMenuItem *,gpointer)28362 void on_menu_item_periodic_table_activate(GtkMenuItem*, gpointer) {
28363 	GtkWidget *dialog = get_periodic_dialog();
28364 	gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")));
28365 	gtk_widget_show(dialog);
28366 	gtk_window_present_with_time(GTK_WINDOW(dialog), GDK_CURRENT_TIME);
28367 }
on_menu_item_plot_functions_activate(GtkMenuItem *,gpointer)28368 void on_menu_item_plot_functions_activate(GtkMenuItem*, gpointer) {
28369 	GtkWidget *dialog = get_plot_dialog();
28370 	if(!dialog) {
28371 		GtkWidget *edialog = gtk_message_dialog_new(GTK_WINDOW(mainwindow), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("Gnuplot was not found."));
28372 		gtk_message_dialog_format_secondary_markup(GTK_MESSAGE_DIALOG(edialog), _("%s (%s) needs to be installed separately, and found in the executable search path, for plotting to work."), "Gnuplot", "<a href=\"http://www.gnuplot.info/\">http://www.gnuplot.info/</a>");
28373 		GList *childlist = gtk_container_get_children(GTK_CONTAINER(gtk_message_dialog_get_message_area(GTK_MESSAGE_DIALOG(edialog))));
28374 		for(guint i = 0; ; i++) {
28375 			GtkWidget *w = (GtkWidget*) g_list_nth_data(childlist, i);
28376 			if(!w) break;
28377 			g_signal_connect(G_OBJECT(w), "activate-link", G_CALLBACK(on_activate_link), NULL);
28378 		}
28379 		g_list_free(childlist);
28380 		gtk_dialog_run(GTK_DIALOG(edialog));
28381 		gtk_widget_destroy(edialog);
28382 		return;
28383 	}
28384 	gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")));
28385 	string str = get_selected_expression_text(), str2;
28386 	CALCULATOR->separateToExpression(str, str2, evalops, true);
28387 	remove_blank_ends(str);
28388 	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_expression")), evalops.parse_options.base == 10 ? str.c_str() : "");
28389 	if(!gtk_widget_get_visible(dialog)) {
28390 		gtk_list_store_clear(tPlotFunctions_store);
28391 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_button_modify")), FALSE);
28392 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_button_remove")), FALSE);
28393 
28394 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_checkbutton_grid")), default_plot_display_grid);
28395 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_checkbutton_full_border")), default_plot_full_border);
28396 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_checkbutton_rows")), default_plot_rows);
28397 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_radiobutton_color")), default_plot_color);
28398 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_radiobutton_mono")), !default_plot_color);
28399 		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_min")), default_plot_min.c_str());
28400 		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_max")), default_plot_max.c_str());
28401 		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_step")), default_plot_step.c_str());
28402 		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_variable")), default_plot_variable.c_str());
28403 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_radiobutton_steps")), default_plot_use_sampling_rate);
28404 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_radiobutton_step")), !default_plot_use_sampling_rate);
28405 		switch(default_plot_type) {
28406 			case 1: {gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_radiobutton_vector")), TRUE); break;}
28407 			case 2: {gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_radiobutton_paired")), TRUE); break;}
28408 			default: {gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_radiobutton_function")), TRUE); break;}
28409 		}
28410 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_checkbutton_rows")), default_plot_type == 1 || default_plot_type == 2);
28411 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_box_variable")), default_plot_type != 1 && default_plot_type != 2);
28412 		switch(default_plot_legend_placement) {
28413 			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;}
28414 			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;}
28415 			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;}
28416 			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;}
28417 			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;}
28418 			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;}
28419 			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;}
28420 		}
28421 		switch(default_plot_smoothing) {
28422 			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;}
28423 			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;}
28424 			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;}
28425 			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;}
28426 			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;}
28427 		}
28428 		switch(default_plot_style) {
28429 			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;}
28430 			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;}
28431 			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;}
28432 			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;}
28433 			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;}
28434 			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;}
28435 			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;}
28436 			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;}
28437 		}
28438 		gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(plot_builder, "plot_spinbutton_steps")), default_plot_sampling_rate);
28439 		gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(plot_builder, "plot_spinbutton_linewidth")), default_plot_linewidth);
28440 
28441 		gtk_widget_show(dialog);
28442 		gtk_notebook_set_current_page(GTK_NOTEBOOK(gtk_builder_get_object(plot_builder, "plot_notebook")), 2);
28443 		gtk_notebook_set_current_page(GTK_NOTEBOOK(gtk_builder_get_object(plot_builder, "plot_notebook")), 1);
28444 		gtk_notebook_set_current_page(GTK_NOTEBOOK(gtk_builder_get_object(plot_builder, "plot_notebook")), 0);
28445 
28446 		gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_entry_expression")));
28447 	} else {
28448 		gtk_window_present_with_time(GTK_WINDOW(dialog), GDK_CURRENT_TIME);
28449 	}
28450 }
on_plot_dialog_hide(GtkWidget *,gpointer)28451 void on_plot_dialog_hide(GtkWidget*, gpointer) {
28452 	default_plot_display_grid = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_checkbutton_grid")));
28453 	default_plot_full_border = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_checkbutton_full_border")));
28454 	default_plot_rows = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_checkbutton_rows")));
28455 	default_plot_color = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_radiobutton_color")));
28456 	default_plot_min = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_min")));
28457 	default_plot_max = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_max")));
28458 	default_plot_step = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_step")));
28459 	default_plot_variable = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_variable")));
28460 	default_plot_use_sampling_rate = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_radiobutton_steps")));
28461 	if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_radiobutton_vector")))) {
28462 		default_plot_type = 1;
28463 	} else if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_radiobutton_paired")))) {
28464 		default_plot_type = 2;
28465 	} else {
28466 		default_plot_type = 0;
28467 	}
28468 	switch(gtk_combo_box_get_active(GTK_COMBO_BOX(gtk_builder_get_object(plot_builder, "plot_combobox_legend_place")))) {
28469 		case PLOTLEGEND_MENU_NONE: {default_plot_legend_placement = PLOT_LEGEND_NONE; break;}
28470 		case PLOTLEGEND_MENU_TOP_LEFT: {default_plot_legend_placement = PLOT_LEGEND_TOP_LEFT; break;}
28471 		case PLOTLEGEND_MENU_TOP_RIGHT: {default_plot_legend_placement = PLOT_LEGEND_TOP_RIGHT; break;}
28472 		case PLOTLEGEND_MENU_BOTTOM_LEFT: {default_plot_legend_placement = PLOT_LEGEND_BOTTOM_LEFT; break;}
28473 		case PLOTLEGEND_MENU_BOTTOM_RIGHT: {default_plot_legend_placement = PLOT_LEGEND_BOTTOM_RIGHT; break;}
28474 		case PLOTLEGEND_MENU_BELOW: {default_plot_legend_placement = PLOT_LEGEND_BELOW; break;}
28475 		case PLOTLEGEND_MENU_OUTSIDE: {default_plot_legend_placement = PLOT_LEGEND_OUTSIDE; break;}
28476 	}
28477 	switch(gtk_combo_box_get_active(GTK_COMBO_BOX(gtk_builder_get_object(plot_builder, "plot_combobox_smoothing")))) {
28478 		case SMOOTHING_MENU_NONE: {default_plot_smoothing = PLOT_SMOOTHING_NONE; break;}
28479 		case SMOOTHING_MENU_UNIQUE: {default_plot_smoothing = PLOT_SMOOTHING_UNIQUE; break;}
28480 		case SMOOTHING_MENU_CSPLINES: {default_plot_smoothing = PLOT_SMOOTHING_CSPLINES; break;}
28481 		case SMOOTHING_MENU_BEZIER: {default_plot_smoothing = PLOT_SMOOTHING_BEZIER; break;}
28482 		case SMOOTHING_MENU_SBEZIER: {default_plot_smoothing = PLOT_SMOOTHING_SBEZIER; break;}
28483 	}
28484 	switch(gtk_combo_box_get_active(GTK_COMBO_BOX(gtk_builder_get_object(plot_builder, "plot_combobox_style")))) {
28485 		case PLOTSTYLE_MENU_LINES: {default_plot_style = PLOT_STYLE_LINES; break;}
28486 		case PLOTSTYLE_MENU_POINTS: {default_plot_style = PLOT_STYLE_POINTS; break;}
28487 		case PLOTSTYLE_MENU_LINESPOINTS: {default_plot_style = PLOT_STYLE_POINTS_LINES; break;}
28488 		case PLOTSTYLE_MENU_BOXES: {default_plot_style = PLOT_STYLE_BOXES; break;}
28489 		case PLOTSTYLE_MENU_HISTEPS: {default_plot_style = PLOT_STYLE_HISTOGRAM; break;}
28490 		case PLOTSTYLE_MENU_STEPS: {default_plot_style = PLOT_STYLE_STEPS; break;}
28491 		case PLOTSTYLE_MENU_CANDLESTICKS: {default_plot_style = PLOT_STYLE_CANDLESTICKS; break;}
28492 		case PLOTSTYLE_MENU_DOTS: {default_plot_style = PLOT_STYLE_DOTS; break;}
28493 	}
28494 	default_plot_sampling_rate = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_builder_get_object(plot_builder, "plot_spinbutton_steps")));
28495 	default_plot_linewidth = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_builder_get_object(plot_builder, "plot_spinbutton_linewidth")));
28496 	GtkTreeIter iter;
28497 	bool b = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tPlotFunctions_store), &iter);
28498 	while(b) {
28499 		MathStructure *y_vector, *x_vector;
28500 		gtk_tree_model_get(GTK_TREE_MODEL(tPlotFunctions_store), &iter, 7, &x_vector, 8, &y_vector, -1);
28501 		if(y_vector) delete y_vector;
28502 		if(x_vector) delete x_vector;
28503 		b = gtk_tree_model_iter_next(GTK_TREE_MODEL(tPlotFunctions_store), &iter);
28504 	}
28505 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_button_save")), false);
28506 	CALCULATOR->closeGnuplot();
28507 }
on_popup_menu_item_abort_activate(GtkMenuItem *,gpointer)28508 void on_popup_menu_item_abort_activate(GtkMenuItem*, gpointer) {
28509 	if(b_busy_expression) on_abort_calculation(NULL, 0, NULL);
28510 	else if(b_busy_result) on_abort_display(NULL, 0, NULL);
28511 	else if(b_busy_command) on_abort_command(NULL, 0, NULL);
28512 }
on_popup_menu_item_clear_activate(GtkMenuItem *,gpointer)28513 void on_popup_menu_item_clear_activate(GtkMenuItem*, gpointer) {
28514 	clear_expression_text();
28515 	focus_keeping_selection();
28516 }
on_popup_menu_item_display_normal_activate(GtkMenuItem * w,gpointer)28517 void on_popup_menu_item_display_normal_activate(GtkMenuItem *w, gpointer) {
28518 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28519 	gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_numerical_display")), 0);
28520 }
on_popup_menu_item_exact_activate(GtkMenuItem * w,gpointer)28521 void on_popup_menu_item_exact_activate(GtkMenuItem *w, gpointer) {
28522 	if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_always_exact")), true);
28523 	else gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_try_exact")), true);
28524 }
on_popup_menu_item_assume_nonzero_denominators_activate(GtkMenuItem * w,gpointer)28525 void on_popup_menu_item_assume_nonzero_denominators_activate(GtkMenuItem *w, gpointer) {
28526 	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)));
28527 }
on_popup_menu_item_display_engineering_activate(GtkMenuItem * w,gpointer)28528 void on_popup_menu_item_display_engineering_activate(GtkMenuItem *w, gpointer) {
28529 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28530 	gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_numerical_display")), 1);
28531 }
on_popup_menu_item_display_scientific_activate(GtkMenuItem * w,gpointer)28532 void on_popup_menu_item_display_scientific_activate(GtkMenuItem *w, gpointer) {
28533 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28534 	gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_numerical_display")), 2);
28535 }
on_popup_menu_item_display_purely_scientific_activate(GtkMenuItem * w,gpointer)28536 void on_popup_menu_item_display_purely_scientific_activate(GtkMenuItem *w, gpointer) {
28537 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28538 	gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_numerical_display")), 3);
28539 }
on_popup_menu_item_display_non_scientific_activate(GtkMenuItem * w,gpointer)28540 void on_popup_menu_item_display_non_scientific_activate(GtkMenuItem *w, gpointer) {
28541 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28542 	gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_numerical_display")), 4);
28543 }
on_popup_menu_item_complex_rectangular_activate(GtkMenuItem * w,gpointer)28544 void on_popup_menu_item_complex_rectangular_activate(GtkMenuItem *w, gpointer) {
28545 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28546 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_complex_rectangular")), TRUE);
28547 }
on_popup_menu_item_complex_exponential_activate(GtkMenuItem * w,gpointer)28548 void on_popup_menu_item_complex_exponential_activate(GtkMenuItem *w, gpointer) {
28549 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28550 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_complex_exponential")), TRUE);
28551 }
on_popup_menu_item_complex_polar_activate(GtkMenuItem * w,gpointer)28552 void on_popup_menu_item_complex_polar_activate(GtkMenuItem *w, gpointer) {
28553 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28554 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_complex_polar")), TRUE);
28555 }
on_popup_menu_item_complex_angle_activate(GtkMenuItem * w,gpointer)28556 void on_popup_menu_item_complex_angle_activate(GtkMenuItem *w, gpointer) {
28557 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28558 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_complex_angle")), TRUE);
28559 }
on_popup_menu_item_display_no_prefixes_activate(GtkMenuItem * w,gpointer)28560 void on_popup_menu_item_display_no_prefixes_activate(GtkMenuItem *w, gpointer) {
28561 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28562 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_display_no_prefixes")), TRUE);
28563 }
on_popup_menu_item_display_prefixes_for_selected_units_activate(GtkMenuItem * w,gpointer)28564 void on_popup_menu_item_display_prefixes_for_selected_units_activate(GtkMenuItem *w, gpointer) {
28565 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28566 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_display_prefixes_for_selected_units")), TRUE);
28567 }
on_popup_menu_item_display_prefixes_for_all_units_activate(GtkMenuItem * w,gpointer)28568 void on_popup_menu_item_display_prefixes_for_all_units_activate(GtkMenuItem *w, gpointer) {
28569 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28570 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_display_prefixes_for_all_units")), TRUE);
28571 }
on_popup_menu_item_display_prefixes_for_currencies_activate(GtkMenuItem * w,gpointer)28572 void on_popup_menu_item_display_prefixes_for_currencies_activate(GtkMenuItem *w, gpointer) {
28573 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28574 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_display_prefixes_for_currencies")), TRUE);
28575 }
on_popup_menu_item_mixed_units_conversion_activate(GtkMenuItem * w,gpointer)28576 void on_popup_menu_item_mixed_units_conversion_activate(GtkMenuItem *w, gpointer) {
28577 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_mixed_units_conversion")), gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)));
28578 }
on_popup_menu_item_fraction_decimal_activate(GtkMenuItem * w,gpointer)28579 void on_popup_menu_item_fraction_decimal_activate(GtkMenuItem *w, gpointer) {
28580 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28581 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_fraction_decimal")), TRUE);
28582 }
on_popup_menu_item_fraction_decimal_exact_activate(GtkMenuItem * w,gpointer)28583 void on_popup_menu_item_fraction_decimal_exact_activate(GtkMenuItem *w, gpointer) {
28584 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28585 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_fraction_decimal_exact")), TRUE);
28586 }
on_popup_menu_item_fraction_combined_activate(GtkMenuItem * w,gpointer)28587 void on_popup_menu_item_fraction_combined_activate(GtkMenuItem *w, gpointer) {
28588 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28589 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_fraction_combined")), TRUE);
28590 }
on_popup_menu_item_fraction_fraction_activate(GtkMenuItem * w,gpointer)28591 void on_popup_menu_item_fraction_fraction_activate(GtkMenuItem *w, gpointer) {
28592 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28593 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_fraction_fraction")), TRUE);
28594 }
on_popup_menu_item_binary_activate(GtkMenuItem * w,gpointer)28595 void on_popup_menu_item_binary_activate(GtkMenuItem *w, gpointer) {
28596 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28597 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_binary")), TRUE);
28598 }
on_popup_menu_item_roman_activate(GtkMenuItem * w,gpointer)28599 void on_popup_menu_item_roman_activate(GtkMenuItem *w, gpointer) {
28600 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28601 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_roman")), TRUE);
28602 }
on_popup_menu_item_sexagesimal_activate(GtkMenuItem * w,gpointer)28603 void on_popup_menu_item_sexagesimal_activate(GtkMenuItem *w, gpointer) {
28604 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28605 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_sexagesimal")), TRUE);
28606 }
on_popup_menu_item_time_format_activate(GtkMenuItem * w,gpointer)28607 void on_popup_menu_item_time_format_activate(GtkMenuItem *w, gpointer) {
28608 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28609 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_time_format")), TRUE);
28610 }
on_popup_menu_item_octal_activate(GtkMenuItem * w,gpointer)28611 void on_popup_menu_item_octal_activate(GtkMenuItem *w, gpointer) {
28612 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28613 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_octal")), TRUE);
28614 }
on_popup_menu_item_decimal_activate(GtkMenuItem * w,gpointer)28615 void on_popup_menu_item_decimal_activate(GtkMenuItem *w, gpointer) {
28616 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28617 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_decimal")), TRUE);
28618 }
on_popup_menu_item_duodecimal_activate(GtkMenuItem * w,gpointer)28619 void on_popup_menu_item_duodecimal_activate(GtkMenuItem *w, gpointer) {
28620 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28621 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_duodecimal")), TRUE);
28622 }
on_popup_menu_item_hexadecimal_activate(GtkMenuItem * w,gpointer)28623 void on_popup_menu_item_hexadecimal_activate(GtkMenuItem *w, gpointer) {
28624 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28625 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_hexadecimal")), TRUE);
28626 }
on_popup_menu_item_custom_base_activate(GtkMenuItem * w,gpointer)28627 void on_popup_menu_item_custom_base_activate(GtkMenuItem *w, gpointer) {
28628 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28629 	gtk_menu_item_activate(GTK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_custom_base")));
28630 }
on_popup_menu_item_abbreviate_names_activate(GtkMenuItem * w,gpointer)28631 void on_popup_menu_item_abbreviate_names_activate(GtkMenuItem *w, gpointer) {
28632 	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)));
28633 }
on_popup_menu_item_all_prefixes_activate(GtkMenuItem * w,gpointer)28634 void on_popup_menu_item_all_prefixes_activate(GtkMenuItem *w, gpointer) {
28635 	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)));
28636 }
on_popup_menu_item_denominator_prefixes_activate(GtkMenuItem * w,gpointer)28637 void on_popup_menu_item_denominator_prefixes_activate(GtkMenuItem *w, gpointer) {
28638 	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)));
28639 }
on_popup_menu_item_view_matrix_activate(GtkMenuItem *,gpointer)28640 void on_popup_menu_item_view_matrix_activate(GtkMenuItem*, gpointer) {
28641 	insert_matrix(mstruct, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")), false, false, true);
28642 }
on_popup_menu_item_view_vector_activate(GtkMenuItem *,gpointer)28643 void on_popup_menu_item_view_vector_activate(GtkMenuItem*, gpointer) {
28644 	insert_matrix(mstruct, GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")), true, false, true);
28645 }
28646 
on_menu_item_display_normal_activate(GtkMenuItem * w,gpointer)28647 void on_menu_item_display_normal_activate(GtkMenuItem *w, gpointer) {
28648 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)))
28649 		return;
28650 	printops.min_exp = EXP_PRECISION;
28651 	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);
28652 	gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_numerical_display")), 0);
28653 	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);
28654 	result_format_updated();
28655 }
on_menu_item_display_engineering_activate(GtkMenuItem * w,gpointer)28656 void on_menu_item_display_engineering_activate(GtkMenuItem *w, gpointer) {
28657 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)))
28658 		return;
28659 	printops.min_exp = EXP_BASE_3;
28660 	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);
28661 	gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_numerical_display")), 1);
28662 	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);
28663 	result_format_updated();
28664 }
on_menu_item_display_scientific_activate(GtkMenuItem * w,gpointer)28665 void on_menu_item_display_scientific_activate(GtkMenuItem *w, gpointer) {
28666 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)))
28667 		return;
28668 	printops.min_exp = EXP_SCIENTIFIC;
28669 	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);
28670 	gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_numerical_display")), 2);
28671 	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);
28672 	result_format_updated();
28673 }
on_menu_item_display_purely_scientific_activate(GtkMenuItem * w,gpointer)28674 void on_menu_item_display_purely_scientific_activate(GtkMenuItem *w, gpointer) {
28675 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)))
28676 		return;
28677 	printops.min_exp = EXP_PURE;
28678 	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);
28679 	gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_numerical_display")), 3);
28680 	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);
28681 	result_format_updated();
28682 }
on_menu_item_display_non_scientific_activate(GtkMenuItem * w,gpointer)28683 void on_menu_item_display_non_scientific_activate(GtkMenuItem *w, gpointer) {
28684 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)))
28685 		return;
28686 	printops.min_exp = EXP_NONE;
28687 	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);
28688 	gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_numerical_display")), 4);
28689 	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);
28690 	result_format_updated();
28691 }
on_menu_item_display_no_prefixes_activate(GtkMenuItem * w,gpointer)28692 void on_menu_item_display_no_prefixes_activate(GtkMenuItem *w, gpointer) {
28693 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28694 	to_prefix = 0;
28695 	printops.use_unit_prefixes = false;
28696 	printops.use_prefixes_for_all_units = false;
28697 	printops.use_prefixes_for_currencies = false;
28698 	if(printops.min_exp != EXP_NONE && printops.min_exp != EXP_PRECISION) scientific_noprefix = true;
28699 	auto_prefix = 0;
28700 	result_format_updated();
28701 }
on_menu_item_display_prefixes_for_selected_units_activate(GtkMenuItem * w,gpointer)28702 void on_menu_item_display_prefixes_for_selected_units_activate(GtkMenuItem *w, gpointer) {
28703 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28704 	to_prefix = 0;
28705 	printops.use_unit_prefixes = true;
28706 	printops.use_prefixes_for_all_units = false;
28707 	printops.use_prefixes_for_currencies = false;
28708 	if(printops.min_exp != EXP_NONE && printops.min_exp != EXP_PRECISION) scientific_noprefix = false;
28709 	auto_prefix = 0;
28710 	result_format_updated();
28711 }
on_menu_item_display_prefixes_for_currencies_activate(GtkMenuItem * w,gpointer)28712 void on_menu_item_display_prefixes_for_currencies_activate(GtkMenuItem *w, gpointer) {
28713 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28714 	to_prefix = 0;
28715 	printops.use_unit_prefixes = true;
28716 	printops.use_prefixes_for_all_units = false;
28717 	printops.use_prefixes_for_currencies = true;
28718 	if(printops.min_exp != EXP_NONE && printops.min_exp != EXP_PRECISION) scientific_noprefix = false;
28719 	auto_prefix = 0;
28720 	result_format_updated();
28721 }
on_menu_item_display_prefixes_for_all_units_activate(GtkMenuItem * w,gpointer)28722 void on_menu_item_display_prefixes_for_all_units_activate(GtkMenuItem *w, gpointer) {
28723 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28724 	to_prefix = 0;
28725 	printops.use_unit_prefixes = true;
28726 	printops.use_prefixes_for_all_units = true;
28727 	printops.use_prefixes_for_currencies = true;
28728 	gint i = gtk_combo_box_get_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_numerical_display")));
28729 	if(i != 0 && i != 4) scientific_noprefix = false;
28730 	auto_prefix = 0;
28731 	result_format_updated();
28732 }
on_menu_item_indicate_infinite_series_activate(GtkMenuItem * w,gpointer)28733 void on_menu_item_indicate_infinite_series_activate(GtkMenuItem *w, gpointer) {
28734 	printops.indicate_infinite_series = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
28735 	result_format_updated();
28736 }
on_menu_item_show_ending_zeroes_activate(GtkMenuItem * w,gpointer)28737 void on_menu_item_show_ending_zeroes_activate(GtkMenuItem *w, gpointer) {
28738 	printops.show_ending_zeroes = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
28739 	result_format_updated();
28740 }
on_menu_item_round_halfway_to_even_activate(GtkMenuItem * w,gpointer)28741 void on_menu_item_round_halfway_to_even_activate(GtkMenuItem *w, gpointer) {
28742 	printops.round_halfway_to_even = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
28743 	result_format_updated();
28744 }
on_menu_item_negative_exponents_activate(GtkMenuItem * w,gpointer)28745 void on_menu_item_negative_exponents_activate(GtkMenuItem *w, gpointer) {
28746 	printops.negative_exponents = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
28747 	if(printops.min_exp != EXP_NONE && printops.min_exp != EXP_PRECISION) scientific_negexp = printops.negative_exponents;
28748 	result_format_updated();
28749 }
on_menu_item_sort_minus_last_activate(GtkMenuItem * w,gpointer)28750 void on_menu_item_sort_minus_last_activate(GtkMenuItem *w, gpointer) {
28751 	printops.sort_options.minus_last = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
28752 	if(printops.min_exp != EXP_NONE && printops.min_exp != EXP_PRECISION) scientific_notminuslast = !printops.sort_options.minus_last;
28753 	result_format_updated();
28754 }
on_menu_item_always_exact_activate(GtkMenuItem * w,gpointer)28755 void on_menu_item_always_exact_activate(GtkMenuItem *w, gpointer) {
28756 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28757 	evalops.approximation = APPROXIMATION_EXACT;
28758 
28759 	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);
28760 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "button_exact")), TRUE);
28761 	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);
28762 
28763 	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_status_exact"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_status_exact_activate, NULL);
28764 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_status_exact")), TRUE);
28765 	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_status_exact"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_status_exact_activate, NULL);
28766 
28767 	if(printops.number_fraction_format == FRACTION_DECIMAL) {
28768 		if(!rpn_mode) block_result_update++;
28769 		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_fraction_decimal_exact")), TRUE);
28770 		automatic_fraction = true;
28771 		if(!rpn_mode) block_result_update--;
28772 	}
28773 
28774 	expression_calculation_updated();
28775 }
on_menu_item_interval_arithmetic_activate(GtkMenuItem * w,gpointer)28776 void on_menu_item_interval_arithmetic_activate(GtkMenuItem *w, gpointer) {
28777 	CALCULATOR->useIntervalArithmetic(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)));
28778 	expression_calculation_updated();
28779 }
28780 
restore_automatic_fraction()28781 void restore_automatic_fraction() {
28782 	if(automatic_fraction && printops.number_fraction_format == FRACTION_DECIMAL_EXACT) {
28783 		if(!rpn_mode) block_result_update++;
28784 		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_fraction_decimal")), TRUE);
28785 		automatic_fraction = false;
28786 		if(!rpn_mode) block_result_update--;
28787 	}
28788 }
28789 
on_menu_item_try_exact_activate(GtkMenuItem * w,gpointer)28790 void on_menu_item_try_exact_activate(GtkMenuItem *w, gpointer) {
28791 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28792 	evalops.approximation = APPROXIMATION_TRY_EXACT;
28793 
28794 	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);
28795 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "button_exact")), FALSE);
28796 	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);
28797 
28798 	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_status_exact"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_status_exact_activate, NULL);
28799 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_status_exact")), FALSE);
28800 	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_status_exact"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_status_exact_activate, NULL);
28801 
28802 	restore_automatic_fraction();
28803 
28804 	expression_calculation_updated();
28805 }
on_menu_item_approximate_activate(GtkMenuItem * w,gpointer)28806 void on_menu_item_approximate_activate(GtkMenuItem *w, gpointer) {
28807 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28808 	evalops.approximation = APPROXIMATION_APPROXIMATE;
28809 
28810 	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);
28811 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "button_exact")), FALSE);
28812 	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);
28813 
28814 	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_status_exact"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_status_exact_activate, NULL);
28815 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_status_exact")), FALSE);
28816 	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "menu_item_status_exact"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_menu_item_status_exact_activate, NULL);
28817 
28818 	restore_automatic_fraction();
28819 
28820 	expression_calculation_updated();
28821 }
on_menu_item_ic_none_activate(GtkMenuItem * w,gpointer)28822 void on_menu_item_ic_none_activate(GtkMenuItem *w, gpointer) {
28823 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28824 	evalops.interval_calculation = INTERVAL_CALCULATION_NONE;
28825 	expression_calculation_updated();
28826 }
on_menu_item_ic_variance_activate(GtkMenuItem * w,gpointer)28827 void on_menu_item_ic_variance_activate(GtkMenuItem *w, gpointer) {
28828 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28829 	evalops.interval_calculation = INTERVAL_CALCULATION_VARIANCE_FORMULA;
28830 	expression_calculation_updated();
28831 }
on_menu_item_ic_interval_arithmetic_activate(GtkMenuItem * w,gpointer)28832 void on_menu_item_ic_interval_arithmetic_activate(GtkMenuItem *w, gpointer) {
28833 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28834 	evalops.interval_calculation = INTERVAL_CALCULATION_INTERVAL_ARITHMETIC;
28835 	expression_calculation_updated();
28836 }
on_menu_item_ic_simple_activate(GtkMenuItem * w,gpointer)28837 void on_menu_item_ic_simple_activate(GtkMenuItem *w, gpointer) {
28838 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28839 	evalops.interval_calculation = INTERVAL_CALCULATION_SIMPLE_INTERVAL_ARITHMETIC;
28840 	expression_calculation_updated();
28841 }
28842 
on_menu_item_fraction_decimal_activate(GtkMenuItem * w,gpointer)28843 void on_menu_item_fraction_decimal_activate(GtkMenuItem *w, gpointer) {
28844 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28845 	to_fraction = false;
28846 	printops.number_fraction_format = FRACTION_DECIMAL;
28847 	printops.restrict_fraction_length = false;
28848 	automatic_fraction = false;
28849 
28850 	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "button_fraction"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_button_fraction_toggled, NULL);
28851 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "button_fraction")), FALSE);
28852 	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "button_fraction"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_button_fraction_toggled, NULL);
28853 
28854 	result_format_updated();
28855 }
on_menu_item_fraction_decimal_exact_activate(GtkMenuItem * w,gpointer)28856 void on_menu_item_fraction_decimal_exact_activate(GtkMenuItem *w, gpointer) {
28857 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28858 	to_fraction = false;
28859 	printops.number_fraction_format = FRACTION_DECIMAL_EXACT;
28860 	printops.restrict_fraction_length = false;
28861 	automatic_fraction = false;
28862 
28863 	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "button_fraction"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_button_fraction_toggled, NULL);
28864 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "button_fraction")), FALSE);
28865 	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "button_fraction"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_button_fraction_toggled, NULL);
28866 
28867 	result_format_updated();
28868 }
on_menu_item_fraction_combined_activate(GtkMenuItem * w,gpointer)28869 void on_menu_item_fraction_combined_activate(GtkMenuItem *w, gpointer) {
28870 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28871 	to_fraction = false;
28872 	printops.number_fraction_format = FRACTION_COMBINED;
28873 	printops.restrict_fraction_length = true;
28874 	automatic_fraction = false;
28875 	default_fraction_fraction = FRACTION_COMBINED;
28876 
28877 	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "button_fraction"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_button_fraction_toggled, NULL);
28878 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "button_fraction")), TRUE);
28879 	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "button_fraction"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_button_fraction_toggled, NULL);
28880 
28881 	result_format_updated();
28882 }
on_menu_item_fraction_fraction_activate(GtkMenuItem * w,gpointer)28883 void on_menu_item_fraction_fraction_activate(GtkMenuItem *w, gpointer) {
28884 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28885 	to_fraction = false;
28886 	printops.number_fraction_format = FRACTION_FRACTIONAL;
28887 	printops.restrict_fraction_length = true;
28888 	automatic_fraction = false;
28889 	default_fraction_fraction = FRACTION_FRACTIONAL;
28890 
28891 	g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(main_builder, "button_fraction"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_button_fraction_toggled, NULL);
28892 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "button_fraction")), TRUE);
28893 	g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(main_builder, "button_fraction"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_button_fraction_toggled, NULL);
28894 
28895 	result_format_updated();
28896 }
on_menu_item_interval_adaptive_activate(GtkMenuItem * w,gpointer)28897 void on_menu_item_interval_adaptive_activate(GtkMenuItem *w, gpointer) {
28898 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28899 	adaptive_interval_display = true;
28900 	printops.interval_display = INTERVAL_DISPLAY_SIGNIFICANT_DIGITS;
28901 	result_format_updated();
28902 }
on_menu_item_interval_significant_activate(GtkMenuItem * w,gpointer)28903 void on_menu_item_interval_significant_activate(GtkMenuItem *w, gpointer) {
28904 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28905 	adaptive_interval_display = false;
28906 	printops.interval_display = INTERVAL_DISPLAY_SIGNIFICANT_DIGITS;
28907 	result_format_updated();
28908 }
on_menu_item_interval_interval_activate(GtkMenuItem * w,gpointer)28909 void on_menu_item_interval_interval_activate(GtkMenuItem *w, gpointer) {
28910 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28911 	adaptive_interval_display = false;
28912 	printops.interval_display = INTERVAL_DISPLAY_INTERVAL;
28913 	result_format_updated();
28914 }
on_menu_item_interval_plusminus_activate(GtkMenuItem * w,gpointer)28915 void on_menu_item_interval_plusminus_activate(GtkMenuItem *w, gpointer) {
28916 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28917 	adaptive_interval_display = false;
28918 	printops.interval_display = INTERVAL_DISPLAY_PLUSMINUS;
28919 	result_format_updated();
28920 }
on_menu_item_interval_midpoint_activate(GtkMenuItem * w,gpointer)28921 void on_menu_item_interval_midpoint_activate(GtkMenuItem *w, gpointer) {
28922 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28923 	adaptive_interval_display = false;
28924 	printops.interval_display = INTERVAL_DISPLAY_MIDPOINT;
28925 	result_format_updated();
28926 }
28927 
on_menu_item_complex_rectangular_activate(GtkMenuItem * w,gpointer)28928 void on_menu_item_complex_rectangular_activate(GtkMenuItem *w, gpointer) {
28929 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28930 	evalops.complex_number_form = COMPLEX_NUMBER_FORM_RECTANGULAR;
28931 	complex_angle_form = false;
28932 	to_caf = -1;
28933 	expression_calculation_updated();
28934 }
on_menu_item_complex_exponential_activate(GtkMenuItem * w,gpointer)28935 void on_menu_item_complex_exponential_activate(GtkMenuItem *w, gpointer) {
28936 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28937 	evalops.complex_number_form = COMPLEX_NUMBER_FORM_EXPONENTIAL;
28938 	complex_angle_form = false;
28939 	to_caf = -1;
28940 	expression_calculation_updated();
28941 }
on_menu_item_complex_polar_activate(GtkMenuItem * w,gpointer)28942 void on_menu_item_complex_polar_activate(GtkMenuItem *w, gpointer) {
28943 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28944 	evalops.complex_number_form = COMPLEX_NUMBER_FORM_POLAR;
28945 	complex_angle_form = false;
28946 	to_caf = -1;
28947 	expression_calculation_updated();
28948 }
on_menu_item_complex_angle_activate(GtkMenuItem * w,gpointer)28949 void on_menu_item_complex_angle_activate(GtkMenuItem *w, gpointer) {
28950 	if(!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) return;
28951 	evalops.complex_number_form = COMPLEX_NUMBER_FORM_CIS;
28952 	complex_angle_form = true;
28953 	to_caf = -1;
28954 	expression_calculation_updated();
28955 }
28956 
on_menu_item_save_activate(GtkMenuItem *,gpointer)28957 void on_menu_item_save_activate(GtkMenuItem*, gpointer) {
28958 	add_as_variable();
28959 }
on_menu_item_save_image_activate(GtkMenuItem *,gpointer)28960 void on_menu_item_save_image_activate(GtkMenuItem*, gpointer) {
28961 	if(display_aborted || !displayed_mstruct) return;
28962 	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);
28963 	gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(d), TRUE);
28964 	GtkFileFilter *filter = gtk_file_filter_new();
28965 	gtk_file_filter_set_name(filter, _("Allowed File Types"));
28966 	gtk_file_filter_add_mime_type(filter, "image/png");
28967 	gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(d), filter);
28968 	GtkFileFilter *filter_all = gtk_file_filter_new();
28969 	gtk_file_filter_add_pattern(filter_all, "*");
28970 	gtk_file_filter_set_name(filter_all, _("All Files"));
28971 	gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(d), filter_all);
28972 	gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(d), "qalculate.png");
28973 	if(gtk_dialog_run(GTK_DIALOG(d)) == GTK_RESPONSE_ACCEPT) {
28974 		GdkRGBA color;
28975 		color.red = 0.0;
28976 		color.green = 0.0;
28977 		color.blue = 0.0;
28978 		color.alpha = 1.0;
28979 		cairo_surface_t *s = draw_structure(*displayed_mstruct, displayed_printops, displayed_caf, top_ips, NULL, 1, &color);
28980 		if(s) {
28981 			cairo_surface_flush(s);
28982 			cairo_surface_write_to_png(s, gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(d)));
28983 			cairo_surface_destroy(s);
28984 		}
28985 	}
28986 	gtk_widget_destroy(d);
28987 }
on_menu_item_copy_activate(GtkMenuItem *,gpointer)28988 void on_menu_item_copy_activate(GtkMenuItem*, gpointer) {
28989 	string copy_text = get_result_text();
28990 	if(!copy_separator) {
28991 		remove_separator(copy_text);
28992 	}
28993 	gtk_clipboard_set_text(gtk_clipboard_get(gdk_atom_intern("CLIPBOARD", FALSE)), copy_text.c_str(), -1);
28994 }
on_menu_item_precision_activate(GtkMenuItem *,gpointer)28995 void on_menu_item_precision_activate(GtkMenuItem*, gpointer) {
28996 	GtkWidget *dialog = get_precision_dialog();
28997 	gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")));
28998 	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);
28999 	gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(precision_builder, "precision_dialog_spinbutton_precision")), PRECISION);
29000 	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);
29001 	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(precision_builder, "precision_dialog_spinbutton_precision")));
29002 	gtk_widget_show(dialog);
29003 }
on_menu_item_decimals_activate(GtkMenuItem *,gpointer)29004 void on_menu_item_decimals_activate(GtkMenuItem*, gpointer) {
29005 	GtkWidget *dialog = get_decimals_dialog();
29006 	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(decimals_builder, "decimals_dialog_checkbutton_min")));
29007 	gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")));
29008 	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);
29009 	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);
29010 	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);
29011 	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);
29012 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (gtk_builder_get_object(decimals_builder, "decimals_dialog_checkbutton_min")), printops.use_min_decimals);
29013 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (gtk_builder_get_object(decimals_builder, "decimals_dialog_checkbutton_max")), printops.use_max_decimals);
29014 	gtk_widget_set_sensitive (GTK_WIDGET(gtk_builder_get_object(decimals_builder, "decimals_dialog_spinbutton_min")), printops.use_min_decimals);
29015 	gtk_widget_set_sensitive (GTK_WIDGET(gtk_builder_get_object(decimals_builder, "decimals_dialog_spinbutton_max")), printops.use_max_decimals);
29016 	gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(decimals_builder, "decimals_dialog_spinbutton_min")), printops.min_decimals);
29017 	gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(decimals_builder, "decimals_dialog_spinbutton_max")), printops.max_decimals);
29018 	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);
29019 	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);
29020 	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);
29021 	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);
29022 	gtk_widget_show(dialog);
29023 }
29024 
on_button_registerup_clicked(GtkButton *,gpointer)29025 void on_button_registerup_clicked(GtkButton*, gpointer) {
29026 	GtkTreeModel *model;
29027 	GtkTreeIter iter, iter2;
29028 	GtkTreePath *path;
29029 	gint index;
29030 	if(!gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(stackview)), &model, &iter)) {
29031 		model = gtk_tree_view_get_model(GTK_TREE_VIEW(stackview));
29032 		if(!gtk_tree_model_get_iter_first(model, &iter)) return;
29033 	}
29034 	path = gtk_tree_model_get_path(model, &iter);
29035 	index = gtk_tree_path_get_indices(path)[0];
29036 	gtk_tree_path_free(path);
29037 	g_signal_handlers_block_matched((gpointer) stackstore, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_stackstore_row_inserted, NULL);
29038 	g_signal_handlers_block_matched((gpointer) stackstore, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_stackstore_row_deleted, NULL);
29039 	if(index == 0) {
29040 		CALCULATOR->moveRPNRegister(1, CALCULATOR->RPNStackSize());
29041 		gtk_tree_model_iter_nth_child(model, &iter2, NULL, CALCULATOR->RPNStackSize() - 1);
29042 		gtk_list_store_move_after(stackstore, &iter, &iter2);
29043 	} else {
29044 		CALCULATOR->moveRPNRegisterUp(index + 1);
29045 		gtk_tree_model_iter_nth_child(model, &iter2, NULL, index - 1);
29046 		gtk_list_store_swap(stackstore, &iter, &iter2);
29047 	}
29048 	g_signal_handlers_unblock_matched((gpointer) stackstore, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_stackstore_row_inserted, NULL);
29049 	g_signal_handlers_unblock_matched((gpointer) stackstore, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_stackstore_row_deleted, NULL);
29050 	if(index <= 1) {
29051 		mstruct->unref();
29052 		mstruct = CALCULATOR->getRPNRegister(1);
29053 		mstruct->ref();
29054 		setResult(NULL, true, false, false, "", 0, true);
29055 	}
29056 	updateRPNIndexes();
29057 }
on_button_registerdown_clicked(GtkButton *,gpointer)29058 void on_button_registerdown_clicked(GtkButton*, gpointer) {
29059 	GtkTreeModel *model;
29060 	GtkTreeIter iter, iter2;
29061 	GtkTreePath *path;
29062 	gint index;
29063 	if(!gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(stackview)), &model, &iter)) {
29064 		model = gtk_tree_view_get_model(GTK_TREE_VIEW(stackview));
29065 		if(CALCULATOR->RPNStackSize() == 0) return;
29066 		if(!gtk_tree_model_iter_nth_child(model, &iter, NULL, CALCULATOR->RPNStackSize() - 1)) return;
29067 	}
29068 	path = gtk_tree_model_get_path(model, &iter);
29069 	index = gtk_tree_path_get_indices(path)[0];
29070 	gtk_tree_path_free(path);
29071 	g_signal_handlers_block_matched((gpointer) stackstore, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_stackstore_row_inserted, NULL);
29072 	g_signal_handlers_block_matched((gpointer) stackstore, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_stackstore_row_deleted, NULL);
29073 	if(index + 1 == (int) CALCULATOR->RPNStackSize()) {
29074 		CALCULATOR->moveRPNRegister(CALCULATOR->RPNStackSize(), 1);
29075 		gtk_tree_model_get_iter_first(model, &iter2);
29076 		gtk_list_store_move_before(stackstore, &iter, &iter2);
29077 	} else {
29078 		CALCULATOR->moveRPNRegisterDown(index + 1);
29079 		gtk_tree_model_iter_nth_child(model, &iter2, NULL, index + 1);
29080 		gtk_list_store_swap(stackstore, &iter, &iter2);
29081 	}
29082 	g_signal_handlers_unblock_matched((gpointer) stackstore, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_stackstore_row_inserted, NULL);
29083 	g_signal_handlers_unblock_matched((gpointer) stackstore, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_stackstore_row_deleted, NULL);
29084 	if(index == 0 || index == (int) CALCULATOR->RPNStackSize() - 1) {
29085 		mstruct->unref();
29086 		mstruct = CALCULATOR->getRPNRegister(1);
29087 		mstruct->ref();
29088 		setResult(NULL, true, false, false, "", 0, true);
29089 	}
29090 	updateRPNIndexes();
29091 }
on_button_registerswap_clicked(GtkButton *,gpointer)29092 void on_button_registerswap_clicked(GtkButton*, gpointer) {
29093 	GtkTreeModel *model;
29094 	GtkTreeIter iter, iter2;
29095 	GtkTreePath *path;
29096 	gint index;
29097 	if(!gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(stackview)), &model, &iter)) {
29098 		model = gtk_tree_view_get_model(GTK_TREE_VIEW(stackview));
29099 		if(!gtk_tree_model_get_iter_first(model, &iter)) return;
29100 	}
29101 	path = gtk_tree_model_get_path(model, &iter);
29102 	index = gtk_tree_path_get_indices(path)[0];
29103 	gtk_tree_path_free(path);
29104 	g_signal_handlers_block_matched((gpointer) stackstore, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_stackstore_row_inserted, NULL);
29105 	g_signal_handlers_block_matched((gpointer) stackstore, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_stackstore_row_deleted, NULL);
29106 	if(index == 0) {
29107 		if(!gtk_tree_model_iter_nth_child(model, &iter2, NULL, 1)) return;
29108 		CALCULATOR->moveRPNRegister(1, 2);
29109 		gtk_list_store_swap(stackstore, &iter, &iter2);
29110 	} else {
29111 		CALCULATOR->moveRPNRegister(index + 1, 1);
29112 		gtk_tree_model_get_iter_first(model, &iter2);
29113 		gtk_list_store_move_before(stackstore, &iter, &iter2);
29114 	}
29115 	g_signal_handlers_unblock_matched((gpointer) stackstore, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_stackstore_row_inserted, NULL);
29116 	g_signal_handlers_unblock_matched((gpointer) stackstore, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_stackstore_row_deleted, NULL);
29117 	mstruct->unref();
29118 	mstruct = CALCULATOR->getRPNRegister(1);
29119 	mstruct->ref();
29120 	setResult(NULL, true, false, false, "", 0, true);
29121 	updateRPNIndexes();
29122 }
on_button_lastx_clicked(GtkButton *,gpointer)29123 void on_button_lastx_clicked(GtkButton*, gpointer) {
29124 	if(expression_has_changed) {
29125 		if(get_expression_text().find_first_not_of(SPACES) != string::npos) {
29126 			execute_expression(true);
29127 		}
29128 	}
29129 	CALCULATOR->RPNStackEnter(new MathStructure(lastx));
29130 	RPNRegisterAdded("", 0);
29131 	mstruct->unref();
29132 	mstruct = CALCULATOR->getRPNRegister(1);
29133 	mstruct->ref();
29134 	setResult(NULL, true, true, false, "", 0, false);
29135 }
on_button_copyregister_clicked(GtkButton *,gpointer)29136 void on_button_copyregister_clicked(GtkButton*, gpointer) {
29137 	GtkTreeModel *model;
29138 	GtkTreeIter iter;
29139 	GtkTreePath *path;
29140 	gchar *text_copy = NULL;
29141 	gint index;
29142 	if(!gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(stackview)), &model, &iter)) {
29143 		model = gtk_tree_view_get_model(GTK_TREE_VIEW(stackview));
29144 		if(!gtk_tree_model_get_iter_first(model, &iter)) return;
29145 	}
29146 	path = gtk_tree_model_get_path(model, &iter);
29147 	index = gtk_tree_path_get_indices(path)[0];
29148 	gtk_tree_path_free(path);
29149 	CALCULATOR->RPNStackEnter(new MathStructure(*CALCULATOR->getRPNRegister(index + 1)));
29150 	gtk_tree_model_get(model, &iter, 1, &text_copy, -1);
29151 	RPNRegisterAdded(text_copy, 0);
29152 	g_free(text_copy);
29153 	mstruct->unref();
29154 	mstruct = CALCULATOR->getRPNRegister(1);
29155 	mstruct->ref();
29156 	setResult(NULL, true, false, false, "", 0, true);
29157 }
on_button_editregister_clicked(GtkButton *,gpointer)29158 void on_button_editregister_clicked(GtkButton*, gpointer) {
29159 	GtkTreeModel *model;
29160 	GtkTreeIter iter;
29161 	GtkTreePath *path;
29162 	if(gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(stackview)), &model, &iter)) {
29163 		path = gtk_tree_model_get_path(model, &iter);
29164 		gtk_tree_view_set_cursor_on_cell(GTK_TREE_VIEW(stackview), path, register_column, register_renderer, TRUE);
29165 		gtk_tree_path_free(path);
29166 	}
29167 }
on_button_deleteregister_clicked(GtkButton *,gpointer)29168 void on_button_deleteregister_clicked(GtkButton*, gpointer) {
29169 	GtkTreeModel *model;
29170 	GtkTreeIter iter;
29171 	GtkTreePath *path;
29172 	gint index;
29173 	if(!gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(stackview)), &model, &iter)) {
29174 		model = gtk_tree_view_get_model(GTK_TREE_VIEW(stackview));
29175 		if(!gtk_tree_model_get_iter_first(model, &iter)) return;
29176 	}
29177 	path = gtk_tree_model_get_path(model, &iter);
29178 	index = gtk_tree_path_get_indices(path)[0];
29179 	gtk_tree_path_free(path);
29180 	CALCULATOR->deleteRPNRegister(index + 1);
29181 	RPNRegisterRemoved(index);
29182 	if(CALCULATOR->RPNStackSize() == 0) {
29183 		clearresult();
29184 		mstruct->clear();
29185 	} else if(index == 0) {
29186 		mstruct->unref();
29187 		mstruct = CALCULATOR->getRPNRegister(1);
29188 		mstruct->ref();
29189 		setResult(NULL, true, false, false, "", 0, true);
29190 	}
29191 }
on_button_clearstack_clicked(GtkButton *,gpointer)29192 void on_button_clearstack_clicked(GtkButton*, gpointer) {
29193 	CALCULATOR->clearRPNStack();
29194 	g_signal_handlers_block_matched((gpointer) stackstore, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_stackstore_row_deleted, NULL);
29195 	gtk_list_store_clear(stackstore);
29196 	g_signal_handlers_unblock_matched((gpointer) stackstore, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_stackstore_row_deleted, NULL);
29197 	clearresult();
29198 	mstruct->clear();
29199 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_clearstack")), FALSE);
29200 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_copyregister")), FALSE);
29201 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_deleteregister")), FALSE);
29202 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_registerdown")), FALSE);
29203 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_registerup")), FALSE);
29204 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_registerswap")), FALSE);
29205 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_sqrt")), FALSE);
29206 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_reciprocal")), FALSE);
29207 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_negate")), FALSE);
29208 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_sum")), FALSE);
29209 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_add")), FALSE);
29210 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_sub")), FALSE);
29211 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_times")), FALSE);
29212 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_divide")), FALSE);
29213 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_rpn_xy")), FALSE);
29214 }
on_stackview_selection_changed(GtkTreeSelection * treeselection,gpointer)29215 void on_stackview_selection_changed(GtkTreeSelection *treeselection, gpointer) {
29216 	GtkTreeModel *model;
29217 	GtkTreeIter iter;
29218 	if(gtk_tree_selection_get_selected(treeselection, &model, &iter)) {
29219 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_editregister")), TRUE);
29220 	} else {
29221 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "button_editregister")), FALSE);
29222 	}
29223 }
on_stackview_item_edited(GtkCellRendererText *,gchar * path,gchar * new_text,gpointer)29224 void on_stackview_item_edited(GtkCellRendererText*, gchar *path, gchar *new_text, gpointer) {
29225 	int index = s2i(path);
29226 	GtkTreeIter iter;
29227 	gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(stackstore), &iter, NULL, index);
29228 	gtk_list_store_set(stackstore, &iter, 1, new_text, -1);
29229 	execute_expression(true, false, OPERATION_ADD, NULL, true, index);
29230 	b_editing_stack = false;
29231 }
on_stackview_item_editing_started(GtkCellRenderer *,GtkCellEditable *,gchar *,gpointer)29232 void on_stackview_item_editing_started(GtkCellRenderer*, GtkCellEditable*, gchar*, gpointer) {
29233 	b_editing_stack = true;
29234 }
on_stackview_item_editing_canceled(GtkCellRenderer *,gpointer)29235 void on_stackview_item_editing_canceled(GtkCellRenderer*, gpointer) {
29236 	b_editing_stack = false;
29237 }
29238 int inserted_stack_index = -1;
on_stackstore_row_inserted(GtkTreeModel *,GtkTreePath * path,GtkTreeIter *,gpointer)29239 void on_stackstore_row_inserted(GtkTreeModel*, GtkTreePath *path, GtkTreeIter*, gpointer) {
29240 	inserted_stack_index = gtk_tree_path_get_indices(path)[0];
29241 }
on_stackstore_row_deleted(GtkTreeModel *,GtkTreePath * path,gpointer)29242 void on_stackstore_row_deleted(GtkTreeModel*, GtkTreePath *path, gpointer) {
29243 	if(inserted_stack_index >= 0) {
29244 		CALCULATOR->moveRPNRegister(gtk_tree_path_get_indices(path)[0] + 1, inserted_stack_index + 1);
29245 		inserted_stack_index = -1;
29246 		updateRPNIndexes();
29247 	}
29248 }
29249 
selected_register_function(MathFunction * f)29250 void selected_register_function(MathFunction *f) {
29251 	if(!f) return;
29252 	GtkTreeModel *model;
29253 	GtkTreeIter iter;
29254 	if(!gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(stackview)), &model, &iter)) return;
29255 	GtkTreePath *path = gtk_tree_model_get_path(model, &iter);
29256 	gint index = gtk_tree_path_get_indices(path)[0];
29257 	gtk_tree_path_free(path);
29258 	execute_expression(true, true, OPERATION_ADD, f, true, index);
29259 }
on_popup_menu_item_stack_copytext_activate(GtkMenuItem *,gpointer)29260 void on_popup_menu_item_stack_copytext_activate(GtkMenuItem*, gpointer) {
29261 	GtkTreeModel *model;
29262 	GtkTreeIter iter;
29263 	if(!gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(stackview)), &model, &iter)) return;
29264 	gchar *gstr;
29265 	gtk_tree_model_get(model, &iter, 1, &gstr, -1);
29266 	gtk_clipboard_set_text(gtk_clipboard_get(gdk_atom_intern("CLIPBOARD", FALSE)), gstr, -1);
29267 	g_free(gstr);
29268 }
on_popup_menu_item_stack_inserttext_activate(GtkMenuItem *,gpointer)29269 void on_popup_menu_item_stack_inserttext_activate(GtkMenuItem*, gpointer) {
29270 	GtkTreeModel *model;
29271 	GtkTreeIter iter;
29272 	if(!gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(stackview)), &model, &iter)) return;
29273 	gchar *gstr;
29274 	gtk_tree_model_get(model, &iter, 1, &gstr, -1);
29275 	insert_text(gstr);
29276 	g_free(gstr);
29277 }
on_popup_menu_item_stack_negate_activate(GtkMenuItem *,gpointer)29278 void on_popup_menu_item_stack_negate_activate(GtkMenuItem*, gpointer) {
29279 	selected_register_function(CALCULATOR->getActiveFunction("neg"));
29280 }
on_popup_menu_item_stack_invert_activate(GtkMenuItem *,gpointer)29281 void on_popup_menu_item_stack_invert_activate(GtkMenuItem*, gpointer) {
29282 	selected_register_function(CALCULATOR->getActiveFunction("inv"));
29283 }
on_popup_menu_item_stack_square_activate(GtkMenuItem *,gpointer)29284 void on_popup_menu_item_stack_square_activate(GtkMenuItem*, gpointer) {
29285 	selected_register_function(CALCULATOR->f_sq);
29286 }
on_popup_menu_item_stack_sqrt_activate(GtkMenuItem *,gpointer)29287 void on_popup_menu_item_stack_sqrt_activate(GtkMenuItem*, gpointer) {
29288 	selected_register_function(CALCULATOR->f_sqrt);
29289 }
on_popup_menu_item_stack_copy_activate(GtkMenuItem *,gpointer)29290 void on_popup_menu_item_stack_copy_activate(GtkMenuItem*, gpointer) {
29291 	on_button_copyregister_clicked(NULL, NULL);
29292 }
on_popup_menu_item_stack_movetotop_activate(GtkMenuItem *,gpointer)29293 void on_popup_menu_item_stack_movetotop_activate(GtkMenuItem*, gpointer) {
29294 	GtkTreeModel *model;
29295 	GtkTreeIter iter, iter2;
29296 	GtkTreePath *path;
29297 	gint index;
29298 	if(!gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(stackview)), &model, &iter)) return;
29299 	path = gtk_tree_model_get_path(model, &iter);
29300 	index = gtk_tree_path_get_indices(path)[0];
29301 	gtk_tree_path_free(path);
29302 	g_signal_handlers_block_matched((gpointer) stackstore, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_stackstore_row_inserted, NULL);
29303 	g_signal_handlers_block_matched((gpointer) stackstore, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_stackstore_row_deleted, NULL);
29304 	CALCULATOR->moveRPNRegister(index + 1, 1);
29305 	gtk_tree_model_get_iter_first(model, &iter2);
29306 	gtk_list_store_move_before(stackstore, &iter, &iter2);
29307 	g_signal_handlers_unblock_matched((gpointer) stackstore, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_stackstore_row_inserted, NULL);
29308 	g_signal_handlers_unblock_matched((gpointer) stackstore, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_stackstore_row_deleted, NULL);
29309 	mstruct->unref();
29310 	mstruct = CALCULATOR->getRPNRegister(1);
29311 	mstruct->ref();
29312 	setResult(NULL, true, false, false, "", 0, true);
29313 	updateRPNIndexes();
29314 }
on_popup_menu_item_stack_up_activate(GtkMenuItem *,gpointer)29315 void on_popup_menu_item_stack_up_activate(GtkMenuItem*, gpointer) {
29316 	on_button_registerup_clicked(NULL, NULL);
29317 }
on_popup_menu_item_stack_down_activate(GtkMenuItem *,gpointer)29318 void on_popup_menu_item_stack_down_activate(GtkMenuItem*, gpointer) {
29319 	on_button_registerdown_clicked(NULL, NULL);
29320 }
on_popup_menu_item_stack_swap_activate(GtkMenuItem *,gpointer)29321 void on_popup_menu_item_stack_swap_activate(GtkMenuItem*, gpointer) {
29322 	on_button_registerswap_clicked(NULL, NULL);
29323 }
on_popup_menu_item_stack_edit_activate(GtkMenuItem *,gpointer)29324 void on_popup_menu_item_stack_edit_activate(GtkMenuItem*, gpointer) {
29325 	on_button_editregister_clicked(NULL, NULL);
29326 }
on_popup_menu_item_stack_delete_activate(GtkMenuItem *,gpointer)29327 void on_popup_menu_item_stack_delete_activate(GtkMenuItem*, gpointer) {
29328 	on_button_deleteregister_clicked(NULL, NULL);
29329 }
on_popup_menu_item_stack_clear_activate(GtkMenuItem *,gpointer)29330 void on_popup_menu_item_stack_clear_activate(GtkMenuItem*, gpointer) {
29331 	on_button_clearstack_clicked(NULL, NULL);
29332 }
update_stackview_popup()29333 void update_stackview_popup() {
29334 	GtkTreeModel *model;
29335 	GtkTreeIter iter;
29336 	bool b_sel = gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(stackview)), &model, &iter);
29337 	gint index = -1;
29338 	if(b_sel) {
29339 		GtkTreePath *path = gtk_tree_model_get_path(model, &iter);
29340 		index = gtk_tree_path_get_indices(path)[0];
29341 		gtk_tree_path_free(path);
29342 	}
29343 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_stack_inserttext")), b_sel);
29344 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_stack_copytext")), b_sel);
29345 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_stack_copy")), b_sel);
29346 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_stack_movetotop")), b_sel && index != 0);
29347 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_stack_moveup")), b_sel);
29348 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_stack_movedown")), b_sel);
29349 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_stack_swap")), b_sel);
29350 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_stack_edit")), b_sel);
29351 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_stack_negate")), b_sel);
29352 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_stack_invert")), b_sel);
29353 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_stack_square")), b_sel);
29354 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_stack_sqrt")), b_sel);
29355 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(main_builder, "popup_menu_item_stack_delete")), b_sel);
29356 }
on_stackview_button_press_event(GtkWidget *,GdkEventButton * event,gpointer)29357 gboolean on_stackview_button_press_event(GtkWidget*, GdkEventButton *event, gpointer) {
29358 	GtkTreePath *path = NULL;
29359 	GtkTreeSelection *select = NULL;
29360 	if(gdk_event_triggers_context_menu((GdkEvent*) event) && event->type == GDK_BUTTON_PRESS) {
29361 		if(b_busy) return TRUE;
29362 		if(gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(stackview), event->x, event->y, &path, NULL, NULL, NULL)) {
29363 			select = gtk_tree_view_get_selection(GTK_TREE_VIEW(stackview));
29364 			if(!gtk_tree_selection_path_is_selected(select, path)) {
29365 				gtk_tree_selection_unselect_all(select);
29366 				gtk_tree_selection_select_path(select, path);
29367 			}
29368 			gtk_tree_path_free(path);
29369 		}
29370 		update_stackview_popup();
29371 #if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 22
29372 		gtk_menu_popup_at_pointer(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_stackview")), (GdkEvent*) event);
29373 #else
29374 		gtk_menu_popup(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_stackview")), NULL, NULL, NULL, NULL, event->button, event->time);
29375 #endif
29376 		return TRUE;
29377 	}
29378 	return FALSE;
29379 }
on_stackview_popup_menu(GtkWidget *,gpointer)29380 gboolean on_stackview_popup_menu(GtkWidget*, gpointer) {
29381 	if(b_busy) return TRUE;
29382 	update_stackview_popup();
29383 #if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 22
29384 	gtk_menu_popup_at_pointer(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_stackview")), NULL);
29385 #else
29386 	gtk_menu_popup(GTK_MENU(gtk_builder_get_object(main_builder, "popup_menu_stackview")), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time());
29387 #endif
29388 	return TRUE;
29389 }
29390 
on_unit_edit_entry_relation_changed(GtkEditable * w,gpointer)29391 void on_unit_edit_entry_relation_changed(GtkEditable *w, gpointer) {
29392 	string str = gtk_entry_get_text(GTK_ENTRY(w));
29393 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_box_reversed")), str.find("\\x") != string::npos);
29394 }
29395 
correct_name_entry(GtkEditable * editable,ExpressionItemType etype,gpointer function)29396 void correct_name_entry(GtkEditable *editable, ExpressionItemType etype, gpointer function) {
29397 	string str = gtk_entry_get_text(GTK_ENTRY(editable));
29398 	if(str.empty()) return;
29399 	remove_blank_ends(str);
29400 	bool b = false;
29401 	if(!str.empty()) {
29402 		switch(etype) {
29403 			case TYPE_FUNCTION: {
29404 				b = CALCULATOR->functionNameIsValid(str);
29405 				if(!b) str = CALCULATOR->convertToValidFunctionName(str);
29406 				break;
29407 			}
29408 			case TYPE_UNIT: {
29409 				b = CALCULATOR->unitNameIsValid(str);
29410 				if(!b) str = CALCULATOR->convertToValidUnitName(str);
29411 				break;
29412 			}
29413 			case TYPE_VARIABLE: {
29414 				b = CALCULATOR->variableNameIsValid(str);
29415 				if(!b) str = CALCULATOR->convertToValidVariableName(str);
29416 				break;
29417 			}
29418 		}
29419 	}
29420 	if(!b) {
29421 		g_signal_handlers_block_matched((gpointer) editable, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, function, NULL);
29422 		gtk_entry_set_text(GTK_ENTRY(editable), str.c_str());
29423 		g_signal_handlers_unblock_matched((gpointer) editable, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, function, NULL);
29424 	}
29425 }
29426 
29427 /*
29428 	check if entered unit name is valid, if not modify
29429 */
on_unit_edit_entry_name_changed(GtkEditable * editable,gpointer)29430 void on_unit_edit_entry_name_changed(GtkEditable *editable, gpointer) {
29431 	correct_name_entry(editable, TYPE_UNIT, (gpointer) on_unit_edit_entry_name_changed);
29432 }
29433 /*
29434 	selected unit type in edit/new unit dialog has changed
29435 */
on_unit_edit_combobox_class_changed(GtkComboBox * om,gpointer)29436 void on_unit_edit_combobox_class_changed(GtkComboBox *om, gpointer) {
29437 
29438 	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);
29439 	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);
29440 	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);
29441 	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);
29442 	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);
29443 	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);
29444 	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);
29445 	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);
29446 	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);
29447 	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);
29448 	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);
29449 	if(gtk_combo_box_get_active(om) != UNIT_CLASS_ALIAS_UNIT) {
29450 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_checkbutton_mix")), FALSE);
29451 		on_unit_edit_checkbutton_mix_toggled(GTK_TOGGLE_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_checkbutton_mix")), NULL);
29452 		gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_spinbutton_exp")), 1);
29453 	}
29454 }
29455 
on_unit_edit_checkbutton_mix_toggled(GtkToggleButton * w,gpointer)29456 void on_unit_edit_checkbutton_mix_toggled(GtkToggleButton *w, gpointer) {
29457 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_label_mix_priority")), gtk_toggle_button_get_active(w));
29458 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_label_mix_min")), gtk_toggle_button_get_active(w));
29459 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_spinbutton_mix_priority")), gtk_toggle_button_get_active(w));
29460 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_spinbutton_mix_min")), gtk_toggle_button_get_active(w));
29461 }
29462 
on_unit_edit_spinbutton_exp_value_changed(GtkSpinButton * w,gpointer)29463 void on_unit_edit_spinbutton_exp_value_changed(GtkSpinButton *w, gpointer) {
29464 	if(gtk_combo_box_get_active(GTK_COMBO_BOX(gtk_builder_get_object(unitedit_builder, "unit_edit_combobox_class"))) != UNIT_CLASS_ALIAS_UNIT) return;
29465 	if(gtk_spin_button_get_value_as_int(w) != 1) {
29466 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_checkbutton_mix")), FALSE);
29467 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_frame_mix")), FALSE);
29468 	} else {
29469 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_frame_mix")), TRUE);
29470 	}
29471 }
29472 
29473 /*
29474 	selected unit system in edit/new unit dialog has changed
29475 */
on_unit_edit_combo_system_changed(GtkComboBox * om,gpointer)29476 void on_unit_edit_combo_system_changed(GtkComboBox *om, gpointer) {
29477 	string str = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(om));
29478 	if(str == "SI" || str == "CGS") {
29479 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(unitedit_builder, "unit_edit_checkbutton_use_prefixes")), TRUE);
29480 	}
29481 }
29482 
29483 /*
29484 	"New" button clicked in unit manager -- open new unit dialog
29485 */
on_units_button_new_clicked(GtkButton *,gpointer)29486 void on_units_button_new_clicked(GtkButton*, gpointer) {
29487 	if(selected_unit_category.empty() || selected_unit_category[0] != '/') {
29488 		edit_unit("", NULL, GTK_WIDGET(gtk_builder_get_object(units_builder, "units_dialog")));
29489 	} else {
29490 		//fill in category field with selected category
29491 		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")));
29492 	}
29493 }
29494 
29495 /*
29496 	"Edit" button clicked in unit manager -- open edit unit dialog for selected unit
29497 */
on_units_button_edit_clicked(GtkButton *,gpointer)29498 void on_units_button_edit_clicked(GtkButton*, gpointer) {
29499 	Unit *u = get_selected_unit();
29500 	if(u) {
29501 		edit_unit("", u, GTK_WIDGET(gtk_builder_get_object(units_builder, "units_dialog")));
29502 	}
29503 }
29504 
29505 /*
29506 	"Insert" button clicked in unit manager -- insert selected unit in expression entry
29507 */
on_units_button_insert_clicked(GtkButton *,gpointer)29508 void on_units_button_insert_clicked(GtkButton*, gpointer) {
29509 	Unit *u = get_selected_unit();
29510 	if(u) {
29511 		if(u->subtype() == SUBTYPE_COMPOSITE_UNIT) {
29512 			string str = ((CompositeUnit*) u)->print(true, printops.abbreviate_names, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) expressiontext);
29513 			if(printops.multiplication_sign == MULTIPLICATION_SIGN_DOT) gsub(saltdot, sdot, str);
29514 			insert_text(str.c_str());
29515 		} else {
29516 			insert_text(u->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, true, false, &can_display_unicode_string_function, (void*) expressiontext).name.c_str());
29517 		}
29518 	}
29519 }
29520 
29521 /*
29522 	"Convert" button clicked in unit manager -- convert result to selected unit
29523 */
on_units_button_convert_to_clicked(GtkButton *,gpointer)29524 void on_units_button_convert_to_clicked(GtkButton*, gpointer) {
29525 	if(b_busy) return;
29526 	Unit *u = get_selected_unit();
29527 	if(u) {
29528 		executeCommand(COMMAND_CONVERT_UNIT, true, "", u);
29529 		focus_keeping_selection();
29530 	}
29531 }
29532 
29533 /*
29534 	deletion of unit requested
29535 */
on_units_button_delete_clicked(GtkButton *,gpointer)29536 void on_units_button_delete_clicked(GtkButton*, gpointer) {
29537 	GtkTreeModel *model;
29538 	GtkTreeIter iter;
29539 	Unit *u = get_selected_unit();
29540 	if(u && u->isLocal()) {
29541 		if(u->isUsedByOtherUnits()) {
29542 			//do not delete units that are used by other units
29543 			show_message(_("Cannot delete unit as it is needed by other units."), GTK_WIDGET(gtk_builder_get_object(units_builder, "units_dialog")));
29544 			return;
29545 		}
29546 		for(size_t i = 0; i < recent_units.size(); i++) {
29547 			if(recent_units[i] == u) {
29548 				recent_units.erase(recent_units.begin() + i);
29549 				gtk_widget_destroy(recent_unit_items[i]);
29550 				recent_unit_items.erase(recent_unit_items.begin() + i);
29551 				break;
29552 			}
29553 		}
29554 		//ensure that all references to the unit is removed in Calculator
29555 		u->destroy();
29556 		//update menus and trees
29557 		if(gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnits)), &model, &iter)) {
29558 			//reselect selected unit category
29559 			GtkTreePath *path = gtk_tree_model_get_path(model, &iter);
29560 			string str = selected_unit_category;
29561 			update_umenus();
29562 			if(str == selected_unit_category) gtk_tree_selection_select_path(gtk_tree_view_get_selection(GTK_TREE_VIEW(tUnits)), path);
29563 			gtk_tree_path_free(path);
29564 		} else {
29565 			update_umenus();
29566 		}
29567 	}
29568 }
29569 
29570 /*
29571 	"New" button clicked in variable manager -- open new variable dialog
29572 */
on_variables_button_new_clicked(GtkButton *,gpointer)29573 void on_variables_button_new_clicked(GtkButton*, gpointer) {
29574 	if(selected_variable_category.empty() || selected_variable_category[0] != '/') {
29575 		edit_variable("", NULL, NULL, GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_dialog")));
29576 	} else {
29577 		//fill in category field with selected category
29578 		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")));
29579 	}
29580 }
29581 
29582 /*
29583 	"Edit" button clicked in variable manager -- open edit dialog for selected variable
29584 */
on_variables_button_edit_clicked(GtkButton *,gpointer)29585 void on_variables_button_edit_clicked(GtkButton*, gpointer) {
29586 	Variable *v = get_selected_variable();
29587 	if(v) {
29588 		if(!CALCULATOR->stillHasVariable(v)) {
29589 			show_message(_("Variable does not exist anymore."), GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_dialog")));
29590 			update_vmenu();
29591 			return;
29592 		}
29593 		edit_variable("", v, NULL, GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_dialog")));
29594 	}
29595 }
29596 
29597 /*
29598 	"Insert" button clicked in variable manager -- insert variable name in expression entry
29599 */
on_variables_button_insert_clicked(GtkButton *,gpointer)29600 void on_variables_button_insert_clicked(GtkButton*, gpointer) {
29601 	Variable *v = get_selected_variable();
29602 	if(v) {
29603 		if(!CALCULATOR->stillHasVariable(v)) {
29604 			show_message(_("Variable does not exist anymore."), GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_dialog")));
29605 			update_vmenu();
29606 			return;
29607 		}
29608 		gchar *gstr = g_strdup(v->preferredInputName(printops.abbreviate_names, true, false, false, &can_display_unicode_string_function, (void*) expressiontext).name.c_str());
29609 		insert_text(gstr);
29610 		g_free(gstr);
29611 	}
29612 }
29613 
29614 /*
29615 	"Delete" button clicked in variable manager -- deletion of selected variable requested
29616 */
on_variables_button_delete_clicked(GtkButton *,gpointer)29617 void on_variables_button_delete_clicked(GtkButton*, gpointer) {
29618 	GtkTreeModel *model;
29619 	GtkTreeIter iter;
29620 	Variable *v = get_selected_variable();
29621 	if(v && !CALCULATOR->stillHasVariable(v)) {
29622 		show_message(_("Variable does not exist anymore."), GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_dialog")));
29623 		update_vmenu();
29624 		return;
29625 	}
29626 	if(v && v->isLocal()) {
29627 		for(size_t i = 0; i < recent_variables.size(); i++) {
29628 			if(recent_variables[i] == v) {
29629 				recent_variables.erase(recent_variables.begin() + i);
29630 				gtk_widget_destroy(recent_variable_items[i]);
29631 				recent_variable_items.erase(recent_variable_items.begin() + i);
29632 				break;
29633 			}
29634 		}
29635 		//ensure that all references are removed in Calculator
29636 		v->destroy();
29637 
29638 		//update menus and trees
29639 		if(gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(tVariables)), &model, &iter)) {
29640 			//reselect selected variable category
29641 			GtkTreePath *path = gtk_tree_model_get_path(model, &iter);
29642 			string str = selected_variable_category;
29643 			update_vmenu();
29644 			if(str == selected_variable_category) gtk_tree_selection_select_path(gtk_tree_view_get_selection(GTK_TREE_VIEW(tVariables)), path);
29645 			gtk_tree_path_free(path);
29646 		} else {
29647 			update_vmenu();
29648 		}
29649 	}
29650 }
29651 
on_variables_button_export_clicked(GtkButton *,gpointer)29652 void on_variables_button_export_clicked(GtkButton*, gpointer) {
29653 	Variable *v = get_selected_variable();
29654 	if(v && !CALCULATOR->stillHasVariable(v)) {
29655 		show_message(_("Variable does not exist anymore."), GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_dialog")));
29656 		update_vmenu();
29657 		return;
29658 	}
29659 	if(v && v->isKnown()) {
29660 		export_csv_file((KnownVariable*) v, GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_dialog")));
29661 	}
29662 }
29663 
29664 /*
29665 	"Close" button clicked in variable manager -- hide
29666 */
on_variables_button_close_clicked(GtkButton *,gpointer)29667 void on_variables_button_close_clicked(GtkButton*, gpointer) {
29668 	gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_dialog")));
29669 }
29670 
29671 /*
29672 	"New" button clicked in function manager -- open new function dialog
29673 */
on_functions_button_new_clicked(GtkButton *,gpointer)29674 void on_functions_button_new_clicked(GtkButton*, gpointer) {
29675 	if(selected_function_category.empty() || selected_function_category[0] != '/') {
29676 		edit_function("", NULL, GTK_WIDGET(gtk_builder_get_object(functions_builder, "functions_dialog")));
29677 	} else {
29678 		//fill in category field with selected category
29679 		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")));
29680 	}
29681 }
29682 
29683 /*
29684 	"Edit" button clicked in function manager -- open edit function dialog for selected function
29685 */
on_functions_button_edit_clicked(GtkButton *,gpointer)29686 void on_functions_button_edit_clicked(GtkButton*, gpointer) {
29687 	MathFunction *f = get_selected_function();
29688 	if(f) {
29689 		edit_function("", f, GTK_WIDGET(gtk_builder_get_object(functions_builder, "functions_dialog")));
29690 	}
29691 }
29692 
29693 /*
29694 	"Insert" button clicked in function manager -- open dialog for insertion of function in expression entry
29695 */
on_functions_button_insert_clicked(GtkButton *,gpointer)29696 void on_functions_button_insert_clicked(GtkButton*, gpointer) {
29697 	insert_function(get_selected_function(), GTK_WIDGET(gtk_builder_get_object(functions_builder, "functions_dialog")));
29698 }
29699 
29700 /*
29701 	"Apply" button clicked in function manager -- apply function to current result
29702 */
on_functions_button_apply_clicked(GtkButton *,gpointer)29703 void on_functions_button_apply_clicked(GtkButton*, gpointer) {
29704 	apply_function(get_selected_function(), GTK_WIDGET(gtk_builder_get_object(functions_builder, "functions_dialog")));
29705 }
29706 
29707 /*
29708 	"Delete" button clicked in function manager -- deletion of selected function requested
29709 */
on_functions_button_delete_clicked(GtkButton *,gpointer)29710 void on_functions_button_delete_clicked(GtkButton*, gpointer) {
29711 	GtkTreeModel *model;
29712 	GtkTreeIter iter;
29713 	MathFunction *f = get_selected_function();
29714 	if(f && f->isLocal()) {
29715 		for(size_t i = 0; i < recent_functions.size(); i++) {
29716 			if(recent_functions[i] == f) {
29717 				recent_functions.erase(recent_functions.begin() + i);
29718 				gtk_widget_destroy(recent_function_items[i]);
29719 				recent_function_items.erase(recent_function_items.begin() + i);
29720 				break;
29721 			}
29722 		}
29723 		//ensure removal of all references in Calculator
29724 		f->destroy();
29725 		//update menus and trees
29726 		if(gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(tFunctions)), &model, &iter)) {
29727 			//reselected selected function category
29728 			GtkTreePath *path = gtk_tree_model_get_path(model, &iter);
29729 			string str = selected_function_category;
29730 			update_fmenu();
29731 			if(str == selected_function_category) {
29732 				gtk_tree_selection_select_path(gtk_tree_view_get_selection(GTK_TREE_VIEW(tFunctions)), path);
29733 			}
29734 			gtk_tree_path_free(path);
29735 		} else {
29736 			update_fmenu();
29737 		}
29738 	}
29739 }
29740 
29741 /*
29742 	"Close" button clicked in function manager -- hide
29743 */
on_functions_button_close_clicked(GtkButton *,gpointer)29744 void on_functions_button_close_clicked(GtkButton*, gpointer) {
29745 	gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(functions_builder, "functions_dialog")));
29746 }
29747 
on_datasets_button_newset_clicked(GtkButton *,gpointer)29748 void on_datasets_button_newset_clicked(GtkButton*, gpointer) {
29749 	edit_dataset(NULL, GTK_WIDGET(gtk_builder_get_object(datasets_builder, "datasets_dialog")));
29750 }
on_datasets_button_editset_clicked(GtkButton *,gpointer)29751 void on_datasets_button_editset_clicked(GtkButton*, gpointer) {
29752 	edit_dataset(selected_dataset, GTK_WIDGET(gtk_builder_get_object(datasets_builder, "datasets_dialog")));
29753 }
on_datasets_button_delset_clicked(GtkButton *,gpointer)29754 void on_datasets_button_delset_clicked(GtkButton*, gpointer) {
29755 	if(selected_dataset && selected_dataset->isLocal()) {
29756 		for(size_t i = 0; i < recent_functions.size(); i++) {
29757 			if(recent_functions[i] == selected_dataset) {
29758 				recent_functions.erase(recent_functions.begin() + i);
29759 				gtk_widget_destroy(recent_function_items[i]);
29760 				recent_function_items.erase(recent_function_items.begin() + i);
29761 				break;
29762 			}
29763 		}
29764 		selected_dataset->destroy();
29765 		selected_dataobject = NULL;
29766 		update_datasets_tree();
29767 		on_tDatasets_selection_changed(gtk_tree_view_get_selection(GTK_TREE_VIEW(tDatasets)), NULL);
29768 	}
29769 }
on_datasets_button_newobject_clicked(GtkButton *,gpointer)29770 void on_datasets_button_newobject_clicked(GtkButton*, gpointer) {
29771 	edit_dataobject(selected_dataset, NULL, GTK_WIDGET(gtk_builder_get_object(datasets_builder, "datasets_dialog")));
29772 }
on_datasets_button_editobject_clicked(GtkButton *,gpointer)29773 void on_datasets_button_editobject_clicked(GtkButton*, gpointer) {
29774 	edit_dataobject(selected_dataset, selected_dataobject, GTK_WIDGET(gtk_builder_get_object(datasets_builder, "datasets_dialog")));
29775 }
on_datasets_button_delobject_clicked(GtkButton *,gpointer)29776 void on_datasets_button_delobject_clicked(GtkButton*, gpointer) {
29777 	if(selected_dataset && selected_dataobject) {
29778 		selected_dataset->delObject(selected_dataobject);
29779 		selected_dataobject = NULL;
29780 		update_dataobjects();
29781 	}
29782 }
on_datasets_button_close_clicked(GtkButton *,gpointer)29783 void on_datasets_button_close_clicked(GtkButton*, gpointer) {
29784 	gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(datasets_builder, "datasets_dialog")));
29785 }
29786 
29787 
29788 /*
29789 	check if entered function name is valid, if not modify
29790 */
on_function_edit_entry_name_changed(GtkEditable * editable,gpointer)29791 void on_function_edit_entry_name_changed(GtkEditable *editable, gpointer) {
29792 	correct_name_entry(editable, TYPE_FUNCTION, (gpointer) on_function_edit_entry_name_changed);
29793 }
29794 /*
29795 	check if entered variable name is valid, if not modify
29796 */
on_variable_edit_entry_name_changed(GtkEditable * editable,gpointer)29797 void on_variable_edit_entry_name_changed(GtkEditable *editable, gpointer) {
29798 	correct_name_entry(editable, TYPE_VARIABLE, (gpointer) on_variable_edit_entry_name_changed);
29799 }
29800 
on_variable_changed()29801 void on_variable_changed() {
29802 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(variableedit_builder, "variable_edit_button_ok")), TRUE);
29803 }
on_function_changed()29804 void on_function_changed() {
29805 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_button_ok")), TRUE);
29806 }
on_simple_function_changed()29807 void on_simple_function_changed() {
29808 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(simplefunctionedit_builder, "simple_function_edit_button_ok")), TRUE);
29809 }
on_argument_changed()29810 void on_argument_changed() {
29811 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(argumentrules_builder, "argument_rules_button_ok")), TRUE);
29812 }
on_unit_changed()29813 void on_unit_changed() {
29814 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unitedit_builder, "unit_edit_button_ok")), TRUE);
29815 }
on_dataset_changed()29816 void on_dataset_changed() {
29817 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasetedit_builder, "dataset_edit_button_ok")), TRUE);
29818 }
on_dataobject_changed()29819 void on_dataobject_changed() {
29820 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasets_builder, "dataobject_edit_button_ok")), TRUE);
29821 }
on_dataproperty_changed()29822 void on_dataproperty_changed() {
29823 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(datasetedit_builder, "dataproperty_edit_button_ok")), TRUE);
29824 }
on_matrix_changed()29825 void on_matrix_changed() {
29826 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(matrixedit_builder, "matrix_edit_button_ok")), TRUE);
29827 }
on_unknown_changed()29828 void on_unknown_changed() {
29829 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unknownedit_builder, "unknown_edit_button_ok")), TRUE);
29830 }
29831 
on_tMatrixEdit_edited(GtkCellRendererText * cell,gchar * path_string,gchar * new_text,gpointer model)29832 void on_tMatrixEdit_edited(GtkCellRendererText *cell, gchar *path_string, gchar *new_text, gpointer model) {
29833 	GtkTreeIter iter;
29834 	gint i_column = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cell), "column"));
29835 	gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL(model), &iter, path_string);
29836 	gtk_list_store_set(GTK_LIST_STORE (model), &iter, i_column, new_text, -1);
29837 	on_matrix_changed();
29838 }
on_tMatrixEdit_editable_key_press_event(GtkWidget * w,GdkEventKey * event,gpointer renderer)29839 gboolean on_tMatrixEdit_editable_key_press_event(GtkWidget *w, GdkEventKey *event, gpointer renderer) {
29840 	switch(event->keyval) {
29841 		case GDK_KEY_Up: {}
29842 		case GDK_KEY_Down: {}
29843 		case GDK_KEY_Tab: {}
29844 		case GDK_KEY_ISO_Enter: {}
29845 		case GDK_KEY_KP_Enter: {}
29846 		case GDK_KEY_Return: {
29847 			gtk_cell_editable_editing_done(GTK_CELL_EDITABLE(w));
29848 			GtkTreeViewColumn *column = NULL;
29849 			GtkTreePath *path = NULL;
29850 			gtk_tree_view_get_cursor(GTK_TREE_VIEW(tMatrixEdit), &path, &column);
29851 			if(path) {
29852 				if(column) {
29853 					for(size_t i = 0; i < matrix_edit_columns.size(); i++) {
29854 						if(matrix_edit_columns[i] == column) {
29855 							if(event->keyval == GDK_KEY_Tab) {
29856 								i++;
29857 								if(i >= matrix_edit_columns.size()) {
29858 									gtk_tree_path_next(path);
29859 									GtkTreeIter iter;
29860 									if(!gtk_tree_model_get_iter(GTK_TREE_MODEL(tMatrixEdit_store), &iter, path)) {
29861 										gtk_tree_path_free(path);
29862 										path = gtk_tree_path_new_first();
29863 									}
29864 									i = 0;
29865 								}
29866 							} else {
29867 								if(event->keyval == GDK_KEY_Up) {
29868 									if(!gtk_tree_path_prev(path)) {
29869 										gtk_tree_path_free(path);
29870 										path = gtk_tree_path_new_from_indices(gtk_tree_model_iter_n_children(GTK_TREE_MODEL(tMatrixEdit_store), NULL) - 1, -1);
29871 									}
29872 								} else {
29873 									gtk_tree_path_next(path);
29874 									GtkTreeIter iter;
29875 									if(!gtk_tree_model_get_iter(GTK_TREE_MODEL(tMatrixEdit_store), &iter, path)) {
29876 										gtk_tree_path_free(path);
29877 										if(event->keyval != GDK_KEY_Up) return TRUE;
29878 										path = gtk_tree_path_new_first();
29879 									}
29880 								}
29881 							}
29882 							gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(tMatrixEdit), path, matrix_edit_columns[i], FALSE, 0.0, 0.0);
29883 							while(gtk_events_pending()) gtk_main_iteration();
29884 							gtk_tree_view_set_cursor(GTK_TREE_VIEW(tMatrixEdit), path, matrix_edit_columns[i], TRUE);
29885 							on_tMatrixEdit_cursor_changed(GTK_TREE_VIEW(tMatrixEdit), NULL);
29886 							break;
29887 						}
29888 					}
29889 				}
29890 				gtk_tree_path_free(path);
29891 			}
29892 			return TRUE;
29893 		}
29894 	}
29895 	return FALSE;
29896 }
on_tMatrixEdit_editing_started(GtkCellRenderer * renderer,GtkCellEditable * editable,gchar * path,gpointer user_data)29897 void on_tMatrixEdit_editing_started(GtkCellRenderer *renderer, GtkCellEditable *editable, gchar *path, gpointer user_data) {
29898 	g_signal_connect(G_OBJECT(editable), "key-press-event", G_CALLBACK(on_tMatrixEdit_editable_key_press_event), renderer);
29899 }
on_tMatrixEdit_key_press_event(GtkWidget *,GdkEventKey * event,gpointer)29900 gboolean on_tMatrixEdit_key_press_event(GtkWidget*, GdkEventKey *event, gpointer) {
29901 	switch(event->keyval) {
29902 		case GDK_KEY_Return: {break;}
29903 		case GDK_KEY_Tab: {
29904 			GtkTreeViewColumn *column = NULL;
29905 			GtkTreePath *path = NULL;
29906 			gtk_tree_view_get_cursor(GTK_TREE_VIEW(tMatrixEdit), &path, &column);
29907 			if(path) {
29908 				if(column) {
29909 					for(size_t i = 0; i < matrix_edit_columns.size(); i++) {
29910 						if(matrix_edit_columns[i] == column) {
29911 							i++;
29912 							if(i < matrix_edit_columns.size()) {
29913 								gtk_tree_view_set_cursor(GTK_TREE_VIEW(tMatrixEdit), path, matrix_edit_columns[i], FALSE);
29914 								while(gtk_events_pending()) gtk_main_iteration();
29915 								gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(tMatrixEdit), path, matrix_edit_columns[i], FALSE, 0.0, 0.0);
29916 							} else {
29917 								gtk_tree_path_next(path);
29918 								GtkTreeIter iter;
29919 								if(!gtk_tree_model_get_iter(GTK_TREE_MODEL(tMatrixEdit_store), &iter, path)) {
29920 									gtk_tree_path_free(path);
29921 									path = gtk_tree_path_new_first();
29922 								}
29923 								gtk_tree_view_set_cursor(GTK_TREE_VIEW(tMatrixEdit), path, matrix_edit_columns[0], FALSE);
29924 								while(gtk_events_pending()) gtk_main_iteration();
29925 								gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(tMatrixEdit), path, matrix_edit_columns[0], FALSE, 0.0, 0.0);
29926 							}
29927 							gtk_tree_path_free(path);
29928 							on_tMatrixEdit_cursor_changed(GTK_TREE_VIEW(tMatrixEdit), NULL);
29929 							return TRUE;
29930 						}
29931 					}
29932 				}
29933 				gtk_tree_path_free(path);
29934 			}
29935 			break;
29936 		}
29937 		default: {
29938 			if(event->length == 0) return FALSE;
29939 			GtkTreeViewColumn *column = NULL;
29940 			GtkTreePath *path = NULL;
29941 			gtk_tree_view_get_cursor(GTK_TREE_VIEW(tMatrixEdit), &path, &column);
29942 			if(path) {
29943 				if(column) {
29944 					gtk_tree_view_set_cursor(GTK_TREE_VIEW(tMatrixEdit), path, column, TRUE);
29945 					while(gtk_events_pending()) gtk_main_iteration();
29946 					gboolean return_val = FALSE;
29947 					g_signal_emit_by_name((gpointer) gtk_builder_get_object(matrixedit_builder, "matrix_edit_dialog"), "key_press_event", event, &return_val);
29948 					gtk_tree_path_free(path);
29949 					return TRUE;
29950 				}
29951 				gtk_tree_path_free(path);
29952 			}
29953 		}
29954 	}
29955 	return FALSE;
29956 }
on_tMatrixEdit_button_press_event(GtkWidget *,GdkEventButton * event,gpointer)29957 gboolean on_tMatrixEdit_button_press_event(GtkWidget*, GdkEventButton *event, gpointer) {
29958 	if(event->button != 1) return FALSE;
29959 	GtkTreeViewColumn *column = NULL;
29960 	GtkTreePath *path = NULL;
29961 	if(gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(tMatrixEdit), (gint) event->x, (gint) event->y, &path, &column, NULL, NULL) && path && column) {
29962 		gtk_tree_view_set_cursor(GTK_TREE_VIEW(tMatrixEdit), path, column, TRUE);
29963 		gtk_tree_path_free(path);
29964 		return TRUE;
29965 	}
29966 	if(path) gtk_tree_path_free(path);
29967 	return FALSE;
29968 }
29969 GtkTreeIter matrix_edit_prev_iter;
29970 gint matrix_edit_prev_column;
29971 bool block_matrix_edit_update_cursor = false;
on_tMatrixEdit_cursor_changed(GtkTreeView *,gpointer)29972 gboolean on_tMatrixEdit_cursor_changed(GtkTreeView*, gpointer) {
29973 	if(block_matrix_edit_update_cursor) return FALSE;
29974 	GtkTreeViewColumn *column = NULL;
29975 	GtkTreePath *path = NULL;
29976 	GtkTreeIter iter;
29977 	gtk_tree_view_get_cursor(GTK_TREE_VIEW(tMatrixEdit), &path, &column);
29978 	bool b = false;
29979 	if(path) {
29980 		if(column) {
29981 			if(gtk_tree_model_get_iter(GTK_TREE_MODEL(tMatrixEdit_store), &iter, path)) {
29982 				gint i_column = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column"));
29983 				matrix_edit_prev_iter = iter;
29984 				matrix_edit_prev_column = i_column;
29985 				gchar *pos_str;
29986 				if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(matrixedit_builder, "matrix_edit_radiobutton_matrix")))) {
29987 					pos_str = g_strdup_printf("(%i, %i)", i_column + 1, gtk_tree_path_get_indices(path)[0] + 1);
29988 				} else {
29989 					pos_str = g_strdup_printf("%i", (int) (i_column + 1 + matrix_edit_columns.size() * gtk_tree_path_get_indices(path)[0]));
29990 				}
29991 				gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(matrixedit_builder, "matrix_edit_label_position")), pos_str);
29992 				g_free(pos_str);
29993 				b = true;
29994 			}
29995 		}
29996 		gtk_tree_path_free(path);
29997 	}
29998 	if(!b) gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(matrixedit_builder, "matrix_edit_label_position")), _("none"));
29999 	return FALSE;
30000 }
30001 
on_matrix_edit_spinbutton_columns_value_changed(GtkSpinButton * w,gpointer)30002 void on_matrix_edit_spinbutton_columns_value_changed(GtkSpinButton *w, gpointer) {
30003 	gint c = matrix_edit_columns.size();
30004 	gint new_c = gtk_spin_button_get_value_as_int(w);
30005 	if(new_c < c) {
30006 		for(gint index_c = new_c; index_c < c; index_c++) {
30007 			gtk_tree_view_remove_column(GTK_TREE_VIEW(tMatrixEdit), matrix_edit_columns[index_c]);
30008 		}
30009 		matrix_edit_columns.resize(new_c);
30010 	} else {
30011 		GtkTreeIter iter;
30012 		for(gint index_c = c; index_c < new_c; index_c++) {
30013 			GtkCellRenderer *matrix_edit_renderer = gtk_cell_renderer_text_new();
30014 			g_object_set(G_OBJECT(matrix_edit_renderer), "editable", TRUE, NULL);
30015 			g_object_set(G_OBJECT(matrix_edit_renderer), "xalign", 1.0, NULL);
30016 			g_object_set_data(G_OBJECT(matrix_edit_renderer), "column", GINT_TO_POINTER(index_c));
30017 			g_signal_connect(G_OBJECT(matrix_edit_renderer), "edited", G_CALLBACK(on_tMatrixEdit_edited), GTK_TREE_MODEL(tMatrixEdit_store));
30018 			g_signal_connect(G_OBJECT(matrix_edit_renderer), "editing-started", G_CALLBACK(on_tMatrixEdit_editing_started), GTK_TREE_MODEL(tMatrixEdit_store));
30019 			GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes(i2s(index_c).c_str(), matrix_edit_renderer, "text", index_c, NULL);
30020 			g_object_set_data(G_OBJECT(column), "column", GINT_TO_POINTER(index_c));
30021 			g_object_set_data(G_OBJECT(column), "renderer", (gpointer) matrix_edit_renderer);
30022 			gtk_tree_view_column_set_min_width(column, 50);
30023 			gtk_tree_view_column_set_alignment(column, 0.5);
30024 			gtk_tree_view_append_column(GTK_TREE_VIEW(tMatrixEdit), column);
30025 			gtk_tree_view_column_set_expand(column, TRUE);
30026 			matrix_edit_columns.push_back(column);
30027 		}
30028 		if(!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tMatrixEdit_store), &iter)) return;
30029 		bool b_matrix = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(matrixedit_builder, "matrix_edit_radiobutton_matrix")));
30030 		while(true) {
30031 			for(gint index_c = c; index_c < new_c; index_c++) {
30032 				if(b_matrix) gtk_list_store_set(GTK_LIST_STORE(tMatrixEdit_store), &iter, index_c, "0", -1);
30033 				else gtk_list_store_set(GTK_LIST_STORE(tMatrixEdit_store), &iter, index_c, "", -1);
30034 			}
30035 			if(!gtk_tree_model_iter_next(GTK_TREE_MODEL(tMatrixEdit_store), &iter)) break;
30036 		}
30037 	}
30038 }
on_matrix_edit_spinbutton_rows_value_changed(GtkSpinButton * w,gpointer)30039 void on_matrix_edit_spinbutton_rows_value_changed(GtkSpinButton *w, gpointer) {
30040 	gint new_r = gtk_spin_button_get_value_as_int(w);
30041 	gint r = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(tMatrixEdit_store), NULL);
30042 	gint c = matrix_edit_columns.size();
30043 	bool b_matrix = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(matrixedit_builder, "matrix_edit_radiobutton_matrix")));
30044 	GtkTreeIter iter;
30045 	if(r < new_r) {
30046 		while(r < new_r) {
30047 			gtk_list_store_append(GTK_LIST_STORE(tMatrixEdit_store), &iter);
30048 			for(gint i = 0; i < c; i++) {
30049 				if(b_matrix) gtk_list_store_set(GTK_LIST_STORE(tMatrixEdit_store), &iter, i, "0", -1);
30050 				else gtk_list_store_set(GTK_LIST_STORE(tMatrixEdit_store), &iter, i, "", -1);
30051 			}
30052 			r++;
30053 		}
30054 	} else if(new_r < r) {
30055 		gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(tMatrixEdit_store), &iter, NULL, new_r);
30056 		while(gtk_list_store_iter_is_valid(GTK_LIST_STORE(tMatrixEdit_store), &iter)) {
30057 			gtk_list_store_remove(GTK_LIST_STORE(tMatrixEdit_store), &iter);
30058 		}
30059 	}
30060 }
30061 
on_tMatrix_edited(GtkCellRendererText * cell,gchar * path_string,gchar * new_text,gpointer model)30062 void on_tMatrix_edited(GtkCellRendererText *cell, gchar *path_string, gchar *new_text, gpointer model) {
30063 	GtkTreeIter iter;
30064 	gint i_column = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cell), "column"));
30065 	gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(model), &iter, path_string);
30066 	gtk_list_store_set(GTK_LIST_STORE(model), &iter, i_column, new_text, -1);
30067 }
on_tMatrix_editable_key_press_event(GtkWidget * w,GdkEventKey * event,gpointer renderer)30068 gboolean on_tMatrix_editable_key_press_event(GtkWidget *w, GdkEventKey *event, gpointer renderer) {
30069 	switch(event->keyval) {
30070 		case GDK_KEY_Up: {}
30071 		case GDK_KEY_Down: {}
30072 		case GDK_KEY_Tab: {}
30073 		case GDK_KEY_ISO_Enter: {}
30074 		case GDK_KEY_KP_Enter: {}
30075 		case GDK_KEY_Return: {
30076 			gtk_cell_editable_editing_done(GTK_CELL_EDITABLE(w));
30077 			GtkTreeViewColumn *column = NULL;
30078 			GtkTreePath *path = NULL;
30079 			gtk_tree_view_get_cursor(GTK_TREE_VIEW(tMatrix), &path, &column);
30080 			if(path) {
30081 				if(column) {
30082 					for(size_t i = 0; i < matrix_columns.size(); i++) {
30083 						if(matrix_columns[i] == column) {
30084 							if(event->keyval == GDK_KEY_Tab) {
30085 								i++;
30086 								if(i >= matrix_columns.size()) {
30087 									gtk_tree_path_next(path);
30088 									GtkTreeIter iter;
30089 									if(!gtk_tree_model_get_iter(GTK_TREE_MODEL(tMatrix_store), &iter, path)) {
30090 										gtk_tree_path_free(path);
30091 										path = gtk_tree_path_new_first();
30092 									}
30093 									i = 0;
30094 								}
30095 							} else {
30096 								if(event->keyval == GDK_KEY_Up) {
30097 									if(!gtk_tree_path_prev(path)) {
30098 										gtk_tree_path_free(path);
30099 										path = gtk_tree_path_new_from_indices(gtk_tree_model_iter_n_children(GTK_TREE_MODEL(tMatrix_store), NULL) - 1, -1);
30100 									}
30101 								} else {
30102 									gtk_tree_path_next(path);
30103 									GtkTreeIter iter;
30104 									if(!gtk_tree_model_get_iter(GTK_TREE_MODEL(tMatrix_store), &iter, path)) {
30105 										gtk_tree_path_free(path);
30106 										if(event->keyval != GDK_KEY_Up) return TRUE;
30107 										path = gtk_tree_path_new_first();
30108 									}
30109 								}
30110 							}
30111 							gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(tMatrix), path, matrix_columns[i], FALSE, 0.0, 0.0);
30112 							while(gtk_events_pending()) gtk_main_iteration();
30113 							gtk_tree_view_set_cursor(GTK_TREE_VIEW(tMatrix), path, matrix_columns[i], TRUE);
30114 							on_tMatrix_cursor_changed(GTK_TREE_VIEW(tMatrix), NULL);
30115 							break;
30116 						}
30117 					}
30118 				}
30119 				gtk_tree_path_free(path);
30120 			}
30121 			return TRUE;
30122 		}
30123 	}
30124 	return FALSE;
30125 }
on_tMatrix_editing_started(GtkCellRenderer * renderer,GtkCellEditable * editable,gchar * path,gpointer user_data)30126 void on_tMatrix_editing_started(GtkCellRenderer *renderer, GtkCellEditable *editable, gchar *path, gpointer user_data) {
30127 	g_signal_connect(G_OBJECT(editable), "key-press-event", G_CALLBACK(on_tMatrix_editable_key_press_event), renderer);
30128 }
on_tMatrix_key_press_event(GtkWidget *,GdkEventKey * event,gpointer)30129 gboolean on_tMatrix_key_press_event(GtkWidget*, GdkEventKey *event, gpointer) {
30130 	switch(event->keyval) {
30131 		case GDK_KEY_Return: {break;}
30132 		case GDK_KEY_Tab: {
30133 			GtkTreeViewColumn *column = NULL;
30134 			GtkTreePath *path = NULL;
30135 			gtk_tree_view_get_cursor(GTK_TREE_VIEW(tMatrix), &path, &column);
30136 			if(path) {
30137 				if(column) {
30138 					for(size_t i = 0; i < matrix_columns.size(); i++) {
30139 						if(matrix_columns[i] == column) {
30140 							i++;
30141 							if(i < matrix_columns.size()) {
30142 								gtk_tree_view_set_cursor(GTK_TREE_VIEW(tMatrix), path, matrix_columns[i], FALSE);
30143 								while(gtk_events_pending()) gtk_main_iteration();
30144 								gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(tMatrix), path, matrix_columns[i], FALSE, 0.0, 0.0);
30145 							} else {
30146 								gtk_tree_path_next(path);
30147 								GtkTreeIter iter;
30148 								if(!gtk_tree_model_get_iter(GTK_TREE_MODEL(tMatrix_store), &iter, path)) {
30149 									gtk_tree_path_free(path);
30150 									path = gtk_tree_path_new_first();
30151 								}
30152 								gtk_tree_view_set_cursor(GTK_TREE_VIEW(tMatrix), path, matrix_columns[0], FALSE);
30153 								while(gtk_events_pending()) gtk_main_iteration();
30154 								gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(tMatrix), path, matrix_columns[0], FALSE, 0.0, 0.0);
30155 							}
30156 							gtk_tree_path_free(path);
30157 							on_tMatrix_cursor_changed(GTK_TREE_VIEW(tMatrix), NULL);
30158 							return TRUE;
30159 						}
30160 					}
30161 				}
30162 				gtk_tree_path_free(path);
30163 			}
30164 			break;
30165 		}
30166 		default: {
30167 			if(event->length == 0) return FALSE;
30168 			GtkTreeViewColumn *column = NULL;
30169 			GtkTreePath *path = NULL;
30170 			gtk_tree_view_get_cursor(GTK_TREE_VIEW(tMatrix), &path, &column);
30171 			if(path) {
30172 				if(column) {
30173 					gtk_tree_view_set_cursor(GTK_TREE_VIEW(tMatrix), path, column, TRUE);
30174 					while(gtk_events_pending()) gtk_main_iteration();
30175 					gboolean return_val = FALSE;
30176 					g_signal_emit_by_name((gpointer) gtk_builder_get_object(matrix_builder, "matrix_dialog"), "key_press_event", event, &return_val);
30177 					gtk_tree_path_free(path);
30178 					return TRUE;
30179 				}
30180 				gtk_tree_path_free(path);
30181 			}
30182 		}
30183 	}
30184 	return FALSE;
30185 }
on_tMatrix_button_press_event(GtkWidget *,GdkEventButton * event,gpointer)30186 gboolean on_tMatrix_button_press_event(GtkWidget*, GdkEventButton *event, gpointer) {
30187 	if(event->button != 1) return FALSE;
30188 	GtkTreeViewColumn *column = NULL;
30189 	GtkTreePath *path = NULL;
30190 	if(gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(tMatrix), (gint) event->x, (gint) event->y, &path, &column, NULL, NULL) && path && column) {
30191 		gtk_tree_view_set_cursor(GTK_TREE_VIEW(tMatrix), path, column, TRUE);
30192 		gtk_tree_path_free(path);
30193 		return TRUE;
30194 	}
30195 	if(path) gtk_tree_path_free(path);
30196 	return FALSE;
30197 }
30198 GtkTreeIter matrix_prev_iter;
30199 gint matrix_prev_column;
30200 bool block_matrix_update_cursor = false;
on_tMatrix_cursor_changed(GtkTreeView *,gpointer)30201 gboolean on_tMatrix_cursor_changed(GtkTreeView*, gpointer) {
30202 	if(block_matrix_update_cursor) return FALSE;
30203 	GtkTreeViewColumn *column = NULL;
30204 	GtkTreePath *path = NULL;
30205 	GtkTreeIter iter;
30206 	gtk_tree_view_get_cursor(GTK_TREE_VIEW(tMatrix), &path, &column);
30207 	bool b = false;
30208 	if(path) {
30209 		if(column) {
30210 			if(gtk_tree_model_get_iter(GTK_TREE_MODEL(tMatrix_store), &iter, path)) {
30211 				gint i_column = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column"));
30212 				matrix_prev_iter = iter;
30213 				matrix_prev_column = i_column;
30214 				gchar *pos_str;
30215 				if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(matrix_builder, "matrix_radiobutton_matrix")))) {
30216 					pos_str = g_strdup_printf("(%i, %i)", i_column + 1, gtk_tree_path_get_indices(path)[0] + 1);
30217 				} else {
30218 					pos_str = g_strdup_printf("%i", (int) (i_column + 1 + matrix_columns.size() * gtk_tree_path_get_indices(path)[0]));
30219 				}
30220 				gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(matrix_builder, "matrix_label_position")), pos_str);
30221 				g_free(pos_str);
30222 				b = true;
30223 			}
30224 		}
30225 		gtk_tree_path_free(path);
30226 	}
30227 	if(!b) gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(matrix_builder, "matrix_label_position")), _("none"));
30228 	return FALSE;
30229 }
30230 
on_matrix_spinbutton_columns_value_changed(GtkSpinButton * w,gpointer)30231 void on_matrix_spinbutton_columns_value_changed(GtkSpinButton *w, gpointer) {
30232 	gint c = matrix_columns.size();
30233 	gint new_c = gtk_spin_button_get_value_as_int(w);
30234 	if(new_c < c) {
30235 		for(gint index_c = new_c; index_c < c; index_c++) {
30236 			gtk_tree_view_remove_column(GTK_TREE_VIEW(tMatrix), matrix_columns[index_c]);
30237 		}
30238 		matrix_columns.resize(new_c);
30239 	} else {
30240 		GtkTreeIter iter;
30241 		for(gint index_c = c; index_c < new_c; index_c++) {
30242 			GtkCellRenderer *matrix_renderer = gtk_cell_renderer_text_new();
30243 			g_object_set(G_OBJECT(matrix_renderer), "editable", TRUE, NULL);
30244 			g_object_set(G_OBJECT(matrix_renderer), "xalign", 1.0, NULL);
30245 			g_object_set_data(G_OBJECT(matrix_renderer), "column", GINT_TO_POINTER(index_c));
30246 			g_signal_connect(G_OBJECT(matrix_renderer), "edited", G_CALLBACK(on_tMatrix_edited), GTK_TREE_MODEL(tMatrix_store));
30247 			g_signal_connect(G_OBJECT(matrix_renderer), "editing-started", G_CALLBACK(on_tMatrix_editing_started), GTK_TREE_MODEL(tMatrix_store));
30248 			GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes(i2s(index_c).c_str(), matrix_renderer, "text", index_c, NULL);
30249 			g_object_set_data (G_OBJECT(column), "column", GINT_TO_POINTER(index_c));
30250 			gtk_tree_view_column_set_min_width(column, 50);
30251 			gtk_tree_view_column_set_alignment(column, 0.5);
30252 			gtk_tree_view_append_column(GTK_TREE_VIEW(tMatrix), column);
30253 			gtk_tree_view_column_set_expand(column, TRUE);
30254 			matrix_columns.push_back(column);
30255 		}
30256 		if(!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tMatrix_store), &iter)) return;
30257 		bool b_matrix = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(matrix_builder, "matrix_radiobutton_matrix")));
30258 		while(true) {
30259 			for(gint index_c = c; index_c < new_c; index_c++) {
30260 				if(b_matrix) gtk_list_store_set(GTK_LIST_STORE(tMatrix_store), &iter, index_c, "0", -1);
30261 				else gtk_list_store_set(GTK_LIST_STORE(tMatrix_store), &iter, index_c, "", -1);
30262 			}
30263 			if(!gtk_tree_model_iter_next(GTK_TREE_MODEL(tMatrix_store), &iter)) break;
30264 		}
30265 	}
30266 }
on_matrix_spinbutton_rows_value_changed(GtkSpinButton * w,gpointer)30267 void on_matrix_spinbutton_rows_value_changed(GtkSpinButton *w, gpointer) {
30268 	gint new_r = gtk_spin_button_get_value_as_int(w);
30269 	gint r = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(tMatrix_store), NULL);
30270 	gint c = matrix_columns.size();
30271 	bool b_matrix = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(matrix_builder, "matrix_radiobutton_matrix")));
30272 	GtkTreeIter iter;
30273 	if(r < new_r) {
30274 		while(r < new_r) {
30275 			gtk_list_store_append(GTK_LIST_STORE(tMatrix_store), &iter);
30276 			for(gint i = 0; i < c; i++) {
30277 				if(b_matrix) gtk_list_store_set(GTK_LIST_STORE(tMatrix_store), &iter, i, "0", -1);
30278 				else gtk_list_store_set(GTK_LIST_STORE(tMatrix_store), &iter, i, "", -1);
30279 			}
30280 			r++;
30281 		}
30282 	} else if(new_r < r) {
30283 		gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(tMatrix_store), &iter, NULL, new_r);
30284 		while(gtk_list_store_iter_is_valid(GTK_LIST_STORE(tMatrix_store), &iter)) {
30285 			gtk_list_store_remove(GTK_LIST_STORE(tMatrix_store), &iter);
30286 		}
30287 	}
30288 }
30289 
30290 bool updating_percentage_entries = false;
30291 void update_percentage_entries();
30292 vector<int> percentage_entries_changes;
on_percentage_button_calculate_clicked(GtkWidget *,gpointer)30293 void on_percentage_button_calculate_clicked(GtkWidget*, gpointer) {
30294 	update_percentage_entries();
30295 }
on_percentage_button_clear_clicked(GtkWidget *,gpointer)30296 void on_percentage_button_clear_clicked(GtkWidget*, gpointer) {
30297 	percentage_entries_changes.clear();
30298 	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(percentage_builder, "percentage_entry_1")), "");
30299 	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(percentage_builder, "percentage_entry_2")), "");
30300 	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(percentage_builder, "percentage_entry_3")), "");
30301 	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(percentage_builder, "percentage_entry_4")), "");
30302 	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(percentage_builder, "percentage_entry_5")), "");
30303 	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(percentage_builder, "percentage_entry_6")), "");
30304 	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(percentage_builder, "percentage_entry_7")), "");
30305 }
percentage_entry_changed(int entry_id,GtkEntry * w)30306 void percentage_entry_changed(int entry_id, GtkEntry *w) {
30307 	for(size_t i = 0; i < percentage_entries_changes.size(); i++) {
30308 		if(percentage_entries_changes[i] == entry_id) {
30309 			percentage_entries_changes.erase(percentage_entries_changes.begin() + i);
30310 			break;
30311 		}
30312 	}
30313 	if(gtk_entry_get_text_length(w) == 0) return;
30314 	percentage_entries_changes.push_back(entry_id);
30315 }
on_percentage_entry_1_changed(GtkEditable * w,gpointer)30316 void on_percentage_entry_1_changed(GtkEditable *w, gpointer) {percentage_entry_changed(1, GTK_ENTRY(w));}
on_percentage_entry_2_changed(GtkEditable * w,gpointer)30317 void on_percentage_entry_2_changed(GtkEditable *w, gpointer) {percentage_entry_changed(2, GTK_ENTRY(w));}
on_percentage_entry_3_changed(GtkEditable * w,gpointer)30318 void on_percentage_entry_3_changed(GtkEditable *w, gpointer) {percentage_entry_changed(4, GTK_ENTRY(w));}
on_percentage_entry_4_changed(GtkEditable * w,gpointer)30319 void on_percentage_entry_4_changed(GtkEditable *w, gpointer) {percentage_entry_changed(8, GTK_ENTRY(w));}
on_percentage_entry_5_changed(GtkEditable * w,gpointer)30320 void on_percentage_entry_5_changed(GtkEditable *w, gpointer) {percentage_entry_changed(16, GTK_ENTRY(w));}
on_percentage_entry_6_changed(GtkEditable * w,gpointer)30321 void on_percentage_entry_6_changed(GtkEditable *w, gpointer) {percentage_entry_changed(32, GTK_ENTRY(w));}
on_percentage_entry_7_changed(GtkEditable * w,gpointer)30322 void on_percentage_entry_7_changed(GtkEditable *w, gpointer) {percentage_entry_changed(64, GTK_ENTRY(w));}
on_percentage_entry_1_activate(GtkEditable * w,gpointer)30323 void on_percentage_entry_1_activate(GtkEditable *w, gpointer) {percentage_entry_changed(1, GTK_ENTRY(w)); update_percentage_entries();}
on_percentage_entry_2_activate(GtkEditable * w,gpointer)30324 void on_percentage_entry_2_activate(GtkEditable *w, gpointer) {percentage_entry_changed(2, GTK_ENTRY(w)); update_percentage_entries();}
on_percentage_entry_3_activate(GtkEditable * w,gpointer)30325 void on_percentage_entry_3_activate(GtkEditable *w, gpointer) {percentage_entry_changed(4, GTK_ENTRY(w)); update_percentage_entries();}
on_percentage_entry_4_activate(GtkEditable * w,gpointer)30326 void on_percentage_entry_4_activate(GtkEditable *w, gpointer) {percentage_entry_changed(8, GTK_ENTRY(w)); update_percentage_entries();}
on_percentage_entry_5_activate(GtkEditable * w,gpointer)30327 void on_percentage_entry_5_activate(GtkEditable *w, gpointer) {percentage_entry_changed(16, GTK_ENTRY(w)); update_percentage_entries();}
on_percentage_entry_6_activate(GtkEditable * w,gpointer)30328 void on_percentage_entry_6_activate(GtkEditable *w, gpointer) {percentage_entry_changed(32, GTK_ENTRY(w)); update_percentage_entries();}
on_percentage_entry_7_activate(GtkEditable * w,gpointer)30329 void on_percentage_entry_7_activate(GtkEditable *w, gpointer) {percentage_entry_changed(64, GTK_ENTRY(w)); update_percentage_entries();}
update_percentage_entries()30330 void update_percentage_entries() {
30331 	if(updating_percentage_entries) return;
30332 	if(percentage_entries_changes.size() < 2) return;
30333 	int variant = percentage_entries_changes[percentage_entries_changes.size() - 1];
30334 	int variant2 = percentage_entries_changes[percentage_entries_changes.size() - 2];
30335 	if(variant > 4) {
30336 		for(int i = percentage_entries_changes.size() - 3; i >= 0 && variant2 > 4; i--) {
30337 			variant2 = percentage_entries_changes[(size_t) i];
30338 		}
30339 		if(variant2 > 4) return;
30340 	}
30341 	variant += variant2;
30342 	updating_percentage_entries = true;
30343 	GtkWidget *w1 = GTK_WIDGET(gtk_builder_get_object(percentage_builder, "percentage_entry_1"));
30344 	GtkWidget *w2 = GTK_WIDGET(gtk_builder_get_object(percentage_builder, "percentage_entry_2"));
30345 	GtkWidget *w3 = GTK_WIDGET(gtk_builder_get_object(percentage_builder, "percentage_entry_3"));
30346 	GtkWidget *w4 = GTK_WIDGET(gtk_builder_get_object(percentage_builder, "percentage_entry_4"));
30347 	GtkWidget *w5 = GTK_WIDGET(gtk_builder_get_object(percentage_builder, "percentage_entry_5"));
30348 	GtkWidget *w6 = GTK_WIDGET(gtk_builder_get_object(percentage_builder, "percentage_entry_6"));
30349 	GtkWidget *w7 = GTK_WIDGET(gtk_builder_get_object(percentage_builder, "percentage_entry_7"));
30350 	g_signal_handlers_block_matched((gpointer) w1, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_percentage_entry_1_changed, NULL);
30351 	g_signal_handlers_block_matched((gpointer) w2, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_percentage_entry_2_changed, NULL);
30352 	g_signal_handlers_block_matched((gpointer) w3, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_percentage_entry_3_changed, NULL);
30353 	g_signal_handlers_block_matched((gpointer) w4, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_percentage_entry_4_changed, NULL);
30354 	g_signal_handlers_block_matched((gpointer) w5, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_percentage_entry_5_changed, NULL);
30355 	g_signal_handlers_block_matched((gpointer) w6, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_percentage_entry_6_changed, NULL);
30356 	g_signal_handlers_block_matched((gpointer) w7, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_percentage_entry_7_changed, NULL);
30357 	MathStructure m1, m2, m3, m4, m5, m6, m7, m1_pre, m2_pre;
30358 	string str1, str2;
30359 	switch(variant) {
30360 		case 3: {str1 = gtk_entry_get_text(GTK_ENTRY(w1)); str2 = gtk_entry_get_text(GTK_ENTRY(w2)); break;}
30361 		case 5: {str1 = gtk_entry_get_text(GTK_ENTRY(w1)); str2 = gtk_entry_get_text(GTK_ENTRY(w3)); break;}
30362 		case 9: {str1 = gtk_entry_get_text(GTK_ENTRY(w1)); str2 = gtk_entry_get_text(GTK_ENTRY(w4)); break;}
30363 		case 17: {str1 = gtk_entry_get_text(GTK_ENTRY(w1)); str2 = gtk_entry_get_text(GTK_ENTRY(w5)); break;}
30364 		case 33: {str1 = gtk_entry_get_text(GTK_ENTRY(w1)); str2 = gtk_entry_get_text(GTK_ENTRY(w6)); break;}
30365 		case 65: {str1 = gtk_entry_get_text(GTK_ENTRY(w1)); str2 = gtk_entry_get_text(GTK_ENTRY(w7)); break;}
30366 		case 6: {str1 = gtk_entry_get_text(GTK_ENTRY(w2)); str2 = gtk_entry_get_text(GTK_ENTRY(w3)); break;}
30367 		case 10: {str1 = gtk_entry_get_text(GTK_ENTRY(w2)); str2 = gtk_entry_get_text(GTK_ENTRY(w4)); break;}
30368 		case 18: {str1 = gtk_entry_get_text(GTK_ENTRY(w2)); str2 = gtk_entry_get_text(GTK_ENTRY(w5)); break;}
30369 		case 34: {str1 = gtk_entry_get_text(GTK_ENTRY(w2)); str2 = gtk_entry_get_text(GTK_ENTRY(w6)); break;}
30370 		case 66: {str1 = gtk_entry_get_text(GTK_ENTRY(w2)); str2 = gtk_entry_get_text(GTK_ENTRY(w7)); break;}
30371 		case 12: {str1 = gtk_entry_get_text(GTK_ENTRY(w3)); str2 = gtk_entry_get_text(GTK_ENTRY(w4)); break;}
30372 		case 20: {str1 = gtk_entry_get_text(GTK_ENTRY(w3)); str2 = gtk_entry_get_text(GTK_ENTRY(w5)); break;}
30373 		case 36: {str1 = gtk_entry_get_text(GTK_ENTRY(w3)); str2 = gtk_entry_get_text(GTK_ENTRY(w6)); break;}
30374 		case 68: {str1 = gtk_entry_get_text(GTK_ENTRY(w3)); str2 = gtk_entry_get_text(GTK_ENTRY(w7)); break;}
30375 		default: {variant = 0;}
30376 	}
30377 	do_timeout = false;
30378 	EvaluationOptions eo;
30379 	eo.parse_options = evalops.parse_options;
30380 	if(eo.parse_options.parsing_mode == PARSING_MODE_RPN || eo.parse_options.parsing_mode == PARSING_MODE_CHAIN) eo.parse_options.parsing_mode = PARSING_MODE_ADAPTIVE;
30381 	eo.parse_options.read_precision = DONT_READ_PRECISION;
30382 	eo.parse_options.base = 10;
30383 	eo.assume_denominators_nonzero = true;
30384 	eo.warn_about_denominators_assumed_nonzero = false;
30385 	if(variant != 0) {
30386 		m1_pre.set(CALCULATOR->parse(CALCULATOR->unlocalizeExpression(str1, eo.parse_options), eo.parse_options));
30387 		m2_pre.set(CALCULATOR->parse(CALCULATOR->unlocalizeExpression(str2, eo.parse_options), eo.parse_options));
30388 	}
30389 	switch(variant) {
30390 		case 3: {m1 = m1_pre; m2 = m2_pre; break;}
30391 		case 5: {m1 = m1_pre; m2 = m2_pre; m2 += m1; break;}
30392 		case 9: {m1 = m1_pre; m2 = m2_pre; m2 /= 100; m2 += 1; m2 *= m1; break;}
30393 		case 17: {m1 = m1_pre; m2_pre /= 100; m2_pre += 1; m2 = m1; m2 /= m2_pre; break;}
30394 		case 33: {m1 = m1_pre; m2 = m2_pre; m2 /= 100; m2 *= m1; break;}
30395 		case 65: {m1 = m1_pre; m2_pre /= 100; m2 = m1; m2 /= m2_pre; break;}
30396 		case 6: {m2 = m1_pre; m1 = m1_pre; m1 -= m2_pre; break;}
30397 		case 10: {m2 = m1_pre; m2_pre /= 100; m2_pre += 1; m1 = m2; m1 /= m2_pre; break;}
30398 		case 18: {m2 = m1_pre; m2_pre /= 100; m2_pre += 1; m1 = m2; m1 *= m2_pre; break;}
30399 		case 34: {m2 = m1_pre; m2_pre /= 100; m1 = m2; m1 /= m2_pre; break;}
30400 		case 66: {m2 = m1_pre; m2_pre /= 100; m1 = m2; m1 *= m2_pre; break;}
30401 		case 12: {m1 = m1_pre; m2_pre /= 100; m1 /= m2_pre; m2 = m1; m2 += m1_pre; break;}
30402 		case 20: {m1_pre.negate(); m2 = m1_pre; m2_pre /= 100; m2 /= m2_pre; m1 = m2; m1 += m1_pre; break;}
30403 		case 36: {m1 = m1_pre; m2_pre /= 100; m2_pre -= 1; m1 /= m2_pre; m2 = m1; m2 += m1_pre; break;}
30404 		case 68: {m1_pre.negate(); m2 = m1_pre; m2_pre /= 100; m2_pre -= 1; m2 /= m2_pre; m1 = m2; m1 += m1_pre; break;}
30405 		default: {variant = 0;}
30406 	}
30407 	if(variant != 0) {
30408 		m3 = m2; m3 -= m1;
30409 		m6 = m2; m6 /= m1;
30410 		m7 = m1; m7 /= m2;
30411 		m4 = m6; m4 -= 1;
30412 		m5 = m7; m5 -= 1;
30413 		m4 *= 100; m5 *= 100; m6 *= 100; m7 *= 100;
30414 		CALCULATOR->calculate(&m1, 500, eo);
30415 		CALCULATOR->calculate(&m2, 500, eo);
30416 		CALCULATOR->calculate(&m3, 500, eo);
30417 		CALCULATOR->calculate(&m4, 500, eo);
30418 		CALCULATOR->calculate(&m5, 500, eo);
30419 		CALCULATOR->calculate(&m6, 500, eo);
30420 		CALCULATOR->calculate(&m7, 500, eo);
30421 		PrintOptions po = printops;
30422 		po.base = 10;
30423 		po.number_fraction_format = FRACTION_DECIMAL;
30424 		po.interval_display = INTERVAL_DISPLAY_SIGNIFICANT_DIGITS;
30425 		gtk_entry_set_text(GTK_ENTRY(w1), m1.isAborted() ? CALCULATOR->timedOutString().c_str() : CALCULATOR->print(m1, 200, po).c_str());
30426 		gtk_entry_set_text(GTK_ENTRY(w2), m2.isAborted() ? CALCULATOR->timedOutString().c_str() : CALCULATOR->print(m2, 200, po).c_str());
30427 		gtk_entry_set_text(GTK_ENTRY(w3), m3.isAborted() ? CALCULATOR->timedOutString().c_str() : CALCULATOR->print(m3, 200, po).c_str());
30428 		po.max_decimals = 2;
30429 		po.use_max_decimals = true;
30430 		gtk_entry_set_text(GTK_ENTRY(w4), m4.isAborted() ? CALCULATOR->timedOutString().c_str() : CALCULATOR->print(m4, 200, po).c_str());
30431 		gtk_entry_set_text(GTK_ENTRY(w5), m5.isAborted() ? CALCULATOR->timedOutString().c_str() : CALCULATOR->print(m5, 200, po).c_str());
30432 		gtk_entry_set_text(GTK_ENTRY(w6), m6.isAborted() ? CALCULATOR->timedOutString().c_str() : CALCULATOR->print(m6, 200, po).c_str());
30433 		gtk_entry_set_text(GTK_ENTRY(w7), m7.isAborted() ? CALCULATOR->timedOutString().c_str() : CALCULATOR->print(m7, 200, po).c_str());
30434 	}
30435 	display_errors(NULL, GTK_WIDGET(gtk_builder_get_object(percentage_builder, "percentage_dialog")));
30436 	do_timeout = true;
30437 	g_signal_handlers_unblock_matched((gpointer) w1, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_percentage_entry_1_changed, NULL);
30438 	g_signal_handlers_unblock_matched((gpointer) w2, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_percentage_entry_2_changed, NULL);
30439 	g_signal_handlers_unblock_matched((gpointer) w3, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_percentage_entry_3_changed, NULL);
30440 	g_signal_handlers_unblock_matched((gpointer) w4, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_percentage_entry_4_changed, NULL);
30441 	g_signal_handlers_unblock_matched((gpointer) w5, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_percentage_entry_5_changed, NULL);
30442 	g_signal_handlers_unblock_matched((gpointer) w6, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_percentage_entry_6_changed, NULL);
30443 	g_signal_handlers_unblock_matched((gpointer) w7, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_percentage_entry_7_changed, NULL);
30444 	updating_percentage_entries = false;
30445 }
30446 
nbases_get_entry()30447 GtkWidget *nbases_get_entry() {
30448 	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"));
30449 	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"));
30450 	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"));
30451 	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"));
30452 	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"));
30453 	return GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_entry_decimal"));
30454 }
nbases_get_base()30455 int nbases_get_base() {
30456 	if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(nbases_builder, "nbases_button_bin")))) return 2;
30457 	if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(nbases_builder, "nbases_button_oct")))) return 8;
30458 	if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(nbases_builder, "nbases_button_duo")))) return 12;
30459 	if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(nbases_builder, "nbases_button_hex")))) return 16;
30460 	if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(nbases_builder, "nbases_button_rom")))) return BASE_ROMAN_NUMERALS;
30461 	return 10;
30462 }
30463 
update_nbases_entries(const MathStructure & value,int base)30464 void update_nbases_entries(const MathStructure &value, int base) {
30465 	GtkWidget *w_dec, *w_bin, *w_oct, *w_hex, *w_duo, *w_roman;
30466 	w_dec = GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_entry_decimal"));
30467 	w_bin = GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_entry_binary"));
30468 	w_oct = GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_entry_octal"));
30469 	w_hex = GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_entry_hexadecimal"));
30470 	w_duo = GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_entry_duo"));
30471 	w_roman = GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_entry_roman"));
30472 	g_signal_handlers_block_matched((gpointer) w_dec, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_entry_decimal_changed, NULL);
30473 	g_signal_handlers_block_matched((gpointer) w_bin, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_entry_binary_changed, NULL);
30474 	g_signal_handlers_block_matched((gpointer) w_oct, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_entry_octal_changed, NULL);
30475 	g_signal_handlers_block_matched((gpointer) w_hex, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_entry_hexadecimal_changed, NULL);
30476 	g_signal_handlers_block_matched((gpointer) w_duo, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_entry_duo_changed, NULL);
30477 	g_signal_handlers_block_matched((gpointer) w_roman, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_entry_roman_changed, NULL);
30478 	PrintOptions po;
30479 	po.number_fraction_format = FRACTION_DECIMAL;
30480 	po.interval_display = INTERVAL_DISPLAY_SIGNIFICANT_DIGITS;
30481 	po.twos_complement = printops.twos_complement;
30482 	po.hexadecimal_twos_complement = printops.hexadecimal_twos_complement;
30483 	po.use_unicode_signs = printops.use_unicode_signs;
30484 	po.lower_case_e = printops.lower_case_e;
30485 	po.lower_case_numbers = printops.lower_case_numbers;
30486 	po.base_display = BASE_DISPLAY_NONE;
30487 	po.abbreviate_names = printops.abbreviate_names;
30488 	po.digit_grouping = printops.digit_grouping;
30489 	po.multiplication_sign = printops.multiplication_sign;
30490 	po.division_sign = printops.division_sign;
30491 	po.short_multiplication = printops.short_multiplication;
30492 	po.excessive_parenthesis = printops.excessive_parenthesis;
30493 	po.can_display_unicode_string_function = &can_display_unicode_string_function;
30494 	po.can_display_unicode_string_arg = (void*) w_dec;
30495 	po.spell_out_logical_operators = printops.spell_out_logical_operators;
30496 	po.interval_display = INTERVAL_DISPLAY_SIGNIFICANT_DIGITS;
30497 	string str;
30498 	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());}
30499 	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());}
30500 	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());}
30501 	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());}
30502 	if(base != BASE_ROMAN_NUMERALS) {
30503 		if(value.isAborted()) {
30504 			gtk_entry_set_text(GTK_ENTRY(w_roman), CALCULATOR->timedOutString().c_str());
30505 		} else if(!value.isNumber() || !value.number().isReal() || !(value.number() <= 9999) || !(value.number() >= -9999)) {
30506 			gtk_entry_set_text(GTK_ENTRY(w_roman), "-");
30507 		} else {
30508 			Number nr = value.number(); nr.round(printops.round_halfway_to_even);
30509 			po.base = BASE_ROMAN_NUMERALS;
30510 			gtk_entry_set_text(GTK_ENTRY(w_roman), nr.print(po).c_str());
30511 		}
30512 	}
30513 	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());}
30514 	g_signal_handlers_unblock_matched((gpointer) w_dec, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_entry_decimal_changed, NULL);
30515 	g_signal_handlers_unblock_matched((gpointer) w_bin, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_entry_binary_changed, NULL);
30516 	g_signal_handlers_unblock_matched((gpointer) w_oct, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_entry_octal_changed, NULL);
30517 	g_signal_handlers_unblock_matched((gpointer) w_hex, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_entry_hexadecimal_changed, NULL);
30518 	g_signal_handlers_unblock_matched((gpointer) w_duo, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_entry_duo_changed, NULL);
30519 	g_signal_handlers_unblock_matched((gpointer) w_roman, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_entry_roman_changed, NULL);
30520 	gtk_widget_set_tooltip_text(w_dec, "");
30521 	gtk_widget_set_tooltip_text(w_bin, "");
30522 	gtk_widget_set_tooltip_text(w_oct, "");
30523 	gtk_widget_set_tooltip_text(w_duo, "");
30524 	gtk_widget_set_tooltip_text(w_hex, "");
30525 	gtk_widget_set_tooltip_text(w_roman, "");
30526 	if(base == 2) gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_label_binary")), "");
30527 	if(base == 8) gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_label_octal")), "");
30528 	if(base == 10) gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_label_decimal")), "");
30529 	if(base == 12) gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_label_duodecimal")), "");
30530 	if(base == 16) gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_label_hexadecimal")), "");
30531 	if(base == BASE_ROMAN_NUMERALS) gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_label_roman")), "");
30532 	gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_binary")), _("Binary"));
30533 		gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_octal")), _("Octal"));
30534 		gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_decimal")), _("Decimal"));
30535 		gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_duodecimal")), _("Duodecimal"));
30536 		gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_hexadecimal")), _("Hexadecimal"));
30537 		gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_roman")), _("Roman numerals"));
30538 	if(CALCULATOR->message()) {
30539 		string sfull;
30540 		int index = 0;
30541 		MessageType mtype_highest = MESSAGE_INFORMATION;
30542 		while(true) {
30543 			MessageType mtype = CALCULATOR->message()->type();
30544 			if(index > 0) {
30545 				if(index == 1) sfull = "• " + sfull;
30546 				sfull += "\n• ";
30547 			}
30548 			sfull += CALCULATOR->message()->message();
30549 			if(mtype > mtype_highest) {
30550 				mtype_highest = mtype;
30551 			}
30552 			if(!CALCULATOR->nextMessage()) break;
30553 			index++;
30554 		}
30555 		if(base == 2) gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_label_binary")), sfull.c_str());
30556 		else if(base == 8) gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_label_octal")), sfull.c_str());
30557 		else if(base == 10) gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_label_decimal")), sfull.c_str());
30558 		else if(base == 12) gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_label_duodecimal")), sfull.c_str());
30559 		else if(base == 16) gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_label_hexadecimal")), sfull.c_str());
30560 		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());
30561 		if(base == 10) gtk_widget_set_tooltip_text(w_dec, sfull.c_str());
30562 		else if(base == 2) gtk_widget_set_tooltip_text(w_bin, sfull.c_str());
30563 		else if(base == 8) gtk_widget_set_tooltip_text(w_oct, sfull.c_str());
30564 		else if(base == 12) gtk_widget_set_tooltip_text(w_duo, sfull.c_str());
30565 		else if(base == 16) gtk_widget_set_tooltip_text(w_hex, sfull.c_str());
30566 		else if(base == BASE_ROMAN_NUMERALS) gtk_widget_set_tooltip_text(w_roman, sfull.c_str());
30567 		if(mtype_highest != MESSAGE_INFORMATION) {
30568 			string str = "<span foreground=\"";
30569 			if(mtype_highest == MESSAGE_ERROR) str += nbases_error_color;
30570 			else str += nbases_warning_color;
30571 			str += "\">";
30572 			if(base == 2) str += _("Binary");
30573 			else if(base == 8) str += _("Octal");
30574 			else if(base == 10) str += _("Decimal");
30575 			else if(base == 12) str += _("Duodecimal");
30576 			else if(base == 16) str += _("Hexadecimal");
30577 			else if(base == BASE_ROMAN_NUMERALS) str += _("Roman numerals");
30578 			str += "</span>";
30579 			if(base == 2) gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_binary")), str.c_str());
30580 			else if(base == 8) gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_octal")), str.c_str());
30581 			else if(base == 10) gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_decimal")), str.c_str());
30582 			else if(base == 12) gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_duodecimal")), str.c_str());
30583 			else if(base == 16) gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_hexadecimal")), str.c_str());
30584 			else if(base == BASE_ROMAN_NUMERALS) gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_roman")), str.c_str());
30585 		}
30586 	}
30587 }
on_nbases_button_close_clicked(GtkButton *,gpointer)30588 void on_nbases_button_close_clicked(GtkButton*, gpointer) {
30589 	gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_dialog")));
30590 }
on_nbases_entry_decimal_changed(GtkEditable * editable,gpointer)30591 void on_nbases_entry_decimal_changed(GtkEditable *editable, gpointer) {
30592 	if(changing_in_nbases_dialog) return;
30593 	string str = gtk_entry_get_text(GTK_ENTRY(editable));
30594 	remove_blank_ends(str);
30595 	if(str.empty()) return;
30596 	if(last_is_operator(str, true)) return;
30597 	changing_in_nbases_dialog = true;
30598 	EvaluationOptions eo;
30599 	eo.parse_options = evalops.parse_options;
30600 	if(eo.parse_options.parsing_mode == PARSING_MODE_RPN || eo.parse_options.parsing_mode == PARSING_MODE_CHAIN) eo.parse_options.parsing_mode = PARSING_MODE_ADAPTIVE;
30601 	eo.parse_options.read_precision = DONT_READ_PRECISION;
30602 	eo.parse_options.base = 10;
30603 	MathStructure value;
30604 	do_timeout = false;
30605 	CALCULATOR->calculate(&value, CALCULATOR->unlocalizeExpression(gtk_entry_get_text(GTK_ENTRY(editable)), eo.parse_options), 1500, eo);
30606 	update_nbases_entries(value, 10);
30607 	do_timeout = true;
30608 	changing_in_nbases_dialog = false;
30609 }
on_nbases_entry_binary_changed(GtkEditable * editable,gpointer)30610 void on_nbases_entry_binary_changed(GtkEditable *editable, gpointer) {
30611 	if(changing_in_nbases_dialog) return;
30612 	string str = gtk_entry_get_text(GTK_ENTRY(editable));
30613 	remove_blank_ends(str);
30614 	if(str.empty()) return;
30615 	if(last_is_operator(str)) return;
30616 	EvaluationOptions eo;
30617 	eo.parse_options = evalops.parse_options;
30618 	if(eo.parse_options.parsing_mode == PARSING_MODE_RPN || eo.parse_options.parsing_mode == PARSING_MODE_CHAIN) eo.parse_options.parsing_mode = PARSING_MODE_ADAPTIVE;
30619 	eo.parse_options.read_precision = DONT_READ_PRECISION;
30620 	eo.parse_options.base = BASE_BINARY;
30621 	eo.parse_options.twos_complement = twos_complement_in;
30622 	changing_in_nbases_dialog = true;
30623 	MathStructure value;
30624 	do_timeout = false;
30625 	CALCULATOR->calculate(&value, CALCULATOR->unlocalizeExpression(gtk_entry_get_text(GTK_ENTRY(editable)), eo.parse_options), 1500, eo);
30626 	update_nbases_entries(value, 2);
30627 	do_timeout = true;
30628 	changing_in_nbases_dialog = false;
30629 }
on_nbases_entry_octal_changed(GtkEditable * editable,gpointer)30630 void on_nbases_entry_octal_changed(GtkEditable *editable, gpointer) {
30631 	if(changing_in_nbases_dialog) return;
30632 	string str = gtk_entry_get_text(GTK_ENTRY(editable));
30633 	remove_blank_ends(str);
30634 	if(str.empty()) return;
30635 	if(last_is_operator(str)) return;
30636 	EvaluationOptions eo;
30637 	eo.parse_options = evalops.parse_options;
30638 	if(eo.parse_options.parsing_mode == PARSING_MODE_RPN || eo.parse_options.parsing_mode == PARSING_MODE_CHAIN) eo.parse_options.parsing_mode = PARSING_MODE_ADAPTIVE;
30639 	eo.parse_options.read_precision = DONT_READ_PRECISION;
30640 	eo.parse_options.base = BASE_OCTAL;
30641 	changing_in_nbases_dialog = true;
30642 	MathStructure value;
30643 	do_timeout = false;
30644 	CALCULATOR->calculate(&value, CALCULATOR->unlocalizeExpression(gtk_entry_get_text(GTK_ENTRY(editable)), eo.parse_options), 1500, eo);
30645 	update_nbases_entries(value, 8);
30646 	do_timeout = true;
30647 	changing_in_nbases_dialog = false;
30648 }
on_nbases_entry_hexadecimal_changed(GtkEditable * editable,gpointer)30649 void on_nbases_entry_hexadecimal_changed(GtkEditable *editable, gpointer) {
30650 	if(changing_in_nbases_dialog) return;
30651 	string str = gtk_entry_get_text(GTK_ENTRY(editable));
30652 	remove_blank_ends(str);
30653 	if(str.empty()) return;
30654 	if(last_is_operator(str)) return;
30655 	EvaluationOptions eo;
30656 	eo.parse_options = evalops.parse_options;
30657 	if(eo.parse_options.parsing_mode == PARSING_MODE_RPN || eo.parse_options.parsing_mode == PARSING_MODE_CHAIN) eo.parse_options.parsing_mode = PARSING_MODE_ADAPTIVE;
30658 	eo.parse_options.read_precision = DONT_READ_PRECISION;
30659 	eo.parse_options.base = BASE_HEXADECIMAL;
30660 	eo.parse_options.hexadecimal_twos_complement = hexadecimal_twos_complement_in;
30661 	changing_in_nbases_dialog = true;
30662 	MathStructure value;
30663 	do_timeout = false;
30664 	str = CALCULATOR->unlocalizeExpression(gtk_entry_get_text(GTK_ENTRY(editable)), eo.parse_options);
30665 	CALCULATOR->calculate(&value, str, 1500, eo);
30666 	update_nbases_entries(value, 16);
30667 	do_timeout = true;
30668 	changing_in_nbases_dialog = false;
30669 }
on_nbases_entry_duo_changed(GtkEditable * editable,gpointer)30670 void on_nbases_entry_duo_changed(GtkEditable *editable, gpointer) {
30671 	if(changing_in_nbases_dialog) return;
30672 	string str = gtk_entry_get_text(GTK_ENTRY(editable));
30673 	remove_blank_ends(str);
30674 	if(str.empty()) return;
30675 	if(last_is_operator(str)) return;
30676 	EvaluationOptions eo;
30677 	eo.parse_options = evalops.parse_options;
30678 	if(eo.parse_options.parsing_mode == PARSING_MODE_RPN || eo.parse_options.parsing_mode == PARSING_MODE_CHAIN) eo.parse_options.parsing_mode = PARSING_MODE_ADAPTIVE;
30679 	eo.parse_options.read_precision = DONT_READ_PRECISION;
30680 	eo.parse_options.base = BASE_DUODECIMAL;
30681 	changing_in_nbases_dialog = true;
30682 	MathStructure value;
30683 	do_timeout = false;
30684 	CALCULATOR->calculate(&value, CALCULATOR->unlocalizeExpression(gtk_entry_get_text(GTK_ENTRY(editable)), eo.parse_options), 1500, eo);
30685 	update_nbases_entries(value, 12);
30686 	do_timeout = true;
30687 	changing_in_nbases_dialog = false;
30688 }
on_nbases_entry_roman_changed(GtkEditable * editable,gpointer)30689 void on_nbases_entry_roman_changed(GtkEditable *editable, gpointer) {
30690 	if(changing_in_nbases_dialog) return;
30691 	string str = gtk_entry_get_text(GTK_ENTRY(editable));
30692 	remove_blank_ends(str);
30693 	if(str.empty()) return;
30694 	if(last_is_operator(str) && (str[str.length() - 1] != '|' || str.find('|') == str.length() - 1)) return;
30695 	EvaluationOptions eo;
30696 	eo.parse_options = evalops.parse_options;
30697 	if(eo.parse_options.parsing_mode == PARSING_MODE_RPN || eo.parse_options.parsing_mode == PARSING_MODE_CHAIN) eo.parse_options.parsing_mode = PARSING_MODE_ADAPTIVE;
30698 	eo.parse_options.read_precision = DONT_READ_PRECISION;
30699 	eo.parse_options.base = BASE_ROMAN_NUMERALS;
30700 	changing_in_nbases_dialog = true;
30701 	MathStructure value;
30702 	do_timeout = false;
30703 	CALCULATOR->calculate(&value, CALCULATOR->unlocalizeExpression(gtk_entry_get_text(GTK_ENTRY(editable)), eo.parse_options), 1500, eo);
30704 	update_nbases_entries(value, BASE_ROMAN_NUMERALS);
30705 	do_timeout = true;
30706 	changing_in_nbases_dialog = false;
30707 }
30708 
30709 void on_nbases_button_bin_toggled(GtkToggleButton *w, gpointer);
30710 void on_nbases_button_oct_toggled(GtkToggleButton *w, gpointer);
30711 void on_nbases_button_dec_toggled(GtkToggleButton *w, gpointer);
30712 void on_nbases_button_duo_toggled(GtkToggleButton *w, gpointer);
30713 void on_nbases_button_hex_toggled(GtkToggleButton *w, gpointer);
30714 void on_nbases_button_rom_toggled(GtkToggleButton *w, gpointer);
30715 
update_nbases_keypad(int base)30716 void update_nbases_keypad(int base) {
30717 	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);
30718 	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);
30719 	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);
30720 	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);
30721 	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);
30722 	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);
30723 	if(base != 2) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(nbases_builder, "nbases_button_bin")), FALSE);
30724 	if(base != 8) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(nbases_builder, "nbases_button_oct")), FALSE);
30725 	if(base != 10) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(nbases_builder, "nbases_button_dec")), FALSE);
30726 	if(base != 12) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(nbases_builder, "nbases_button_duo")), FALSE);
30727 	if(base != 16) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(nbases_builder, "nbases_button_hex")), FALSE);
30728 	if(base != BASE_ROMAN_NUMERALS) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(nbases_builder, "nbases_button_rom")), FALSE);
30729 	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);
30730 	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);
30731 	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);
30732 	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);
30733 	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);
30734 	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);
30735 
30736 	if(base == BASE_ROMAN_NUMERALS && strcmp(gtk_label_get_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_one"))), "1") != 0) return;
30737 
30738 	if(base == 12) {
30739 		if(strcmp(gtk_label_get_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_a"))), "A") == 0) {
30740 			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")), "↊");
30741 			else gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_a")), "X");
30742 			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")), "↋");
30743 			else gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_b")), "E");
30744 		}
30745 	} else if(strcmp(gtk_label_get_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_a"))), "A") != 0) {
30746 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_a")), "A");
30747 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_b")), "B");
30748 	}
30749 	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"));
30750 	if(base == BASE_ROMAN_NUMERALS) {
30751 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_zero")), "I");
30752 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_one")), "V");
30753 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_two")), "X");
30754 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_three")), "L");
30755 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_four")), "C");
30756 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_five")), "D");
30757 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_six")), "M");
30758 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_eight")), "|");
30759 		if(uni_roman) {
30760 			gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_nine")), "Ɔ");
30761 		} else {
30762 			gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_seven")), "(");
30763 			gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_nine")), ")");
30764 		}
30765 	} else if(strcmp(gtk_label_get_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_one"))), "1") != 0) {
30766 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_zero")), "0");
30767 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_one")), "1");
30768 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_two")), "2");
30769 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_three")), "3");
30770 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_four")), "4");
30771 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_five")), "5");
30772 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_six")), "6");
30773 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_seven")), "7");
30774 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_eight")), "8");
30775 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(nbases_builder, "nbases_label_nine")), "9");
30776 	}
30777 
30778 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_button_two")), base != 2);
30779 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_button_three")), base != 2);
30780 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_button_four")), base != 2);
30781 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_button_five")), base != 2);
30782 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_button_six")), base != 2);
30783 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_button_seven")), base != 2 && (base != BASE_ROMAN_NUMERALS || !uni_roman));
30784 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_button_eight")), base != 2 && base != 8);
30785 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_button_nine")), base != 2 && base != 8);
30786 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_button_a")), base >= 12);
30787 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_button_b")), base >= 12);
30788 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_button_c")), base == 16);
30789 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_button_d")), base == 16);
30790 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_button_e")), base == 16);
30791 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_button_f")), base == 16);
30792 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_button_and")), base != BASE_ROMAN_NUMERALS);
30793 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_button_or")), base != BASE_ROMAN_NUMERALS);
30794 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_button_xor")), base != BASE_ROMAN_NUMERALS);
30795 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_button_not")), base != BASE_ROMAN_NUMERALS);
30796 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_button_left_shift")), base != BASE_ROMAN_NUMERALS);
30797 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_button_right_shift")), base != BASE_ROMAN_NUMERALS);
30798 
30799 }
30800 
30801 gboolean on_nbases_entry_binary_focus_in_event(GtkWidget*, GdkEventFocus*, gpointer);
30802 gboolean on_nbases_entry_octal_focus_in_event(GtkWidget*, GdkEventFocus*, gpointer);
30803 gboolean on_nbases_entry_decimal_focus_in_event(GtkWidget*, GdkEventFocus*, gpointer);
30804 gboolean on_nbases_entry_duo_focus_in_event(GtkWidget*, GdkEventFocus*, gpointer);
30805 gboolean on_nbases_entry_hexadecimal_focus_in_event(GtkWidget*, GdkEventFocus*, gpointer);
30806 gboolean on_nbases_entry_roman_focus_in_event(GtkWidget*, GdkEventFocus*, gpointer);
30807 
on_nbases_button_bin_toggled(GtkToggleButton * w,gpointer)30808 void on_nbases_button_bin_toggled(GtkToggleButton *w, gpointer) {
30809 	if(!gtk_toggle_button_get_active(w)) {
30810 		g_signal_handlers_block_matched((gpointer) w, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_button_bin_toggled, NULL);
30811 		gtk_toggle_button_set_active(w, TRUE);
30812 		g_signal_handlers_unblock_matched((gpointer) w, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_button_bin_toggled, NULL);
30813 		return;
30814 	}
30815 	update_nbases_keypad(2);
30816 	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);
30817 	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_entry_binary")));
30818 	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);
30819 }
on_nbases_button_oct_toggled(GtkToggleButton * w,gpointer)30820 void on_nbases_button_oct_toggled(GtkToggleButton *w, gpointer) {
30821 	if(!gtk_toggle_button_get_active(w)) {
30822 		g_signal_handlers_block_matched((gpointer) w, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_button_oct_toggled, NULL);
30823 		gtk_toggle_button_set_active(w, TRUE);
30824 		g_signal_handlers_unblock_matched((gpointer) w, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_button_oct_toggled, NULL);
30825 		return;
30826 	}
30827 	update_nbases_keypad(8);
30828 	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);
30829 	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_entry_octal")));
30830 	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);
30831 }
on_nbases_button_dec_toggled(GtkToggleButton * w,gpointer)30832 void on_nbases_button_dec_toggled(GtkToggleButton *w, gpointer) {
30833 	if(!gtk_toggle_button_get_active(w)) {
30834 		g_signal_handlers_block_matched((gpointer) w, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_button_dec_toggled, NULL);
30835 		gtk_toggle_button_set_active(w, TRUE);
30836 		g_signal_handlers_unblock_matched((gpointer) w, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_button_dec_toggled, NULL);
30837 		return;
30838 	}
30839 	update_nbases_keypad(10);
30840 	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);
30841 	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_entry_decimal")));
30842 	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);
30843 }
on_nbases_button_duo_toggled(GtkToggleButton * w,gpointer)30844 void on_nbases_button_duo_toggled(GtkToggleButton *w, gpointer) {
30845 	if(!gtk_toggle_button_get_active(w)) {
30846 		g_signal_handlers_block_matched((gpointer) w, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_button_duo_toggled, NULL);
30847 		gtk_toggle_button_set_active(w, TRUE);
30848 		g_signal_handlers_unblock_matched((gpointer) w, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_button_duo_toggled, NULL);
30849 		return;
30850 	}
30851 	update_nbases_keypad(12);
30852 	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);
30853 	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_entry_duo")));
30854 	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);
30855 }
on_nbases_button_hex_toggled(GtkToggleButton * w,gpointer)30856 void on_nbases_button_hex_toggled(GtkToggleButton *w, gpointer) {
30857 	if(!gtk_toggle_button_get_active(w)) {
30858 		g_signal_handlers_block_matched((gpointer) w, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_button_hex_toggled, NULL);
30859 		gtk_toggle_button_set_active(w, TRUE);
30860 		g_signal_handlers_unblock_matched((gpointer) w, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_button_hex_toggled, NULL);
30861 		return;
30862 	}
30863 	update_nbases_keypad(16);
30864 	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);
30865 	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_entry_hexadecimal")));
30866 	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);
30867 }
on_nbases_button_rom_toggled(GtkToggleButton * w,gpointer)30868 void on_nbases_button_rom_toggled(GtkToggleButton *w, gpointer) {
30869 	if(!gtk_toggle_button_get_active(w)) {
30870 		g_signal_handlers_block_matched((gpointer) w, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_button_rom_toggled, NULL);
30871 		gtk_toggle_button_set_active(w, TRUE);
30872 		g_signal_handlers_unblock_matched((gpointer) w, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_nbases_button_rom_toggled, NULL);
30873 		return;
30874 	}
30875 	update_nbases_keypad(BASE_ROMAN_NUMERALS);
30876 	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);
30877 	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(nbases_builder, "nbases_entry_roman")));
30878 	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);
30879 }
30880 
on_nbases_entry_binary_focus_in_event(GtkWidget *,GdkEventFocus *,gpointer)30881 gboolean on_nbases_entry_binary_focus_in_event(GtkWidget*, GdkEventFocus*, gpointer) {
30882 	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);
30883 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(nbases_builder, "nbases_button_bin")), TRUE);
30884 	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);
30885 	update_nbases_keypad(2);
30886 	return FALSE;
30887 }
on_nbases_entry_octal_focus_in_event(GtkWidget *,GdkEventFocus *,gpointer)30888 gboolean on_nbases_entry_octal_focus_in_event(GtkWidget*, GdkEventFocus*, gpointer) {
30889 	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);
30890 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(nbases_builder, "nbases_button_oct")), TRUE);
30891 	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);
30892 	update_nbases_keypad(8);
30893 	return FALSE;
30894 }
on_nbases_entry_decimal_focus_in_event(GtkWidget *,GdkEventFocus *,gpointer)30895 gboolean on_nbases_entry_decimal_focus_in_event(GtkWidget*, GdkEventFocus*, gpointer) {
30896 	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);
30897 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(nbases_builder, "nbases_button_dec")), TRUE);
30898 	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);
30899 	update_nbases_keypad(10);
30900 	return FALSE;
30901 }
on_nbases_entry_duo_focus_in_event(GtkWidget *,GdkEventFocus *,gpointer)30902 gboolean on_nbases_entry_duo_focus_in_event(GtkWidget*, GdkEventFocus*, gpointer) {
30903 	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);
30904 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(nbases_builder, "nbases_button_duo")), TRUE);
30905 	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);
30906 	update_nbases_keypad(12);
30907 	return FALSE;
30908 }
on_nbases_entry_hexadecimal_focus_in_event(GtkWidget *,GdkEventFocus *,gpointer)30909 gboolean on_nbases_entry_hexadecimal_focus_in_event(GtkWidget*, GdkEventFocus*, gpointer) {
30910 	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);
30911 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(nbases_builder, "nbases_button_hex")), TRUE);
30912 	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);
30913 	update_nbases_keypad(16);
30914 	return FALSE;
30915 }
on_nbases_entry_roman_focus_in_event(GtkWidget *,GdkEventFocus *,gpointer)30916 gboolean on_nbases_entry_roman_focus_in_event(GtkWidget*, GdkEventFocus*, gpointer) {
30917 	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);
30918 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(nbases_builder, "nbases_button_rom")), TRUE);
30919 	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);
30920 	update_nbases_keypad(BASE_ROMAN_NUMERALS);
30921 	return FALSE;
30922 }
30923 
nbases_insert_text(GtkWidget * w,const gchar * text)30924 void nbases_insert_text(GtkWidget *w, const gchar *text) {
30925 	changing_in_nbases_dialog = true;
30926 	gtk_editable_delete_selection(GTK_EDITABLE(w));
30927 	changing_in_nbases_dialog = false;
30928 	gint pos = gtk_editable_get_position(GTK_EDITABLE(w));
30929 	gtk_editable_insert_text(GTK_EDITABLE(w), text, -1, &pos);
30930 	gtk_editable_set_position(GTK_EDITABLE(w), pos);
30931 	gtk_widget_grab_focus(w);
30932 	gtk_editable_select_region(GTK_EDITABLE(w), pos, pos);
30933 }
30934 
on_nbases_button_zero_clicked(GtkToggleButton *,gpointer)30935 void on_nbases_button_zero_clicked(GtkToggleButton*, gpointer) {
30936 	nbases_insert_text(nbases_get_entry(), nbases_get_base() == BASE_ROMAN_NUMERALS ? "I" : "0");
30937 }
on_nbases_button_one_clicked(GtkToggleButton *,gpointer)30938 void on_nbases_button_one_clicked(GtkToggleButton*, gpointer) {
30939 	nbases_insert_text(nbases_get_entry(), nbases_get_base() == BASE_ROMAN_NUMERALS ? "V" : "1");
30940 }
on_nbases_button_two_clicked(GtkToggleButton *,gpointer)30941 void on_nbases_button_two_clicked(GtkToggleButton*, gpointer) {
30942 	nbases_insert_text(nbases_get_entry(), nbases_get_base() == BASE_ROMAN_NUMERALS ? "X" : "2");
30943 }
on_nbases_button_three_clicked(GtkToggleButton *,gpointer)30944 void on_nbases_button_three_clicked(GtkToggleButton*, gpointer) {
30945 	nbases_insert_text(nbases_get_entry(), nbases_get_base() == BASE_ROMAN_NUMERALS ? "L" : "3");
30946 }
on_nbases_button_four_clicked(GtkToggleButton *,gpointer)30947 void on_nbases_button_four_clicked(GtkToggleButton*, gpointer) {
30948 	nbases_insert_text(nbases_get_entry(), nbases_get_base() == BASE_ROMAN_NUMERALS ? "C" : "4");
30949 }
on_nbases_button_five_clicked(GtkToggleButton *,gpointer)30950 void on_nbases_button_five_clicked(GtkToggleButton*, gpointer) {
30951 	nbases_insert_text(nbases_get_entry(), nbases_get_base() == BASE_ROMAN_NUMERALS ? "D" : "5");
30952 }
on_nbases_button_six_clicked(GtkToggleButton *,gpointer)30953 void on_nbases_button_six_clicked(GtkToggleButton*, gpointer) {
30954 	nbases_insert_text(nbases_get_entry(), nbases_get_base() == BASE_ROMAN_NUMERALS ? "M" : "6");
30955 }
on_nbases_button_seven_clicked(GtkToggleButton *,gpointer)30956 void on_nbases_button_seven_clicked(GtkToggleButton*, gpointer) {
30957 	nbases_insert_text(nbases_get_entry(), nbases_get_base() == BASE_ROMAN_NUMERALS ? "(" : "7");
30958 }
on_nbases_button_eight_clicked(GtkToggleButton *,gpointer)30959 void on_nbases_button_eight_clicked(GtkToggleButton*, gpointer) {
30960 	nbases_insert_text(nbases_get_entry(), nbases_get_base() == BASE_ROMAN_NUMERALS ? "|" : "8");
30961 }
on_nbases_button_nine_clicked(GtkToggleButton *,gpointer)30962 void on_nbases_button_nine_clicked(GtkToggleButton*, gpointer) {
30963 	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");
30964 }
on_nbases_button_a_clicked(GtkToggleButton *,gpointer)30965 void on_nbases_button_a_clicked(GtkToggleButton*, gpointer) {
30966 	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"));
30967 }
on_nbases_button_b_clicked(GtkToggleButton *,gpointer)30968 void on_nbases_button_b_clicked(GtkToggleButton*, gpointer) {
30969 	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"));
30970 }
on_nbases_button_c_clicked(GtkToggleButton *,gpointer)30971 void on_nbases_button_c_clicked(GtkToggleButton*, gpointer) {
30972 	nbases_insert_text(nbases_get_entry(), printops.lower_case_numbers ? "c" : "C");
30973 }
on_nbases_button_d_clicked(GtkToggleButton *,gpointer)30974 void on_nbases_button_d_clicked(GtkToggleButton*, gpointer) {
30975 	nbases_insert_text(nbases_get_entry(), printops.lower_case_numbers ? "d" : "D");
30976 }
on_nbases_button_e_clicked(GtkToggleButton *,gpointer)30977 void on_nbases_button_e_clicked(GtkToggleButton*, gpointer) {
30978 	nbases_insert_text(nbases_get_entry(), printops.lower_case_numbers ? "e" : "E");
30979 }
on_nbases_button_f_clicked(GtkToggleButton *,gpointer)30980 void on_nbases_button_f_clicked(GtkToggleButton*, gpointer) {
30981 	nbases_insert_text(nbases_get_entry(), printops.lower_case_numbers ? "f" : "F");
30982 }
on_nbases_button_add_clicked(GtkToggleButton *,gpointer)30983 void on_nbases_button_add_clicked(GtkToggleButton*, gpointer) {
30984 	nbases_insert_text(nbases_get_entry(), expression_add_sign());
30985 }
on_nbases_button_sub_clicked(GtkToggleButton *,gpointer)30986 void on_nbases_button_sub_clicked(GtkToggleButton*, gpointer) {
30987 	nbases_insert_text(nbases_get_entry(), expression_sub_sign());
30988 }
on_nbases_button_times_clicked(GtkToggleButton *,gpointer)30989 void on_nbases_button_times_clicked(GtkToggleButton*, gpointer) {
30990 	nbases_insert_text(nbases_get_entry(), expression_times_sign());
30991 }
on_nbases_button_divide_clicked(GtkToggleButton *,gpointer)30992 void on_nbases_button_divide_clicked(GtkToggleButton*, gpointer) {
30993 	nbases_insert_text(nbases_get_entry(), expression_divide_sign());
30994 }
on_nbases_button_and_clicked(GtkToggleButton *,gpointer)30995 void on_nbases_button_and_clicked(GtkToggleButton*, gpointer) {
30996 	nbases_insert_text(nbases_get_entry(), "&");
30997 }
on_nbases_button_or_clicked(GtkToggleButton *,gpointer)30998 void on_nbases_button_or_clicked(GtkToggleButton*, gpointer) {
30999 	nbases_insert_text(nbases_get_entry(), "|");
31000 }
on_nbases_button_xor_clicked(GtkToggleButton *,gpointer)31001 void on_nbases_button_xor_clicked(GtkToggleButton*, gpointer) {
31002 	nbases_insert_text(nbases_get_entry(), " xor ");
31003 }
on_nbases_button_not_clicked(GtkToggleButton *,gpointer)31004 void on_nbases_button_not_clicked(GtkToggleButton*, gpointer) {
31005 	nbases_insert_text(nbases_get_entry(), "~");
31006 }
on_nbases_button_left_shift_clicked(GtkToggleButton *,gpointer)31007 void on_nbases_button_left_shift_clicked(GtkToggleButton*, gpointer) {
31008 	nbases_insert_text(nbases_get_entry(), "<<");
31009 }
on_nbases_button_right_shift_clicked(GtkToggleButton *,gpointer)31010 void on_nbases_button_right_shift_clicked(GtkToggleButton*, gpointer) {
31011 	nbases_insert_text(nbases_get_entry(), ">>");
31012 }
on_nbases_button_del_clicked(GtkToggleButton *,gpointer)31013 void on_nbases_button_del_clicked(GtkToggleButton*, gpointer) {
31014 	DO_CUSTOM_BUTTON_1(26)
31015 	gint i1, i2;
31016 	GtkWidget *w = nbases_get_entry();
31017 	if(!gtk_editable_get_selection_bounds(GTK_EDITABLE(w), &i1, &i2)) {
31018 		i1 = gtk_editable_get_position(GTK_EDITABLE(w));
31019 		i2 = i1 + 1;
31020 	}
31021 	string str = gtk_entry_get_text(GTK_ENTRY(w));
31022 	gtk_editable_delete_text(GTK_EDITABLE(w), i1, i2);
31023 	if(str == gtk_entry_get_text(GTK_ENTRY(w))) gtk_editable_delete_text(GTK_EDITABLE(w), i1 - 1, i2 - 1);
31024 	gtk_widget_grab_focus(w);
31025 	gtk_editable_select_region(GTK_EDITABLE(w), i1, i1);
31026 }
on_nbases_button_ac_clicked(GtkToggleButton *,gpointer)31027 void on_nbases_button_ac_clicked(GtkToggleButton*, gpointer) {
31028 	gtk_entry_set_text(GTK_ENTRY(nbases_get_entry()), "");
31029 	gtk_widget_grab_focus(nbases_get_entry());
31030 }
31031 
on_nbases_dialog_key_press_event(GtkWidget * o,GdkEventKey * event,gpointer)31032 gboolean on_nbases_dialog_key_press_event(GtkWidget *o, GdkEventKey *event, gpointer) {
31033 	if(b_busy) {
31034 		if(event->keyval == GDK_KEY_Escape) {
31035 			if(b_busy_expression) on_abort_calculation(NULL, 0, NULL);
31036 			else if(b_busy_result) on_abort_display(NULL, 0, NULL);
31037 			else if(b_busy_command) on_abort_command(NULL, 0, NULL);
31038 		}
31039 		return TRUE;
31040 	}
31041 	const gchar *key = key_press_get_symbol(event);
31042 	if(!key) return FALSE;
31043 	if(strlen(key) > 0) nbases_insert_text(nbases_get_entry(), key);
31044 	return TRUE;
31045 }
31046 
get_fp_bits()31047 unsigned int get_fp_bits() {
31048 	switch(gtk_combo_box_get_active(GTK_COMBO_BOX(gtk_builder_get_object(floatingpoint_builder, "fp_combo_bits")))) {
31049 		case 0: return 16;
31050 		case 1: return 32;
31051 		case 2: return 64;
31052 		case 3: return 80;
31053 		case 4: return 128;
31054 	}
31055 	return 32;
31056 }
31057 
update_fp_entries(string sbin,int base,Number * decnum=NULL)31058 void update_fp_entries(string sbin, int base, Number *decnum = NULL) {
31059 	unsigned int bits = get_fp_bits();
31060 	unsigned int expbits = standard_expbits(bits);
31061 	GtkWidget *w_dec, *w_hex, *w_float, *w_value, *w_error;
31062 	GtkTextBuffer *w_bin;
31063 	w_dec = GTK_WIDGET(gtk_builder_get_object(floatingpoint_builder, "fp_entry_dec"));
31064 	w_bin = GTK_TEXT_BUFFER(gtk_builder_get_object(floatingpoint_builder, "fp_buffer_bin"));
31065 	w_hex = GTK_WIDGET(gtk_builder_get_object(floatingpoint_builder, "fp_entry_hex"));
31066 	w_float = GTK_WIDGET(gtk_builder_get_object(floatingpoint_builder, "fp_entry_float"));
31067 	w_value = GTK_WIDGET(gtk_builder_get_object(floatingpoint_builder, "fp_entry_value"));
31068 	w_error = GTK_WIDGET(gtk_builder_get_object(floatingpoint_builder, "fp_entry_error"));
31069 	g_signal_handlers_block_matched((gpointer) w_dec, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_fp_entry_dec_changed, NULL);
31070 	g_signal_handlers_block_matched((gpointer) w_bin, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_fp_buffer_bin_changed, NULL);
31071 	g_signal_handlers_block_matched((gpointer) w_hex, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_fp_entry_hex_changed, NULL);
31072 	if(sbin.empty()) {
31073 		if(base != 10) gtk_entry_set_text(GTK_ENTRY(w_dec), "");
31074 		if(base != 16) gtk_entry_set_text(GTK_ENTRY(w_hex), "");
31075 		if(base != 2) gtk_text_buffer_set_text(w_bin, "", -1);
31076 		gtk_entry_set_text(GTK_ENTRY(w_float), "");
31077 		gtk_entry_set_text(GTK_ENTRY(w_value), "");
31078 		gtk_entry_set_text(GTK_ENTRY(w_error), "");
31079 	} else {
31080 		PrintOptions po;
31081 		po.number_fraction_format = FRACTION_DECIMAL;
31082 		po.interval_display = INTERVAL_DISPLAY_SIGNIFICANT_DIGITS;
31083 		po.use_unicode_signs = printops.use_unicode_signs;
31084 		po.lower_case_e = printops.lower_case_e;
31085 		po.lower_case_numbers = printops.lower_case_numbers;
31086 		po.base_display = BASE_DISPLAY_NONE;
31087 		po.abbreviate_names = printops.abbreviate_names;
31088 		po.digit_grouping = printops.digit_grouping;
31089 		po.multiplication_sign = printops.multiplication_sign;
31090 		po.division_sign = printops.division_sign;
31091 		po.short_multiplication = printops.short_multiplication;
31092 		po.excessive_parenthesis = printops.excessive_parenthesis;
31093 		po.can_display_unicode_string_function = &can_display_unicode_string_function;
31094 		po.can_display_unicode_string_arg = (void*) w_dec;
31095 		po.spell_out_logical_operators = printops.spell_out_logical_operators;
31096 		po.binary_bits = bits;
31097 		po.show_ending_zeroes = false;
31098 		po.min_exp = 0;
31099 		int prec_bak = CALCULATOR->getPrecision();
31100 		CALCULATOR->setPrecision(100);
31101 		ParseOptions pa;
31102 		pa.base = BASE_BINARY;
31103 		Number nr(sbin, pa);
31104 		if(base != 16) {po.base = 16; gtk_entry_set_text(GTK_ENTRY(w_hex), nr.print(po).c_str());}
31105 		if(base != 2) {
31106 			string str = sbin;
31107 			if(bits > 32) {
31108 				for(size_t i = expbits + 5; i < str.length() - 1; i += 4) {
31109 					if((bits == 80 && str.length() - i == 32) || (bits == 128 && (str.length() - i == 56))) str.insert(i, "\n");
31110 					else str.insert(i, " ");
31111 					i++;
31112 				}
31113 			}
31114 			str.insert(expbits + 1, bits > 32 ? "\n" : " ");
31115 			str.insert(1, " ");
31116 			gtk_text_buffer_set_text(w_bin, str.c_str(), -1);
31117 		}
31118 		if(printops.min_exp == -1 || printops.min_exp == 0) po.min_exp = 8;
31119 		else po.min_exp = printops.min_exp;
31120 		po.base = 10;
31121 		po.max_decimals = 50;
31122 		po.use_max_decimals = true;
31123 		Number value;
31124 		int ret = from_float(value, sbin, bits, expbits);
31125 		if(ret <= 0) {
31126 			gtk_entry_set_text(GTK_ENTRY(w_float), ret < 0 ? "NaN" : "");
31127 			gtk_entry_set_text(GTK_ENTRY(w_value), ret < 0 ? "NaN" : "");
31128 			gtk_entry_set_text(GTK_ENTRY(w_error), "");
31129 			if(base != 10) gtk_entry_set_text(GTK_ENTRY(w_dec), m_undefined.print(po).c_str());
31130 		} else {
31131 			if(sbin.length() < bits) sbin.insert(0, bits - sbin.length(), '0');
31132 			Number exponent, significand;
31133 			exponent.set(sbin.substr(1, expbits), pa);
31134 			Number expbias(2);
31135 			expbias ^= (expbits - 1);
31136 			expbias--;
31137 			bool subnormal = exponent.isZero();
31138 			exponent -= expbias;
31139 			string sfloat;
31140 			bool b_approx = false;
31141 			po.is_approximate = &b_approx;
31142 			if(exponent > expbias) {
31143 				if(sbin[0] != '0') sfloat = nr_minus_inf.print(po);
31144 				else sfloat = nr_plus_inf.print(po);
31145 			} else {
31146 				if(subnormal) exponent++;
31147 				if(subnormal) significand.set(string("0.") + sbin.substr(1 + expbits), pa);
31148 				else significand.set(string("1.") + sbin.substr(1 + expbits), pa);
31149 				if(sbin[0] != '0') significand.negate();
31150 				int exp_bak = po.min_exp;
31151 				po.min_exp = 0;
31152 				sfloat = significand.print(po);
31153 				if(!subnormal || !significand.isZero()) {
31154 					sfloat += " ";
31155 					sfloat += expression_times_sign();
31156 					sfloat += " ";
31157 					sfloat += "2^";
31158 					sfloat += exponent.print(po);
31159 				}
31160 				po.min_exp = exp_bak;
31161 				if(b_approx) sfloat.insert(0, SIGN_ALMOST_EQUAL " ");
31162 			}
31163 			gtk_entry_set_text(GTK_ENTRY(w_float), sfloat.c_str());
31164 			b_approx = false;
31165 			string svalue = value.print(po);
31166 			if(base != 10) gtk_entry_set_text(GTK_ENTRY(w_dec), svalue.c_str());
31167 			if(b_approx) svalue.insert(0, SIGN_ALMOST_EQUAL " ");
31168 			gtk_entry_set_text(GTK_ENTRY(w_value), svalue.c_str());
31169 			Number nr_error;
31170 			if(decnum && (!decnum->isInfinite() || !value.isInfinite())) {
31171 				nr_error = value;
31172 				nr_error -= *decnum;
31173 				nr_error.abs();
31174 				if(decnum->isApproximate() && prec_bak < CALCULATOR->getPrecision()) CALCULATOR->setPrecision(prec_bak);
31175 			}
31176 			b_approx = false;
31177 			string serror = nr_error.print(po);
31178 			if(b_approx) serror.insert(0, SIGN_ALMOST_EQUAL " ");
31179 			gtk_entry_set_text(GTK_ENTRY(w_error), serror.c_str());
31180 		}
31181 		CALCULATOR->setPrecision(prec_bak);
31182 	}
31183 	g_signal_handlers_unblock_matched((gpointer) w_dec, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_fp_entry_dec_changed, NULL);
31184 	g_signal_handlers_unblock_matched((gpointer) w_bin, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_fp_buffer_bin_changed, NULL);
31185 	g_signal_handlers_unblock_matched((gpointer) w_hex, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_fp_entry_hex_changed, NULL);
31186 }
on_fp_entry_dec_changed(GtkEditable * editable,gpointer)31187 void on_fp_entry_dec_changed(GtkEditable *editable, gpointer) {
31188 	if(changing_in_fp_dialog) return;
31189 	string str = gtk_entry_get_text(GTK_ENTRY(editable));
31190 	remove_blank_ends(str);
31191 	if(str.empty()) return;
31192 	if(last_is_operator(str, true)) return;
31193 	unsigned int bits = get_fp_bits();
31194 	unsigned int expbits = standard_expbits(bits);
31195 	changing_in_fp_dialog = true;
31196 	EvaluationOptions eo;
31197 	eo.parse_options = evalops.parse_options;
31198 	eo.parse_options.read_precision = DONT_READ_PRECISION;
31199 	if(eo.parse_options.parsing_mode == PARSING_MODE_RPN || eo.parse_options.parsing_mode == PARSING_MODE_CHAIN) eo.parse_options.parsing_mode = PARSING_MODE_ADAPTIVE;
31200 	eo.parse_options.base = 10;
31201 	MathStructure value;
31202 	do_timeout = false;
31203 	CALCULATOR->calculate(&value, CALCULATOR->unlocalizeExpression(gtk_entry_get_text(GTK_ENTRY(editable)), eo.parse_options), 1500, eo);
31204 	if(value.isNumber()) {
31205 		string sbin = to_float(value.number(), bits, expbits);
31206 		update_fp_entries(sbin, 10, &value.number());
31207 	} else if(value.isUndefined()) {
31208 		string sbin = to_float(nr_one_i, bits, expbits);
31209 		update_fp_entries(sbin, 10);
31210 	} else {
31211 		update_fp_entries("", 10);
31212 	}
31213 	changing_in_fp_dialog = false;
31214 	CALCULATOR->clearMessages();
31215 	do_timeout = true;
31216 }
on_fp_combo_bits_changed(GtkComboBox *,gpointer)31217 void on_fp_combo_bits_changed(GtkComboBox*, gpointer) {
31218 	on_fp_entry_dec_changed(GTK_EDITABLE(gtk_builder_get_object(floatingpoint_builder, "fp_entry_dec")), NULL);
31219 }
on_fp_buffer_bin_changed(GtkTextBuffer * w,gpointer)31220 void on_fp_buffer_bin_changed(GtkTextBuffer *w, gpointer) {
31221 	if(changing_in_fp_dialog) return;
31222 	GtkTextIter istart, iend;
31223 	gtk_text_buffer_get_start_iter(w, &istart);
31224 	gtk_text_buffer_get_end_iter(w, &iend);
31225 	gchar *gtext = gtk_text_buffer_get_text(w, &istart, &iend, FALSE);
31226 	string str = gtext;
31227 	g_free(gtext);
31228 	remove_blanks(str);
31229 	if(str.empty()) return;
31230 	changing_in_fp_dialog = true;
31231 	do_timeout = false;
31232 	unsigned int bits = get_fp_bits();
31233 	if(str.find_first_not_of("01") == string::npos && str.length() <= bits) {
31234 		update_fp_entries(str, 2);
31235 	} else {
31236 		update_fp_entries("", 2);
31237 	}
31238 	changing_in_fp_dialog = false;
31239 	CALCULATOR->clearMessages();
31240 	do_timeout = true;
31241 }
on_fp_entry_hex_changed(GtkEditable * editable,gpointer)31242 void on_fp_entry_hex_changed(GtkEditable *editable, gpointer) {
31243 	if(changing_in_fp_dialog) return;
31244 	string str = gtk_entry_get_text(GTK_ENTRY(editable));
31245 	remove_blanks(str);
31246 	if(str.empty()) return;
31247 	changing_in_fp_dialog = true;
31248 	unsigned int bits = get_fp_bits();
31249 	do_timeout = false;
31250 	ParseOptions pa;
31251 	pa.base = BASE_HEXADECIMAL;
31252 	Number nr(str, pa);
31253 	PrintOptions po;
31254 	po.base = BASE_BINARY;
31255 	po.binary_bits = bits;
31256 	po.max_decimals = 0;
31257 	po.use_max_decimals = true;
31258 	po.base_display = BASE_DISPLAY_NONE;
31259 	string sbin = nr.print(po);
31260 	if(sbin.length() < bits) sbin.insert(0, bits - sbin.length(), '0');
31261 	if(sbin.length() <= bits) {
31262 		update_fp_entries(sbin, 16);
31263 	} else {
31264 		update_fp_entries("", 16);
31265 	}
31266 	changing_in_fp_dialog = false;
31267 	CALCULATOR->clearMessages();
31268 	do_timeout = true;
31269 }
fp_insert_text(GtkWidget * w,const gchar * text)31270 void fp_insert_text(GtkWidget *w, const gchar *text) {
31271 	changing_in_fp_dialog = true;
31272 	gtk_editable_delete_selection(GTK_EDITABLE(w));
31273 	changing_in_fp_dialog = false;
31274 	gint pos = gtk_editable_get_position(GTK_EDITABLE(w));
31275 	gtk_editable_insert_text(GTK_EDITABLE(w), text, -1, &pos);
31276 	gtk_editable_set_position(GTK_EDITABLE(w), pos);
31277 	gtk_widget_grab_focus(w);
31278 	gtk_editable_select_region(GTK_EDITABLE(w), pos, pos);
31279 }
31280 
on_floatingpoint_dialog_key_press_event(GtkWidget * o,GdkEventKey * event,gpointer)31281 gboolean on_floatingpoint_dialog_key_press_event(GtkWidget *o, GdkEventKey *event, gpointer) {
31282 	if(b_busy) {
31283 		if(event->keyval == GDK_KEY_Escape) {
31284 			if(b_busy_expression) on_abort_calculation(NULL, 0, NULL);
31285 			else if(b_busy_result) on_abort_display(NULL, 0, NULL);
31286 			else if(b_busy_command) on_abort_command(NULL, 0, NULL);
31287 		}
31288 		return TRUE;
31289 	}
31290 	return FALSE;
31291 }
on_fp_entry_dec_key_press_event(GtkWidget * o,GdkEventKey * event,gpointer)31292 gboolean on_fp_entry_dec_key_press_event(GtkWidget *o, GdkEventKey *event, gpointer) {
31293 	const gchar *key = key_press_get_symbol(event);
31294 	if(!key) return FALSE;
31295 	if(strlen(key) > 0) fp_insert_text(o, key);
31296 	return TRUE;
31297 }
31298 
on_button_functions_clicked(GtkButton *,gpointer)31299 void on_button_functions_clicked(GtkButton*, gpointer) {
31300 	manage_functions();
31301 }
on_button_variables_clicked(GtkButton *,gpointer)31302 void on_button_variables_clicked(GtkButton*, gpointer) {
31303 	manage_variables();
31304 }
on_button_units_clicked(GtkButton *,gpointer)31305 void on_button_units_clicked(GtkButton*, gpointer) {
31306 	manage_units();
31307 }
on_button_bases_clicked(GtkButton *,gpointer)31308 void on_button_bases_clicked(GtkButton*, gpointer) {
31309 	on_menu_item_convert_number_bases_activate(NULL, NULL);
31310 }
on_button_convert_clicked(GtkButton *,gpointer user_data)31311 void on_button_convert_clicked(GtkButton*, gpointer user_data) {
31312 	on_menu_item_convert_to_unit_expression_activate(NULL, user_data);
31313 }
31314 
31315 
on_about_activate_link(GtkAboutDialog *,gchar * uri,gpointer)31316 gboolean on_about_activate_link(GtkAboutDialog*, gchar *uri, gpointer) {
31317 #ifdef _WIN32
31318 	ShellExecuteA(NULL, "open", uri, NULL, NULL, SW_SHOWNORMAL);
31319 	return TRUE;
31320 #else
31321 	return FALSE;
31322 #endif
31323 }
31324 
31325 
on_menu_item_check_updates_activate(GtkMenuItem *,gpointer)31326 void on_menu_item_check_updates_activate(GtkMenuItem*, gpointer) {
31327 	check_for_new_version(false);
31328 }
31329 
on_menu_item_about_activate(GtkMenuItem *,gpointer)31330 void on_menu_item_about_activate(GtkMenuItem*, gpointer) {
31331 	const gchar *authors[] = {"Hanna Knutsson", NULL};
31332 	GtkWidget *dialog = gtk_about_dialog_new();
31333 	gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG(dialog), authors);
31334 	gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(dialog), _("Powerful and easy to use calculator"));
31335 	gtk_about_dialog_set_license_type(GTK_ABOUT_DIALOG(dialog), GTK_LICENSE_GPL_2_0);
31336 	gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(dialog), "Copyright © 2003–2007, 2008, 2016-2020 Hanna Knutsson");
31337 	gtk_about_dialog_set_logo_icon_name(GTK_ABOUT_DIALOG(dialog), "qalculate");
31338 	gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(dialog), "Qalculate! (GTK+)");
31339 	gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(dialog), VERSION);
31340 	gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(dialog), "http://qalculate.github.io/");
31341 	gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(mainwindow));
31342 	g_signal_connect(G_OBJECT(dialog), "activate-link", G_CALLBACK(on_about_activate_link), NULL);
31343 	gtk_dialog_run(GTK_DIALOG(dialog));
31344 	gtk_widget_destroy(dialog);
31345 }
31346 
on_menu_item_reportbug_activate(GtkMenuItem *,gpointer)31347 void on_menu_item_reportbug_activate(GtkMenuItem*, gpointer) {
31348 #ifdef _WIN32
31349 	ShellExecuteA(NULL, "open", "https://github.com/Qalculate/qalculate-gtk/issues", NULL, NULL, SW_SHOWNORMAL);
31350 #else
31351 	GError *error = NULL;
31352 #	if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 22
31353 	gtk_show_uri_on_window(GTK_WINDOW(mainwindow), "https://github.com/Qalculate/qalculate-gtk/issues", gtk_get_current_event_time(), &error);
31354 #	else
31355 	gtk_show_uri(NULL, "https://github.com/Qalculate/qalculate-gtk/issues", gtk_get_current_event_time(), &error);
31356 #	endif
31357 	if(error) {
31358 		gchar *error_str = g_locale_to_utf8(error->message, -1, NULL, NULL, NULL);
31359 		GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(mainwindow), (GtkDialogFlags) 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("Failed to open %s.\n%s"), "https://github.com/Qalculate/qalculate-gtk/issues", error_str);
31360 		gtk_dialog_run(GTK_DIALOG(dialog));
31361 		gtk_widget_destroy(dialog);
31362 		g_free(error_str);
31363 		g_error_free(error);
31364 	}
31365 #endif
31366 }
31367 
on_menu_item_help_activate(GtkMenuItem *,gpointer)31368 void on_menu_item_help_activate(GtkMenuItem*, gpointer) {
31369 	show_help("index.html", gtk_builder_get_object(main_builder, "main_window"));
31370 }
31371 
31372 /*
31373 	precision has changed in precision dialog
31374 */
on_precision_dialog_spinbutton_precision_value_changed(GtkSpinButton * w,gpointer)31375 void on_precision_dialog_spinbutton_precision_value_changed(GtkSpinButton *w, gpointer) {
31376 	CALCULATOR->setPrecision(gtk_spin_button_get_value_as_int(w));
31377 }
on_precision_dialog_button_recalculate_clicked(GtkButton *,gpointer)31378 void on_precision_dialog_button_recalculate_clicked(GtkButton*, gpointer) {
31379 	CALCULATOR->setPrecision(gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_builder_get_object(precision_builder, "precision_dialog_spinbutton_precision"))));
31380 	execute_expression(true, false, OPERATION_ADD, NULL, rpn_mode);
31381 }
31382 
31383 
on_decimals_dialog_spinbutton_max_value_changed(GtkSpinButton * w,gpointer)31384 void on_decimals_dialog_spinbutton_max_value_changed(GtkSpinButton *w, gpointer) {
31385 	printops.max_decimals = gtk_spin_button_get_value_as_int(w);
31386 	result_format_updated();
31387 }
on_decimals_dialog_spinbutton_min_value_changed(GtkSpinButton * w,gpointer)31388 void on_decimals_dialog_spinbutton_min_value_changed(GtkSpinButton *w, gpointer) {
31389 	printops.min_decimals = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(w));
31390 	result_format_updated();
31391 }
on_decimals_dialog_checkbutton_max_toggled(GtkToggleButton * w,gpointer)31392 void on_decimals_dialog_checkbutton_max_toggled(GtkToggleButton *w, gpointer) {
31393 	printops.use_max_decimals = gtk_toggle_button_get_active(w);
31394 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(decimals_builder, "decimals_dialog_spinbutton_max")), printops.use_max_decimals);
31395 	result_format_updated();
31396 }
on_decimals_dialog_checkbutton_min_toggled(GtkToggleButton * w,gpointer)31397 void on_decimals_dialog_checkbutton_min_toggled(GtkToggleButton *w, gpointer) {
31398 	printops.use_min_decimals = gtk_toggle_button_get_active(w);
31399 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(decimals_builder, "decimals_dialog_spinbutton_min")), printops.use_min_decimals);
31400 	result_format_updated();
31401 }
31402 
on_unknown_edit_checkbutton_custom_assumptions_toggled(GtkToggleButton * w,gpointer)31403 void on_unknown_edit_checkbutton_custom_assumptions_toggled(GtkToggleButton *w, gpointer) {
31404 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unknownedit_builder, "unknown_edit_hbox_type")), gtk_toggle_button_get_active(w));
31405 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(unknownedit_builder, "unknown_edit_hbox_sign")), gtk_toggle_button_get_active(w));
31406 }
on_unknown_edit_combobox_type_changed(GtkComboBox * om,gpointer)31407 void on_unknown_edit_combobox_type_changed(GtkComboBox *om, gpointer) {
31408 	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) {
31409 		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);
31410 		gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(unknownedit_builder, "unknown_edit_combobox_sign")), ASSUMPTION_SIGN_UNKNOWN);
31411 		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);
31412 	}
31413 }
on_unknown_edit_combobox_sign_changed(GtkComboBox * om,gpointer)31414 void on_unknown_edit_combobox_sign_changed(GtkComboBox *om, gpointer) {
31415 	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) {
31416 		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);
31417 		gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(unknownedit_builder, "unknown_edit_combobox_type")), ASSUMPTION_TYPE_REAL - 2);
31418 		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);
31419 	}
31420 }
31421 
on_variables_dialog_key_press_event(GtkWidget * o,GdkEventKey * event,gpointer)31422 gboolean on_variables_dialog_key_press_event(GtkWidget *o, GdkEventKey *event, gpointer) {
31423 	if(gtk_widget_has_focus(GTK_WIDGET(tVariables)) && gdk_keyval_to_unicode(event->keyval) > 32) {
31424 		gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_entry_search")));
31425 	}
31426 	if(gtk_widget_has_focus(GTK_WIDGET(gtk_builder_get_object(variables_builder, "variables_entry_search")))) {
31427 		if(event->keyval == GDK_KEY_Escape) {
31428 			gtk_widget_hide(o);
31429 			return TRUE;
31430 		}
31431 		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) {
31432 			gtk_widget_grab_focus(GTK_WIDGET(tVariables));
31433 		}
31434 	}
31435 	return FALSE;
31436 }
on_functions_dialog_key_press_event(GtkWidget * o,GdkEventKey * event,gpointer)31437 gboolean on_functions_dialog_key_press_event(GtkWidget *o, GdkEventKey *event, gpointer) {
31438 	if(gtk_widget_has_focus(GTK_WIDGET(tFunctions)) && gdk_keyval_to_unicode(event->keyval) > 32) {
31439 		gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(functions_builder, "functions_entry_search")));
31440 	}
31441 	if(gtk_widget_has_focus(GTK_WIDGET(gtk_builder_get_object(functions_builder, "functions_entry_search")))) {
31442 		if(event->keyval == GDK_KEY_Escape) {
31443 			gtk_widget_hide(o);
31444 			return TRUE;
31445 		}
31446 		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) {
31447 			gtk_widget_grab_focus(GTK_WIDGET(tFunctions));
31448 		}
31449 	}
31450 	return FALSE;
31451 }
on_units_dialog_key_press_event(GtkWidget * o,GdkEventKey * event,gpointer)31452 gboolean on_units_dialog_key_press_event(GtkWidget *o, GdkEventKey *event, gpointer) {
31453 	if(gtk_widget_has_focus(GTK_WIDGET(tUnits)) && gdk_keyval_to_unicode(event->keyval) > 32) {
31454 		gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_entry_search")));
31455 	}
31456 	if(gtk_widget_has_focus(GTK_WIDGET(gtk_builder_get_object(units_builder, "units_entry_search")))) {
31457 		if(event->keyval == GDK_KEY_Escape) {
31458 			gtk_widget_hide(o);
31459 			return TRUE;
31460 		}
31461 		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) {
31462 			gtk_widget_grab_focus(GTK_WIDGET(tUnits));
31463 		}
31464 	}
31465 	return FALSE;
31466 }
on_units_convert_to_button_focus_out_event(GtkWidget *,GdkEvent *,gpointer)31467 gboolean on_units_convert_to_button_focus_out_event(GtkWidget*, GdkEvent*, gpointer) {
31468 	gtk_widget_hide(completion_window);
31469 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(units_builder, "units_convert_to_button")), FALSE);
31470 	return FALSE;
31471 }
on_units_convert_to_button_key_press_event(GtkWidget *,GdkEventKey * event,gpointer)31472 gboolean on_units_convert_to_button_key_press_event(GtkWidget*, GdkEventKey *event, gpointer) {
31473 	if(!gtk_widget_get_visible(units_convert_window)) return FALSE;
31474 	switch(event->keyval) {
31475 		case GDK_KEY_Escape: {
31476 			gtk_widget_hide(units_convert_window);
31477 			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(units_builder, "units_convert_to_button")), FALSE);
31478 			return TRUE;
31479 			break;
31480 		}
31481 		case GDK_KEY_KP_Enter: {}
31482 		case GDK_KEY_ISO_Enter: {}
31483 		case GDK_KEY_Return: {
31484 			GtkTreeIter iter;
31485 			if(gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(units_convert_view)), NULL, &iter)) {
31486 				GtkTreePath *path = gtk_tree_model_get_path(units_convert_filter, &iter);
31487 				on_units_convert_view_row_activated(GTK_TREE_VIEW(units_convert_view), path, NULL, NULL);
31488 				gtk_tree_path_free(path);
31489 				return TRUE;
31490 			}
31491 		}
31492 		case GDK_KEY_BackSpace: {}
31493 		case GDK_KEY_Delete: {
31494 			string str = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(units_builder, "units_convert_search")));
31495 			if(str.length() > 0) {
31496 				str = str.substr(0, str.length() - 1);
31497 				gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(units_builder, "units_convert_search")), str.c_str());
31498 			}
31499 			return TRUE;
31500 		}
31501 		case GDK_KEY_Down: {}
31502 		case GDK_KEY_End: {}
31503 		case GDK_KEY_Home: {}
31504 		case GDK_KEY_KP_Page_Up: {}
31505 		case GDK_KEY_Page_Up: {}
31506 		case GDK_KEY_KP_Page_Down: {}
31507 		case GDK_KEY_Page_Down: {}
31508 		case GDK_KEY_Up: {
31509 			GtkTreeIter iter;
31510 			GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(units_convert_view));
31511 			bool b = false;
31512 			if(event->keyval == GDK_KEY_Up) {
31513 				if(gtk_tree_selection_get_selected(selection, NULL, &iter)) {
31514 					if(gtk_tree_model_iter_previous(units_convert_filter, &iter)) b = true;
31515 					else gtk_tree_selection_unselect_all(selection);
31516 				} else {
31517 					gint rows = gtk_tree_model_iter_n_children(units_convert_filter, NULL);
31518 					if(rows > 0) {
31519 						GtkTreePath *path = gtk_tree_path_new_from_indices(rows - 1, -1);
31520 						gtk_tree_model_get_iter(units_convert_filter, &iter, path);
31521 						gtk_tree_path_free(path);
31522 						b = true;
31523 					}
31524 				}
31525 			} else if(event->keyval == GDK_KEY_Down) {
31526 				if(gtk_tree_selection_get_selected(selection, NULL, &iter)) {
31527 					if(gtk_tree_model_iter_next(units_convert_filter, &iter)) b = true;
31528 					else gtk_tree_selection_unselect_all(selection);
31529 				} else {
31530 					if(gtk_tree_model_get_iter_first(units_convert_filter, &iter)) b = true;
31531 				}
31532 			} else if(event->keyval == GDK_KEY_End) {
31533 				gint rows = gtk_tree_model_iter_n_children(units_convert_filter, NULL);
31534 				if(rows > 0) {
31535 					GtkTreePath *path = gtk_tree_path_new_from_indices(rows - 1, -1);
31536 					gtk_tree_model_get_iter(units_convert_filter, &iter, path);
31537 					gtk_tree_path_free(path);
31538 					b = true;
31539 				}
31540 			} else if(event->keyval == GDK_KEY_Home) {
31541 				if(gtk_tree_model_get_iter_first(units_convert_filter, &iter)) b = true;
31542 			} else if(event->keyval == GDK_KEY_KP_Page_Down || event->keyval == GDK_KEY_Page_Down) {
31543 				if(gtk_tree_selection_get_selected(selection, NULL, &iter)) {
31544 					b = true;
31545 					for(size_t i = 0; i < 20; i++) {
31546 						if(!gtk_tree_model_iter_next(units_convert_filter, &iter)) {
31547 							b = false;
31548 							gint rows = gtk_tree_model_iter_n_children(units_convert_filter, NULL);
31549 							if(rows > 0) {
31550 								GtkTreePath *path = gtk_tree_path_new_from_indices(rows - 1, -1);
31551 								gtk_tree_model_get_iter(units_convert_filter, &iter, path);
31552 								gtk_tree_path_free(path);
31553 								b = true;
31554 							}
31555 							break;
31556 						}
31557 					}
31558 				}
31559 			} else if(event->keyval == GDK_KEY_KP_Page_Up || event->keyval == GDK_KEY_Page_Up) {
31560 				if(gtk_tree_selection_get_selected(selection, NULL, &iter)) {
31561 					b = true;
31562 					for(size_t i = 0; i < 20; i++) {
31563 						if(!gtk_tree_model_iter_previous(units_convert_filter, &iter)) {
31564 							b = false;
31565 							if(gtk_tree_model_get_iter_first(units_convert_filter, &iter)) b = true;
31566 							break;
31567 						}
31568 					}
31569 				}
31570 			}
31571 			if(b) {
31572 				gtk_tree_view_set_hover_selection(GTK_TREE_VIEW(units_convert_view), FALSE);
31573 				units_convert_hover_blocked = true;
31574 				GtkTreePath *path = gtk_tree_model_get_path(units_convert_filter, &iter);
31575 				gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(units_convert_view), path, NULL, FALSE, 0.0, 0.0);
31576 				gtk_tree_selection_unselect_all(selection);
31577 				gtk_tree_selection_select_iter(selection, &iter);
31578 				gtk_tree_path_free(path);
31579 			}
31580 			return TRUE;
31581 		}
31582 	}
31583 	if(gdk_keyval_to_unicode(event->keyval) > 32) {
31584 		gchar buffer[10];
31585 		buffer[g_unichar_to_utf8(gdk_keyval_to_unicode(event->keyval), buffer)] = '\0';
31586 		string str = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(units_builder, "units_convert_search")));
31587 		str += buffer;
31588 		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(units_builder, "units_convert_search")), str.c_str());
31589 		return TRUE;
31590 	}
31591 	return FALSE;
31592 }
31593 
do_shortcut(int type,string value)31594 bool do_shortcut(int type, string value) {
31595 	switch(type) {
31596 		case SHORTCUT_TYPE_FUNCTION: {
31597 			insertButtonFunction(CALCULATOR->getActiveFunction(value));
31598 			return true;
31599 		}
31600 		case SHORTCUT_TYPE_FUNCTION_WITH_DIALOG: {
31601 			insert_function(CALCULATOR->getActiveFunction(value), mainwindow);
31602 			return true;
31603 		}
31604 		case SHORTCUT_TYPE_VARIABLE: {
31605 			insert_var(CALCULATOR->getActiveVariable(value));
31606 			return true;
31607 		}
31608 		case SHORTCUT_TYPE_UNIT: {
31609 			Unit *u = CALCULATOR->getActiveUnit(value);
31610 			if(u && CALCULATOR->stillHasUnit(u)) {
31611 				if(u->subtype() == SUBTYPE_COMPOSITE_UNIT) {
31612 					string str = ((CompositeUnit*) u)->print(true, printops.abbreviate_names, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) expressiontext);
31613 					if(printops.multiplication_sign == MULTIPLICATION_SIGN_DOT) gsub(saltdot, sdot, str);
31614 					insert_text(str.c_str());
31615 				} else {
31616 					insert_text(u->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, true, false, &can_display_unicode_string_function, (void*) expressiontext).name.c_str());
31617 				}
31618 			}
31619 			return true;
31620 		}
31621 		case SHORTCUT_TYPE_TEXT: {
31622 			insert_text(value.c_str());
31623 			return true;
31624 		}
31625 		case SHORTCUT_TYPE_DATE: {
31626 			on_menu_item_insert_date_activate(NULL, NULL);
31627 			return true;
31628 		}
31629 		case SHORTCUT_TYPE_VECTOR: {
31630 			on_menu_item_insert_vector_activate(NULL, NULL);
31631 			return true;
31632 		}
31633 		case SHORTCUT_TYPE_MATRIX: {
31634 			on_menu_item_insert_matrix_activate(NULL, NULL);
31635 			return true;
31636 		}
31637 		case SHORTCUT_TYPE_SMART_PARENTHESES: {
31638 			brace_wrap();
31639 			return true;
31640 		}
31641 		case SHORTCUT_TYPE_CONVERT: {
31642 			ParseOptions pa = evalops.parse_options; pa.base = 10;
31643 			executeCommand(COMMAND_CONVERT_STRING, true, CALCULATOR->unlocalizeExpression(value, pa));
31644 			return true;
31645 		}
31646 		case SHORTCUT_TYPE_CONVERT_ENTRY: {
31647 			on_menu_item_convert_to_unit_expression_activate(NULL, NULL);
31648 			return true;
31649 		}
31650 		case SHORTCUT_TYPE_OPTIMAL_UNIT: {
31651 			executeCommand(COMMAND_CONVERT_OPTIMAL);
31652 			return true;
31653 		}
31654 		case SHORTCUT_TYPE_BASE_UNITS: {
31655 			executeCommand(COMMAND_CONVERT_BASE);
31656 			return true;
31657 		}
31658 		case SHORTCUT_TYPE_OPTIMAL_PREFIX: {
31659 			result_prefix_changed(NULL);
31660 			return true;
31661 		}
31662 		case SHORTCUT_TYPE_TO_NUMBER_BASE: {
31663 			int save_base = printops.base;
31664 			Number save_nbase = CALCULATOR->customOutputBase();
31665 			to_base = 0;
31666 			to_bits = 0;
31667 			Number nbase;
31668 			base_from_string(value, printops.base, nbase);
31669 			CALCULATOR->setCustomOutputBase(nbase);
31670 			result_format_updated();
31671 			printops.base = save_base;
31672 			CALCULATOR->setCustomOutputBase(save_nbase);
31673 			return true;
31674 		}
31675 		case SHORTCUT_TYPE_FACTORIZE: {
31676 			executeCommand(COMMAND_FACTORIZE);
31677 			return true;
31678 		}
31679 		case SHORTCUT_TYPE_EXPAND: {
31680 			executeCommand(COMMAND_EXPAND);
31681 			return true;
31682 		}
31683 		case SHORTCUT_TYPE_PARTIAL_FRACTIONS: {
31684 			executeCommand(COMMAND_EXPAND_PARTIAL_FRACTIONS);
31685 			return true;
31686 		}
31687 		case SHORTCUT_TYPE_SET_UNKNOWNS: {
31688 			on_menu_item_set_unknowns_activate(NULL, NULL);
31689 			return true;
31690 		}
31691 		case SHORTCUT_TYPE_RPN_UP: {
31692 			if(!rpn_mode) return false;
31693 			on_button_registerup_clicked(NULL, NULL);
31694 			return true;
31695 		}
31696 		case SHORTCUT_TYPE_RPN_DOWN: {
31697 			if(!rpn_mode) return false;
31698 			on_button_registerdown_clicked(NULL, NULL);
31699 			return true;
31700 		}
31701 		case SHORTCUT_TYPE_RPN_SWAP: {
31702 			if(!rpn_mode) return false;
31703 			on_button_registerswap_clicked(NULL, NULL);
31704 			return true;
31705 		}
31706 		case SHORTCUT_TYPE_RPN_COPY: {
31707 			if(!rpn_mode) return false;
31708 			on_button_copyregister_clicked(NULL, NULL);
31709 			return true;
31710 		}
31711 		case SHORTCUT_TYPE_RPN_LASTX: {
31712 			if(!rpn_mode) return false;
31713 			on_button_lastx_clicked(NULL, NULL);
31714 			return true;
31715 		}
31716 		case SHORTCUT_TYPE_RPN_DELETE: {
31717 			if(!rpn_mode) return false;
31718 			on_button_deleteregister_clicked(NULL, NULL);
31719 			return true;
31720 		}
31721 		case SHORTCUT_TYPE_RPN_CLEAR: {
31722 			if(!rpn_mode) return false;
31723 			on_button_clearstack_clicked(NULL, NULL);
31724 			return true;
31725 		}
31726 		case SHORTCUT_TYPE_META_MODE: {
31727 			for(size_t i = 0; i < modes.size(); i++) {
31728 				if(equalsIgnoreCase(modes[i].name, value)) {
31729 					load_mode(modes[i]);
31730 					return true;
31731 				}
31732 			}
31733 			show_message(_("Mode not found."), mainwindow);
31734 			return true;
31735 		}
31736 		case SHORTCUT_TYPE_INPUT_BASE: {
31737 			Number nbase;
31738 			base_from_string(value, evalops.parse_options.base, nbase, true);
31739 			CALCULATOR->setCustomInputBase(nbase);
31740 			on_historyview_selection_changed(NULL, NULL);
31741 			update_keypad_bases();
31742 			expression_format_updated(true);
31743 			input_base_updated_from_menu();
31744 			return true;
31745 		}
31746 		case SHORTCUT_TYPE_OUTPUT_BASE: {
31747 			Number nbase; int base;
31748 			base_from_string(value, base, nbase);
31749 			CALCULATOR->setCustomOutputBase(nbase);
31750 			set_output_base_from_dialog(base);
31751 			output_base_updated_from_menu();
31752 			return true;
31753 		}
31754 		case SHORTCUT_TYPE_EXACT_MODE: {
31755 			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "button_exact")), !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "button_exact"))));
31756 			return true;
31757 		}
31758 		case SHORTCUT_TYPE_DEGREES: {
31759 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_degrees")), TRUE);
31760 			return true;
31761 		}
31762 		case SHORTCUT_TYPE_RADIANS: {
31763 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_radians")), TRUE);
31764 			return true;
31765 		}
31766 		case SHORTCUT_TYPE_GRADIANS: {
31767 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_gradians")), TRUE);
31768 			return true;
31769 		}
31770 		case SHORTCUT_TYPE_FRACTIONS: {
31771 			if(printops.number_fraction_format >= FRACTION_FRACTIONAL) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_fraction_decimal")), TRUE);
31772 			else gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_fraction_fraction")), TRUE);
31773 			return true;
31774 		}
31775 		case SHORTCUT_TYPE_MIXED_FRACTIONS: {
31776 			if(printops.number_fraction_format == FRACTION_COMBINED) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_fraction_decimal")), TRUE);
31777 			else gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_fraction_combined")), TRUE);
31778 			return true;
31779 		}
31780 		case SHORTCUT_TYPE_SCIENTIFIC_NOTATION: {
31781 			if(printops.min_exp == EXP_SCIENTIFIC) gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_numerical_display")), 0);
31782 			else gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_numerical_display")), 2);
31783 			return true;
31784 		}
31785 		case SHORTCUT_TYPE_SIMPLE_NOTATION: {
31786 			if(printops.min_exp == EXP_NONE) gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_numerical_display")), 0);
31787 			else gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(main_builder, "combobox_numerical_display")), 4);
31788 			return true;
31789 		}
31790 		case SHORTCUT_TYPE_RPN_MODE: {
31791 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_rpn_mode")), !rpn_mode);
31792 			return true;
31793 		}
31794 		case SHORTCUT_TYPE_AUTOCALC: {
31795 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_autocalc")), !auto_calculate);
31796 			return true;
31797 		}
31798 		case SHORTCUT_TYPE_PROGRAMMING: {
31799 			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "button_programmers_keypad")), ~visible_keypad & PROGRAMMING_KEYPAD);
31800 			if(visible_keypad & PROGRAMMING_KEYPAD) gtk_expander_set_expanded(GTK_EXPANDER(gtk_builder_get_object(main_builder, "expander_keypad")), true);
31801 			return true;
31802 		}
31803 		case SHORTCUT_TYPE_KEYPAD: {
31804 			//void on_expander_history_expanded(GObject *o, GParamSpec*, gpointer)
31805 			gtk_expander_set_expanded(GTK_EXPANDER(gtk_builder_get_object(main_builder, "expander_keypad")), !gtk_expander_get_expanded(GTK_EXPANDER(gtk_builder_get_object(main_builder, "expander_keypad"))));
31806 			return true;
31807 		}
31808 		case SHORTCUT_TYPE_HISTORY: {
31809 			gtk_expander_set_expanded(GTK_EXPANDER(gtk_builder_get_object(main_builder, "expander_history")), !gtk_expander_get_expanded(GTK_EXPANDER(gtk_builder_get_object(main_builder, "expander_history"))));
31810 			return true;
31811 		}
31812 		case SHORTCUT_TYPE_HISTORY_SEARCH: {
31813 			on_popup_menu_item_history_search_activate(NULL, NULL);
31814 			return true;
31815 		}
31816 		case SHORTCUT_TYPE_CONVERSION: {
31817 			gtk_expander_set_expanded(GTK_EXPANDER(gtk_builder_get_object(main_builder, "expander_convert")), !gtk_expander_get_expanded(GTK_EXPANDER(gtk_builder_get_object(main_builder, "expander_convert"))));
31818 			return true;
31819 		}
31820 		case SHORTCUT_TYPE_STACK: {
31821 			gtk_expander_set_expanded(GTK_EXPANDER(gtk_builder_get_object(main_builder, "expander_stack")), !gtk_expander_get_expanded(GTK_EXPANDER(gtk_builder_get_object(main_builder, "expander_stack"))));
31822 			return true;
31823 		}
31824 		case SHORTCUT_TYPE_MINIMAL: {
31825 			set_minimal_mode(!minimal_mode);
31826 			return true;
31827 		}
31828 		case SHORTCUT_TYPE_MANAGE_VARIABLES: {
31829 			on_menu_item_manage_variables_activate(NULL, NULL);
31830 			return true;
31831 		}
31832 		case SHORTCUT_TYPE_MANAGE_FUNCTIONS: {
31833 			on_menu_item_manage_functions_activate(NULL, NULL);
31834 			return true;
31835 		}
31836 		case SHORTCUT_TYPE_MANAGE_UNITS: {
31837 			on_menu_item_manage_units_activate(NULL, NULL);
31838 			return true;
31839 		}
31840 		case SHORTCUT_TYPE_MANAGE_DATA_SETS: {
31841 			on_menu_item_datasets_activate(NULL, NULL);
31842 			return true;
31843 		}
31844 		case SHORTCUT_TYPE_STORE: {
31845 			on_menu_item_save_activate(NULL, NULL);
31846 			return true;
31847 		}
31848 		case SHORTCUT_TYPE_MEMORY_CLEAR: {
31849 			memory_clear();
31850 			return true;
31851 		}
31852 		case SHORTCUT_TYPE_MEMORY_RECALL: {
31853 			memory_recall();
31854 			return true;
31855 		}
31856 		case SHORTCUT_TYPE_MEMORY_STORE: {
31857 			memory_store();
31858 			return true;
31859 		}
31860 		case SHORTCUT_TYPE_MEMORY_ADD: {
31861 			memory_add();
31862 			return true;
31863 		}
31864 		case SHORTCUT_TYPE_MEMORY_SUBTRACT: {
31865 			memory_subtract();
31866 			return true;
31867 		}
31868 		case SHORTCUT_TYPE_NEW_VARIABLE: {
31869 			on_menu_item_new_variable_activate(NULL, NULL);
31870 			return true;
31871 		}
31872 		case SHORTCUT_TYPE_NEW_FUNCTION: {
31873 			on_menu_item_new_function_simple_activate(NULL, NULL);
31874 			return true;
31875 		}
31876 		case SHORTCUT_TYPE_PLOT: {
31877 			on_menu_item_plot_functions_activate(NULL, NULL);
31878 			return true;
31879 		}
31880 		case SHORTCUT_TYPE_NUMBER_BASES: {
31881 			on_menu_item_convert_number_bases_activate(NULL, NULL);
31882 			return true;
31883 		}
31884 		case SHORTCUT_TYPE_FLOATING_POINT: {
31885 			on_menu_item_convert_floatingpoint_activate(NULL, NULL);
31886 			return true;
31887 		}
31888 		case SHORTCUT_TYPE_CALENDARS: {
31889 			on_menu_item_show_calendarconversion_dialog_activate(NULL, NULL);
31890 			return true;
31891 		}
31892 		case SHORTCUT_TYPE_PERCENTAGE_TOOL: {
31893 			on_menu_item_show_percentage_dialog_activate(NULL, NULL);
31894 			return true;
31895 		}
31896 		case SHORTCUT_TYPE_PERIODIC_TABLE: {
31897 			on_menu_item_periodic_table_activate(NULL, NULL);
31898 			return true;
31899 		}
31900 		case SHORTCUT_TYPE_UPDATE_EXRATES: {
31901 			on_menu_item_fetch_exchange_rates_activate(NULL, NULL);
31902 			return true;
31903 		}
31904 		case SHORTCUT_TYPE_COPY_RESULT: {
31905 			on_menu_item_copy_activate(NULL, NULL);
31906 			return true;
31907 		}
31908 		case SHORTCUT_TYPE_SAVE_IMAGE: {
31909 			on_menu_item_save_image_activate(NULL, NULL);
31910 			return true;
31911 		}
31912 		case SHORTCUT_TYPE_HELP: {
31913 			on_menu_item_help_activate(NULL, NULL);
31914 			return true;
31915 		}
31916 		case SHORTCUT_TYPE_QUIT: {
31917 			on_menu_item_quit_activate(NULL, NULL);
31918 			return true;
31919 		}
31920 		case SHORTCUT_TYPE_CHAIN_MODE: {
31921 			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(main_builder, "menu_item_chain_mode")), !chain_mode);
31922 			return true;
31923 		}
31924 	}
31925 	return false;
31926 }
do_keyboard_shortcut(GdkEventKey * event)31927 bool do_keyboard_shortcut(GdkEventKey *event) {
31928 #if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 18
31929 	guint state = event->state & gdk_keymap_get_modifier_mask(gdk_keymap_get_for_display(gtk_widget_get_display(mainwindow)), GDK_MODIFIER_INTENT_DEFAULT_MOD_MASK);
31930 #else
31931 	guint state = event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK | GDK_MOD1_MASK | GDK_SUPER_MASK | GDK_HYPER_MASK | GDK_META_MASK);
31932 #endif
31933 	unordered_map<guint64, keyboard_shortcut>::iterator it = keyboard_shortcuts.find((guint64) event->keyval + (guint64) G_MAXUINT32 * (guint64) state);
31934 	if(it == keyboard_shortcuts.end() && event->keyval == GDK_KEY_KP_Delete) it = keyboard_shortcuts.find((guint64) GDK_KEY_Delete + (guint64) G_MAXUINT32 * (guint64) state);
31935 	if(it != keyboard_shortcuts.end()) {
31936 		return do_shortcut(it->second.type, it->second.value);
31937 	}
31938 	return false;
31939 }
31940 
on_configure_event(GtkWidget *,GdkEventConfigure * event,gpointer)31941 gboolean on_configure_event(GtkWidget*, GdkEventConfigure *event, gpointer) {
31942 	if(minimal_mode) {
31943 		if(minimal_window_resized_timeout_id) g_source_remove(minimal_window_resized_timeout_id);
31944 		minimal_window_resized_timeout_id = g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE, 1000, minimal_window_resized_timeout, NULL, NULL);
31945 	}
31946 	return FALSE;
31947 }
31948 
on_resultspinner_button_press_event(GtkWidget * w,GdkEventButton * event,gpointer)31949 gboolean on_resultspinner_button_press_event(GtkWidget *w, GdkEventButton *event, gpointer) {
31950 	if(event->button != 1 || !gtk_widget_is_visible(w)) return FALSE;
31951 	if(b_busy_command) on_abort_command(NULL, 0, NULL);
31952 	else if(b_busy_expression) on_abort_calculation(NULL, 0, NULL);
31953 	else if(b_busy_result) on_abort_display(NULL, 0, NULL);
31954 	return TRUE;
31955 }
31956 
31957 bool disable_history_arrow_keys = false;
31958 string current_history_expression;
on_key_release_event(GtkWidget *,GdkEventKey *,gpointer)31959 gboolean on_key_release_event(GtkWidget*, GdkEventKey*, gpointer) {
31960 	disable_history_arrow_keys = false;
31961 	return FALSE;
31962 }
on_key_press_event(GtkWidget * o,GdkEventKey * event,gpointer)31963 gboolean on_key_press_event(GtkWidget *o, GdkEventKey *event, gpointer) {
31964 	if(block_input && (event->keyval == GDK_KEY_q || event->keyval == GDK_KEY_Q) && !(event->state & GDK_CONTROL_MASK)) {block_input = false; return TRUE;}
31965 	if(gtk_widget_has_focus(expressiontext) || b_editing_stack) return FALSE;
31966 	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")));}
31967 	if(do_keyboard_shortcut(event)) return TRUE;
31968 	if(gtk_widget_has_focus(GTK_WIDGET(gtk_builder_get_object(main_builder, "convert_entry_unit")))) {
31969 		return FALSE;
31970 	}
31971 	if(gtk_widget_has_focus(GTK_WIDGET(gtk_builder_get_object(main_builder, "convert_entry_search")))) {
31972 		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) {
31973 			gtk_widget_grab_focus(GTK_WIDGET(tUnitSelector));
31974 		}
31975 		return FALSE;
31976 	}
31977 	if(gtk_widget_has_focus(GTK_WIDGET(gtk_builder_get_object(main_builder, "convert_treeview_unit")))) {
31978 		if(!(event->keyval >= GDK_KEY_KP_Multiply && event->keyval <= GDK_KEY_KP_9) && !(event->keyval >= GDK_KEY_parenleft && event->keyval <= GDK_KEY_A)) {
31979 			if(gdk_keyval_to_unicode(event->keyval) > 32) {
31980 				if(!gtk_widget_has_focus(GTK_WIDGET(gtk_builder_get_object(main_builder, "convert_entry_search")))) {
31981 					gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(main_builder, "convert_entry_search")));
31982 				}
31983 			}
31984 			return FALSE;
31985 		}
31986 	}
31987 	if(gtk_widget_has_focus(GTK_WIDGET(gtk_builder_get_object(main_builder, "convert_treeview_category")))) {
31988 		if(!(event->keyval >= GDK_KEY_KP_Multiply && event->keyval <= GDK_KEY_KP_9) && !(event->keyval >= GDK_KEY_parenleft && event->keyval <= GDK_KEY_A)) {
31989 			return FALSE;
31990 		}
31991 	}
31992 	if(event->keyval > GDK_KEY_Hyper_R || event->keyval < GDK_KEY_Shift_L) {
31993 		GtkWidget *w = gtk_window_get_focus(GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")));
31994 		if(gtk_bindings_activate_event(G_OBJECT(o), event)) return TRUE;
31995 		if(w && gtk_bindings_activate_event(G_OBJECT(w), event)) return TRUE;
31996 		focus_keeping_selection();
31997 	}
31998 	return FALSE;
31999 }
32000 
on_expressiontext_focus_out_event(GtkWidget *,GdkEvent *,gpointer)32001 gboolean on_expressiontext_focus_out_event(GtkWidget*, GdkEvent*, gpointer) {
32002 	gtk_widget_hide(completion_window);
32003 	return FALSE;
32004 }
on_expressiontext_key_press_event(GtkWidget *,GdkEventKey * event,gpointer)32005 gboolean on_expressiontext_key_press_event(GtkWidget*, GdkEventKey *event, gpointer) {
32006 	if(block_input && (event->keyval == GDK_KEY_q || event->keyval == GDK_KEY_Q) && !(event->state & GDK_CONTROL_MASK)) {block_input = false;
32007 return TRUE;}
32008 	if(b_busy) {
32009 		if(event->keyval == GDK_KEY_Escape) {
32010 			if(b_busy_expression) on_abort_calculation(NULL, 0, NULL);
32011 			else if(b_busy_result) on_abort_display(NULL, 0, NULL);
32012 			else if(b_busy_command) on_abort_command(NULL, 0, NULL);
32013 		}
32014 		return TRUE;
32015 	}
32016 	if(do_keyboard_shortcut(event)) return TRUE;
32017 	if(rpn_mode && event->state & GDK_CONTROL_MASK) {
32018 		switch(event->keyval) {
32019 			case GDK_KEY_Up: {
32020 				on_button_registerup_clicked(NULL, NULL);
32021 				return TRUE;
32022 			}
32023 			case GDK_KEY_Down: {
32024 				on_button_registerdown_clicked(NULL, NULL);
32025 				return TRUE;
32026 			}
32027 			case GDK_KEY_Right: {
32028 				on_button_registerswap_clicked(NULL, NULL);
32029 				return TRUE;
32030 			}
32031 			case GDK_KEY_Left: {
32032 				on_button_lastx_clicked(NULL, NULL);
32033 				return TRUE;
32034 			}
32035 			case GDK_KEY_Delete: {}
32036 			case GDK_KEY_KP_Delete: {
32037 				if(event->state & GDK_SHIFT_MASK) {
32038 					on_button_clearstack_clicked(NULL, NULL);
32039 				} else {
32040 					on_button_deleteregister_clicked(NULL, NULL);
32041 				}
32042 				return TRUE;
32043 			}
32044 			case GDK_KEY_C: {
32045 				if(event->state & GDK_SHIFT_MASK) {
32046 					on_button_copyregister_clicked(NULL, NULL);
32047 					return TRUE;
32048 				}
32049 				break;
32050 			}
32051 			case GDK_KEY_S: {
32052 				if(event->state & GDK_SHIFT_MASK) {
32053 					on_button_registerswap_clicked(NULL, NULL);
32054 					return TRUE;
32055 				}
32056 				break;
32057 			}
32058 			case GDK_KEY_L: {
32059 				if(event->state & GDK_SHIFT_MASK) {
32060 					on_button_lastx_clicked(NULL, NULL);
32061 					return TRUE;
32062 				}
32063 				break;
32064 			}
32065 			default: {}
32066 		}
32067 	}
32068 	switch(event->keyval) {
32069 		case GDK_KEY_Escape: {
32070 			if(gtk_widget_get_visible(completion_window)) {
32071 				gtk_widget_hide(completion_window);
32072 				return TRUE;
32073 			} else {
32074 				clear_expression_text();
32075 				return TRUE;
32076 			}
32077 			break;
32078 		}
32079 		case GDK_KEY_KP_Enter: {}
32080 		case GDK_KEY_ISO_Enter: {}
32081 		case GDK_KEY_Return: {
32082 			if(gtk_widget_get_visible(completion_window)) {
32083 				GtkTreeIter iter;
32084 				if(gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(completion_view)), NULL, &iter)) {
32085 					GtkTreePath *path = gtk_tree_model_get_path(completion_sort, &iter);
32086 					on_completion_match_selected(GTK_TREE_VIEW(completion_view), path, NULL, NULL);
32087 					gtk_tree_path_free(path);
32088 					return TRUE;
32089 				}
32090 			}
32091 			execute_expression();
32092 			return TRUE;
32093 		}
32094 		case GDK_KEY_dead_circumflex: {
32095 #ifdef _WIN32
32096 			// fix dead key
32097 			block_input = true;
32098 			INPUT ip; ip.type = INPUT_KEYBOARD; ip.ki.wScan = 0; ip.ki.time = 0; ip.ki.dwExtraInfo = 0;
32099 			ip.ki.wVk = 0x51; ip.ki.dwFlags = 0; SendInput(1, &ip, sizeof(INPUT));
32100 			ip.ki.dwFlags = KEYEVENTF_KEYUP; SendInput(1, &ip, sizeof(INPUT));
32101 #endif
32102 		}
32103 		case GDK_KEY_asciicircum: {
32104 			bool input_xor = (caret_as_xor != ((event->state & GDK_CONTROL_MASK) > 0));
32105 			if(rpn_mode && rpn_keys) {
32106 				calculateRPN(input_xor ? OPERATION_BITWISE_XOR : OPERATION_RAISE);
32107 				return TRUE;
32108 			}
32109 			if(evalops.parse_options.parsing_mode != PARSING_MODE_RPN) {
32110 				if(do_chain_mode(input_xor ? " xor " : "^")) return TRUE;
32111 				wrap_expression_selection();
32112 			}
32113 			overwrite_expression_selection(input_xor ? " xor " : "^");
32114 			return TRUE;
32115 		}
32116 		case GDK_KEY_slash: {}
32117 		case GDK_KEY_KP_Divide: {
32118 			if(event->state & GDK_CONTROL_MASK) {
32119 				overwrite_expression_selection("/");
32120 				return TRUE;
32121 			}
32122 			if(rpn_mode && rpn_keys) {
32123 				calculateRPN(OPERATION_DIVIDE);
32124 				return TRUE;
32125 			}
32126 			if(evalops.parse_options.parsing_mode != PARSING_MODE_RPN) {
32127 				if(do_chain_mode(expression_divide_sign())) return TRUE;
32128 				wrap_expression_selection();
32129 			}
32130 			overwrite_expression_selection(expression_divide_sign());
32131 			return TRUE;
32132 		}
32133 		case GDK_KEY_plus: {}
32134 		case GDK_KEY_KP_Add: {
32135 			if(rpn_mode && rpn_keys) {
32136 				calculateRPN(OPERATION_ADD);
32137 				return TRUE;
32138 			}
32139 			if(evalops.parse_options.parsing_mode != PARSING_MODE_RPN) {
32140 				if(do_chain_mode(expression_add_sign())) return TRUE;
32141 				wrap_expression_selection();
32142 			}
32143 			overwrite_expression_selection(expression_add_sign());
32144 			return TRUE;
32145 		}
32146 		case GDK_KEY_minus: {}
32147 		case GDK_KEY_KP_Subtract: {
32148 			if(rpn_mode && event->state & GDK_CONTROL_MASK) {
32149 				insertButtonFunction(CALCULATOR->getActiveFunction("neg"));
32150 				return TRUE;
32151 			}
32152 			if(rpn_mode && rpn_keys) {
32153 				calculateRPN(OPERATION_SUBTRACT);
32154 				return TRUE;
32155 			}
32156 			if(evalops.parse_options.parsing_mode != PARSING_MODE_RPN) {
32157 				if(do_chain_mode(expression_sub_sign())) return TRUE;
32158 				wrap_expression_selection();
32159 			}
32160 			overwrite_expression_selection(expression_sub_sign());
32161 			return TRUE;
32162 		}
32163 		case GDK_KEY_KP_Multiply: {}
32164 		case GDK_KEY_asterisk: {
32165 			if(event->state & GDK_CONTROL_MASK) {
32166 				if(rpn_mode && rpn_keys) {
32167 					calculateRPN(OPERATION_RAISE);
32168 					return TRUE;
32169 				}
32170 				if(evalops.parse_options.parsing_mode != PARSING_MODE_RPN) {
32171 					if(do_chain_mode("^")) return TRUE;
32172 					wrap_expression_selection();
32173 				}
32174 				overwrite_expression_selection("^");
32175 				return TRUE;
32176 			}
32177 			if(rpn_mode && rpn_keys) {
32178 				calculateRPN(OPERATION_MULTIPLY);
32179 				return TRUE;
32180 			}
32181 			if(evalops.parse_options.parsing_mode != PARSING_MODE_RPN) {
32182 				if(do_chain_mode(expression_times_sign())) return TRUE;
32183 				wrap_expression_selection();
32184 			}
32185 			overwrite_expression_selection(expression_times_sign());
32186 			return TRUE;
32187 		}
32188 		case GDK_KEY_E: {
32189 			if(event->state & GDK_CONTROL_MASK) {
32190 				if(rpn_mode && rpn_keys) {
32191 					calculateRPN(OPERATION_EXP10);
32192 					return TRUE;
32193 				}
32194 				if((evalops.parse_options.parsing_mode != PARSING_MODE_RPN && wrap_expression_selection() > 0) || (evalops.parse_options.base != 10 && evalops.parse_options.base >= 2)) {
32195 					insert_text((expression_times_sign() + i2s(evalops.parse_options.base) + "^").c_str());
32196 				} else {
32197 					if(printops.lower_case_e) insert_text("e");
32198 					else insert_text("E");
32199 				}
32200 				return TRUE;
32201 			}
32202 			break;
32203 		}
32204 		case GDK_KEY_A: {
32205 			if(event->state & GDK_CONTROL_MASK) {
32206 				insert_angle_symbol();
32207 				return TRUE;
32208 			}
32209 			break;
32210 		}
32211 		case GDK_KEY_End: {
32212 			GtkTextIter iend;
32213 			gtk_text_buffer_get_end_iter(expressionbuffer, &iend);
32214 			if(event->state & GDK_SHIFT_MASK) {
32215 				GtkTextIter iselstart, iselend, ipos;
32216 				GtkTextMark *mark = gtk_text_buffer_get_insert(expressionbuffer);
32217 				if(mark) gtk_text_buffer_get_iter_at_mark(expressionbuffer, &ipos, mark);
32218 				if(!gtk_text_buffer_get_selection_bounds(expressionbuffer, &iselstart, &iselend)) gtk_text_buffer_select_range(expressionbuffer, &iend, &ipos);
32219 				else if(gtk_text_iter_equal(&iselstart, &ipos)) gtk_text_buffer_select_range(expressionbuffer, &iend, &iselend);
32220 				else gtk_text_buffer_select_range(expressionbuffer, &iend, &iselstart);
32221 			} else {
32222 				gtk_text_buffer_place_cursor(expressionbuffer, &iend);
32223 			}
32224 			return TRUE;
32225 		}
32226 		case GDK_KEY_Home: {
32227 			GtkTextIter istart;
32228 			gtk_text_buffer_get_start_iter(expressionbuffer, &istart);
32229 			if(event->state & GDK_SHIFT_MASK) {
32230 				GtkTextIter iselstart, iselend, ipos;
32231 				GtkTextMark *mark = gtk_text_buffer_get_insert(expressionbuffer);
32232 				if(mark) gtk_text_buffer_get_iter_at_mark(expressionbuffer, &ipos, mark);
32233 				if(!gtk_text_buffer_get_selection_bounds(expressionbuffer, &iselstart, &iselend)) gtk_text_buffer_select_range(expressionbuffer, &istart, &ipos);
32234 				else if(gtk_text_iter_equal(&iselend, &ipos)) gtk_text_buffer_select_range(expressionbuffer, &istart, &iselstart);
32235 				else gtk_text_buffer_select_range(expressionbuffer, &istart, &iselend);
32236 			} else {
32237 				gtk_text_buffer_place_cursor(expressionbuffer, &istart);
32238 			}
32239 			return TRUE;
32240 		}
32241 		case GDK_KEY_Up: {
32242 			if(gtk_widget_get_visible(completion_window)) {
32243 				GtkTreeIter iter;
32244 				GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(completion_view));
32245 				bool b = false;
32246 				if(gtk_tree_selection_get_selected(selection, NULL, &iter)) {
32247 					if(gtk_tree_model_iter_previous(completion_sort, &iter)) {
32248 						gint i_prio = 0;
32249 						gtk_tree_model_get(GTK_TREE_MODEL(completion_sort), &iter, 4, &i_prio, -1);
32250 						if(i_prio != 3 || gtk_tree_model_iter_previous(completion_sort, &iter)) b = true;
32251 					} else {
32252 						gtk_tree_selection_unselect_all(selection);
32253 					}
32254 				} else {
32255 					gint rows = gtk_tree_model_iter_n_children(completion_sort, NULL);
32256 					if(rows > 0) {
32257 						GtkTreePath *path = gtk_tree_path_new_from_indices(rows - 1, -1);
32258 						gtk_tree_model_get_iter(completion_sort, &iter, path);
32259 						gtk_tree_path_free(path);
32260 						b = true;
32261 					}
32262 				}
32263 				if(b) {
32264 					gtk_tree_view_set_hover_selection(GTK_TREE_VIEW(completion_view), FALSE);
32265 					completion_hover_blocked = true;
32266 					GtkTreePath *path = gtk_tree_model_get_path(completion_sort, &iter);
32267 					gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(completion_view), path, NULL, FALSE, 0.0, 0.0);
32268 					gtk_tree_selection_select_iter(selection, &iter);
32269 					gtk_tree_path_free(path);
32270 				}
32271 				return TRUE;
32272 			}
32273 			if(disable_history_arrow_keys || event->state & GDK_SHIFT_MASK || event->state & GDK_CONTROL_MASK) break;
32274 			GtkTextIter ipos;
32275 			GtkTextMark *mark = gtk_text_buffer_get_insert(expressionbuffer);
32276 			if(mark) {
32277 				gtk_text_buffer_get_iter_at_mark(expressionbuffer, &ipos, mark);
32278 				if((cursor_has_moved && (!gtk_text_iter_is_start(&ipos) || gtk_text_buffer_get_has_selection(expressionbuffer))) || (!gtk_text_iter_is_end(&ipos) && !gtk_text_iter_is_start(&ipos)) || gtk_text_view_backward_display_line(GTK_TEXT_VIEW(expressiontext), &ipos)) {
32279 					disable_history_arrow_keys = true;
32280 					break;
32281 				}
32282 			}
32283 		}
32284 		case GDK_KEY_KP_Page_Up: {}
32285 		case GDK_KEY_Page_Up: {
32286 			if(expression_history_index + 1 < (int) expression_history.size()) {
32287 				if(expression_history_index == -1) current_history_expression = get_expression_text();
32288 				expression_history_index++;
32289 				dont_change_index = true;
32290 				block_completion();
32291 				if(expression_history_index == -1 && current_history_expression == get_expression_text()) expression_history_index = 0;
32292 				if(expression_history_index == -1) set_expression_text(current_history_expression.c_str());
32293 				else set_expression_text(expression_history[expression_history_index].c_str());
32294 				unblock_completion();
32295 				dont_change_index = false;
32296 			} else {
32297 				break;
32298 			}
32299 			if(event->keyval == GDK_KEY_Up) cursor_has_moved = false;
32300 			return TRUE;
32301 		}
32302 		case GDK_KEY_Down: {
32303 			if(gtk_widget_get_visible(completion_window)) {
32304 				GtkTreeIter iter;
32305 				GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(completion_view));
32306 				bool b = false;
32307 				if(gtk_tree_selection_get_selected(selection, NULL, &iter)) {
32308 					if(gtk_tree_model_iter_next(completion_sort, &iter)) {
32309 						gint i_prio = 0;
32310 						gtk_tree_model_get(GTK_TREE_MODEL(completion_sort), &iter, 4, &i_prio, -1);
32311 						if(i_prio != 3 || gtk_tree_model_iter_next(completion_sort, &iter)) b = true;
32312 					} else {
32313 						gtk_tree_selection_unselect_all(selection);
32314 					}
32315 				} else {
32316 					if(gtk_tree_model_get_iter_first(completion_sort, &iter)) b = true;
32317 				}
32318 				if(b) {
32319 					gtk_tree_view_set_hover_selection(GTK_TREE_VIEW(completion_view), FALSE);
32320 					completion_hover_blocked = true;
32321 					GtkTreePath *path = gtk_tree_model_get_path(completion_sort, &iter);
32322 					gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(completion_view), path, NULL, FALSE, 0.0, 0.0);
32323 					gtk_tree_selection_select_iter(selection, &iter);
32324 					gtk_tree_path_free(path);
32325 				}
32326 				return TRUE;
32327 			}
32328 			if(disable_history_arrow_keys || event->state & GDK_SHIFT_MASK || event->state & GDK_CONTROL_MASK) break;
32329 			GtkTextIter ipos;
32330 			GtkTextMark *mark = gtk_text_buffer_get_insert(expressionbuffer);
32331 			if(mark) {
32332 				gtk_text_buffer_get_iter_at_mark(expressionbuffer, &ipos, mark);
32333 				if((cursor_has_moved && (!gtk_text_iter_is_end(&ipos) || gtk_text_buffer_get_has_selection(expressionbuffer))) || (!gtk_text_iter_is_end(&ipos) && !gtk_text_iter_is_start(&ipos)) || gtk_text_view_forward_display_line(GTK_TEXT_VIEW(expressiontext), &ipos)) {
32334 					disable_history_arrow_keys = true;
32335 					break;
32336 				}
32337 			}
32338 		}
32339 		case GDK_KEY_KP_Page_Down: {}
32340 		case GDK_KEY_Page_Down: {
32341 			if(expression_history_index == -1) current_history_expression = get_expression_text();
32342 			if(expression_history_index >= -1) expression_history_index--;
32343 			dont_change_index = true;
32344 			block_completion();
32345 			if(expression_history_index < 0) {
32346 				if(expression_history_index == -1 && current_history_expression != get_expression_text()) set_expression_text(current_history_expression.c_str());
32347 				else clear_expression_text();
32348 			} else {
32349 				set_expression_text(expression_history[expression_history_index].c_str());
32350 			}
32351 			unblock_completion();
32352 			dont_change_index = false;
32353 			if(event->keyval == GDK_KEY_Down) cursor_has_moved = false;
32354 			return TRUE;
32355 		}
32356 		case GDK_KEY_KP_Separator: {
32357 			overwrite_expression_selection(CALCULATOR->getDecimalPoint().c_str());
32358 			return TRUE;
32359 		}
32360 		case GDK_KEY_braceleft: {}
32361 		case GDK_KEY_braceright: {
32362 			return TRUE;
32363 		}
32364 	}
32365 	if(event->state & GDK_CONTROL_MASK && (event->keyval == GDK_KEY_z || event->keyval == GDK_KEY_Z)) {
32366 		if(event->state & GDK_SHIFT_MASK || event->keyval == GDK_KEY_Z) expression_redo();
32367 		else expression_undo();
32368 		return TRUE;
32369 	}
32370 	return FALSE;
32371 }
on_resultview_draw(GtkWidget * widget,cairo_t * cr,gpointer)32372 gboolean on_resultview_draw(GtkWidget *widget, cairo_t *cr, gpointer) {
32373 	if(exit_in_progress) return TRUE;
32374 	gint scalefactor = gtk_widget_get_scale_factor(widget);
32375 	gtk_render_background(gtk_widget_get_style_context(widget), cr, 0, 0, gtk_widget_get_allocated_width(widget), gtk_widget_get_allocated_height(widget));
32376 	if(surface_result) {
32377 		gint w = 0, h = 0;
32378 		if(!first_draw_of_result) {
32379 			if(b_busy) {
32380 				if(b_busy_result) return TRUE;
32381 			} else if(display_aborted || (!displayed_mstruct && result_too_long)) {
32382 				PangoLayout *layout = gtk_widget_create_pango_layout(widget, NULL);
32383 				pango_layout_set_markup(layout, display_aborted ? _("result processing was aborted") : _("result is too long\nsee history"), -1);
32384 				pango_layout_get_pixel_size(layout, &w, &h);
32385 				PangoRectangle rect;
32386 				pango_layout_get_pixel_extents(layout, &rect, NULL);
32387 				if(rect.x < 0) {w -= rect.x; if(rect.width > w) w = rect.width;}
32388 				else if(w < rect.x + rect.width) w = rect.x + rect.width;
32389 				cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
32390 				cairo_surface_set_device_scale(s, scalefactor, scalefactor);
32391 				cairo_t *cr2 = cairo_create(s);
32392 				GdkRGBA rgba;
32393 				gtk_style_context_get_color(gtk_widget_get_style_context(widget), gtk_widget_get_state_flags(widget), &rgba);
32394 				gdk_cairo_set_source_rgba(cr2, &rgba);
32395 				if(rect.x < 0) cairo_move_to(cr, -rect.x, 0);
32396 				pango_cairo_show_layout(cr2, layout);
32397 				cairo_destroy(cr2);
32398 				cairo_surface_destroy(surface_result);
32399 				surface_result = s;
32400 				tmp_surface = s;
32401 			} else if(displayed_mstruct) {
32402 				if(displayed_mstruct->isAborted()) {
32403 					PangoLayout *layout = gtk_widget_create_pango_layout(widget, NULL);
32404 					pango_layout_set_markup(layout, _("calculation was aborted"), -1);
32405 					gint w = 0, h = 0;
32406 					pango_layout_get_pixel_size(layout, &w, &h);
32407 					PangoRectangle rect;
32408 					pango_layout_get_pixel_extents(layout, &rect, NULL);
32409 					if(rect.x < 0) {w -= rect.x; if(rect.width > w) w = rect.width;}
32410 					else if(w < rect.x + rect.width) w = rect.x + rect.width;
32411 					tmp_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * scalefactor, h * scalefactor);
32412 					cairo_surface_set_device_scale(tmp_surface, scalefactor, scalefactor);
32413 					cairo_t *cr2 = cairo_create(tmp_surface);
32414 					GdkRGBA rgba;
32415 					gtk_style_context_get_color(gtk_widget_get_style_context(widget), gtk_widget_get_state_flags(widget), &rgba);
32416 					gdk_cairo_set_source_rgba(cr2, &rgba);
32417 					if(rect.x < 0) cairo_move_to(cr, -rect.x, 0);
32418 					pango_cairo_show_layout(cr2, layout);
32419 					cairo_destroy(cr2);
32420 					g_object_unref(layout);
32421 				} else {
32422 					gint rw = -1;
32423 					if(scale_n == 3) rw = gtk_widget_get_allocated_width(GTK_WIDGET(gtk_builder_get_object(main_builder, "scrolled_result"))) - 12;
32424 					displayed_printops.can_display_unicode_string_arg = (void*) resultview;
32425 					tmp_surface = draw_structure(*displayed_mstruct, displayed_printops, displayed_caf, top_ips, NULL, scale_n, NULL, NULL, NULL, rw);
32426 					displayed_printops.can_display_unicode_string_arg = NULL;
32427 				}
32428 				surface_result = tmp_surface;
32429 			}
32430 		}
32431 		w = cairo_image_surface_get_width(surface_result) / scalefactor;
32432 		h = cairo_image_surface_get_height(surface_result) / scalefactor;
32433 		gint sbw, sbh;
32434 		gtk_widget_get_preferred_width(gtk_scrolled_window_get_vscrollbar(GTK_SCROLLED_WINDOW(gtk_builder_get_object(main_builder, "scrolled_result"))), NULL, &sbw);
32435 		gtk_widget_get_preferred_height(gtk_scrolled_window_get_hscrollbar(GTK_SCROLLED_WINDOW(gtk_builder_get_object(main_builder, "scrolled_result"))), NULL, &sbh);
32436 		gint rh = gtk_widget_get_allocated_height(GTK_WIDGET(gtk_builder_get_object(main_builder, "scrolled_result")));
32437 		gint rw = gtk_widget_get_allocated_width(GTK_WIDGET(gtk_builder_get_object(main_builder, "scrolled_result"))) - 12;
32438 		if(first_draw_of_result || (!b_busy && result_font_updated)) {
32439 			gint margin = 24;
32440 			while(displayed_mstruct && !display_aborted && scale_n < 3 && (w > rw || (w > rw - sbw ? h + margin / 1.5 > rh - sbh : h + margin > rh))) {
32441 				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")));
32442 				double scale_div = (double) h / (gtk_widget_get_allocated_height(GTK_WIDGET(gtk_builder_get_object(main_builder, "resultport"))) + scroll_diff);
32443 				if(scale_div > 1.44) {
32444 					scale_n = 3;
32445 				} else if(scale_n < 2 && scale_div > 1.2) {
32446 					scale_n = 2;
32447 				} else {
32448 					scale_n++;
32449 				}
32450 				cairo_surface_destroy(surface_result);
32451 				displayed_printops.can_display_unicode_string_arg = (void*) resultview;
32452 				surface_result = draw_structure(*displayed_mstruct, displayed_printops, displayed_caf, top_ips, NULL, scale_n, NULL, NULL, NULL, scale_n == 3 ? rw : -1);
32453 				displayed_printops.can_display_unicode_string_arg = NULL;
32454 				w = cairo_image_surface_get_width(surface_result) / scalefactor;
32455 				h = cairo_image_surface_get_height(surface_result) / scalefactor;
32456 				if(scale_n == 0) margin = 18;
32457 				else margin = 12;
32458 			}
32459 			result_font_updated = FALSE;
32460 		}
32461 		gtk_widget_set_size_request(widget, w, h);
32462 		if(h > sbh) rw -= sbw;
32463 		if(rw >= w) {
32464 #if GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION < 16
32465 			// compensate for overlay scrollbars
32466 			cairo_set_source_surface(cr, surface_result, rw >= w + 5 ? rw - w - 5 : rw - w - (rw - w) / 2, h < rh ? (rh - h) / 2 : 0);
32467 #else
32468 			cairo_set_source_surface(cr, surface_result, rw >= w ? rw - w : rw - w - (rw - w) / 2, h < rh ? (rh - h) / 2 : 0);
32469 #endif
32470 		} else {
32471 			if(h + ((rh - h) / 2) < rh - sbh) cairo_set_source_surface(cr, surface_result, 0, (rh - h) / 2);
32472 			else cairo_set_source_surface(cr, surface_result, 0, (h > rh - sbh) ? 0 : (rh - h - sbh) / 2);
32473 		}
32474 		cairo_paint(cr);
32475 		first_draw_of_result = FALSE;
32476 	} else if(showing_first_time_message) {
32477 		PangoLayout *layout = gtk_widget_create_pango_layout(GTK_WIDGET(gtk_builder_get_object(main_builder, "resultview")), NULL);
32478 		GdkRGBA rgba;
32479 		pango_layout_set_markup(layout, (string("<span size=\"smaller\">") + string(_("Type a mathematical expression above, e.g. \"5 + 2 / 3\",\nand press the enter key.")) + "</span>").c_str(), -1);
32480 		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);
32481 		cairo_move_to(cr, 6, 6);
32482 		gdk_cairo_set_source_rgba(cr, &rgba);
32483 		pango_cairo_show_layout(cr, layout);
32484 		g_object_unref(layout);
32485 	} else {
32486 		gtk_widget_set_size_request(widget, -1, -1);
32487 	}
32488 	return TRUE;
32489 }
on_matrix_edit_radiobutton_matrix_toggled(GtkToggleButton * w,gpointer)32490 void on_matrix_edit_radiobutton_matrix_toggled(GtkToggleButton *w, gpointer) {
32491 	if(gtk_toggle_button_get_active(w)) {
32492 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(matrixedit_builder, "matrix_edit_label_elements")), _("Elements"));
32493 	} else {
32494 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(matrixedit_builder, "matrix_edit_label_elements")), _("Elements (in horizontal order)"));
32495 	}
32496 	on_tMatrixEdit_cursor_changed(GTK_TREE_VIEW(tMatrixEdit), NULL);
32497 }
on_matrix_edit_radiobutton_vector_toggled(GtkToggleButton * w,gpointer)32498 void on_matrix_edit_radiobutton_vector_toggled(GtkToggleButton *w, gpointer) {
32499 	if(!gtk_toggle_button_get_active(w)) {
32500 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(matrixedit_builder, "matrix_edit_label_elements")), _("Elements"));
32501 	} else {
32502 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(matrixedit_builder, "matrix_edit_label_elements")), _("Elements (in horizontal order)"));
32503 	}
32504 	on_tMatrixEdit_cursor_changed(GTK_TREE_VIEW(tMatrixEdit), NULL);
32505 }
on_matrix_radiobutton_matrix_toggled(GtkToggleButton * w,gpointer)32506 void on_matrix_radiobutton_matrix_toggled(GtkToggleButton *w, gpointer) {
32507 	if(gtk_toggle_button_get_active(w)) {
32508 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(matrix_builder, "matrix_label_elements")), _("Elements"));
32509 	} else {
32510 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(matrix_builder, "matrix_label_elements")), _("Elements (in horizontal order)"));
32511 	}
32512 	on_tMatrix_cursor_changed(GTK_TREE_VIEW(tMatrix), NULL);
32513 }
on_matrix_radiobutton_vector_toggled(GtkToggleButton * w,gpointer)32514 void on_matrix_radiobutton_vector_toggled(GtkToggleButton *w, gpointer) {
32515 	if(!gtk_toggle_button_get_active(w)) {
32516 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(matrix_builder, "matrix_label_elements")), _("Elements"));
32517 	} else {
32518 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(matrix_builder, "matrix_label_elements")), _("Elements (in horizontal order)"));
32519 	}
32520 	on_tMatrix_cursor_changed(GTK_TREE_VIEW(tMatrix), NULL);
32521 }
32522 
on_csv_import_radiobutton_matrix_toggled(GtkToggleButton *,gpointer)32523 void on_csv_import_radiobutton_matrix_toggled(GtkToggleButton*, gpointer) {
32524 }
on_csv_import_radiobutton_vectors_toggled(GtkToggleButton *,gpointer)32525 void on_csv_import_radiobutton_vectors_toggled(GtkToggleButton*, gpointer) {
32526 }
on_csv_import_combobox_delimiter_changed(GtkComboBox * w,gpointer)32527 void on_csv_import_combobox_delimiter_changed(GtkComboBox *w, gpointer) {
32528 	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);
32529 }
on_csv_import_button_file_clicked(GtkButton *,gpointer)32530 void on_csv_import_button_file_clicked(GtkButton*, gpointer) {
32531 	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);
32532 	string filestr = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(csvimport_builder, "csv_import_entry_file")));
32533 	remove_blank_ends(filestr);
32534 	if(!filestr.empty()) gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(d), filestr.c_str());
32535 	if(gtk_dialog_run(GTK_DIALOG(d)) == GTK_RESPONSE_ACCEPT) {
32536 		const gchar *file_str = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(d));
32537 		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(csvimport_builder, "csv_import_entry_file")), file_str);
32538 		string name_str = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(csvimport_builder, "csv_import_entry_name")));
32539 		remove_blank_ends(name_str);
32540 		if(name_str.empty()) {
32541 			name_str = file_str;
32542 			size_t i = name_str.find_last_of("/");
32543 			if(i != string::npos) name_str = name_str.substr(i + 1, name_str.length() - i);
32544 			i = name_str.find_last_of(".");
32545 			if(i != string::npos) name_str = name_str.substr(0, i);
32546 			gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(csvimport_builder, "csv_import_entry_name")), name_str.c_str());
32547 		}
32548 	}
32549 	gtk_widget_destroy(d);
32550 }
32551 
on_csv_export_combobox_delimiter_changed(GtkComboBox * w,gpointer)32552 void on_csv_export_combobox_delimiter_changed(GtkComboBox *w, gpointer) {
32553 	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);
32554 }
on_csv_export_button_file_clicked(GtkButton *,gpointer)32555 void on_csv_export_button_file_clicked(GtkButton*, gpointer) {
32556 	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);
32557 	string filestr = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(csvexport_builder, "csv_export_entry_file")));
32558 	remove_blank_ends(filestr);
32559 	if(!filestr.empty()) gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(d), filestr.c_str());
32560 	if(gtk_dialog_run(GTK_DIALOG(d)) == GTK_RESPONSE_ACCEPT) {
32561 		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)));
32562 	}
32563 	gtk_widget_destroy(d);
32564 }
on_csv_export_radiobutton_current_toggled(GtkToggleButton * w,gpointer)32565 void on_csv_export_radiobutton_current_toggled(GtkToggleButton *w, gpointer) {
32566 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(csvexport_builder, "csv_export_entry_matrix")), !gtk_toggle_button_get_active(w));
32567 }
on_csv_export_radiobutton_matrix_toggled(GtkToggleButton * w,gpointer)32568 void on_csv_export_radiobutton_matrix_toggled(GtkToggleButton *w, gpointer) {
32569 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(csvexport_builder, "csv_export_entry_matrix")), gtk_toggle_button_get_active(w));
32570 }
32571 
on_type_label_date_clicked(GtkButton * w,gpointer user_data)32572 void on_type_label_date_clicked(GtkButton *w, gpointer user_data) {
32573 	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), _("_Cancel"), GTK_RESPONSE_CANCEL, _("_OK"), GTK_RESPONSE_OK, NULL);
32574 	GtkWidget *date_w = gtk_calendar_new();
32575 	gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(d))), date_w);
32576 	gtk_widget_show_all(d);
32577 	if(gtk_dialog_run(GTK_DIALOG(d)) == GTK_RESPONSE_OK) {
32578 		guint year = 0, month = 0, day = 0;
32579 		gtk_calendar_get_date(GTK_CALENDAR(date_w), &year, &month, &day);
32580 		gchar *gstr = g_strdup_printf("%i-%02i-%02i", year, month + 1, day);
32581 		gtk_entry_set_text(GTK_ENTRY(user_data), gstr);
32582 		g_free(gstr);
32583 	}
32584 	gtk_widget_destroy(d);
32585 }
on_type_label_vector_clicked(GtkButton * w,gpointer user_data)32586 void on_type_label_vector_clicked(GtkButton *w, gpointer user_data) {
32587 	MathStructure mstruct_v;
32588 	GtkEntry *entry = GTK_ENTRY(user_data);
32589 	string str = gtk_entry_get_text(entry);
32590 	remove_blank_ends(str);
32591 	if(!str.empty()) {
32592 		if(str[0] != '(' && str[0] != '[') {
32593 			str.insert(0, 1, '[');
32594 			str += ']';
32595 		}
32596 		CALCULATOR->beginTemporaryStopMessages();
32597 		CALCULATOR->parse(&mstruct_v, CALCULATOR->unlocalizeExpression(str, evalops.parse_options), evalops.parse_options);
32598 		CALCULATOR->endTemporaryStopMessages();
32599 	}
32600 	insert_matrix(str.empty() ? NULL : &mstruct_v, gtk_widget_get_ancestor(GTK_WIDGET(w), GTK_TYPE_WINDOW), TRUE, false, false, entry);
32601 }
on_type_label_matrix_clicked(GtkButton * w,gpointer user_data)32602 void on_type_label_matrix_clicked(GtkButton *w, gpointer user_data) {
32603 	MathStructure mstruct_m;
32604 	GtkEntry *entry = GTK_ENTRY(user_data);
32605 	string str = gtk_entry_get_text(entry);
32606 	remove_blank_ends(str);
32607 	if(!str.empty()) {
32608 		CALCULATOR->beginTemporaryStopMessages();
32609 		CALCULATOR->parse(&mstruct_m, CALCULATOR->unlocalizeExpression(str, evalops.parse_options), evalops.parse_options);
32610 		CALCULATOR->endTemporaryStopMessages();
32611 		if(!mstruct_m.isMatrix()) str = "";
32612 	}
32613 	insert_matrix(str.empty() ? NULL : &mstruct_m, gtk_widget_get_ancestor(GTK_WIDGET(w), GTK_TYPE_WINDOW), FALSE, false, false, entry);
32614 }
on_type_label_file_clicked(GtkButton *,gpointer user_data)32615 void on_type_label_file_clicked(GtkButton*, gpointer user_data) {
32616 	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);
32617 	string filestr = gtk_entry_get_text(GTK_ENTRY(user_data));
32618 	remove_blank_ends(filestr);
32619 	if(!filestr.empty()) gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(d), filestr.c_str());
32620 	gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(d), filestr.c_str());
32621 	if(gtk_dialog_run(GTK_DIALOG(d)) == GTK_RESPONSE_ACCEPT) {
32622 		gtk_entry_set_text(GTK_ENTRY(user_data), gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(d)));
32623 	}
32624 	gtk_widget_destroy(d);
32625 }
32626 
on_functions_button_deactivate_clicked(GtkButton *,gpointer)32627 void on_functions_button_deactivate_clicked(GtkButton*, gpointer) {
32628 	MathFunction *f = get_selected_function();
32629 	if(f) {
32630 		f->setActive(!f->isActive());
32631 		update_fmenu();
32632 	}
32633 }
on_variables_button_deactivate_clicked(GtkButton *,gpointer)32634 void on_variables_button_deactivate_clicked(GtkButton*, gpointer) {
32635 	Variable *v = get_selected_variable();
32636 	if(v) {
32637 		v->setActive(!v->isActive());
32638 		update_vmenu();
32639 	}
32640 }
on_units_button_deactivate_clicked(GtkButton *,gpointer)32641 void on_units_button_deactivate_clicked(GtkButton*, gpointer) {
32642 	Unit *u = get_selected_unit();
32643 	if(u) {
32644 		u->setActive(!u->isActive());
32645 		update_umenus();
32646 	}
32647 }
32648 
on_function_edit_textview_expression_key_press_event(GtkWidget * w,GdkEventKey * event,gpointer renderer)32649 gboolean on_function_edit_textview_expression_key_press_event(GtkWidget *w, GdkEventKey *event, gpointer renderer) {
32650 	const gchar *key = key_press_get_symbol(event);
32651 	if(!key) return FALSE;
32652 	if(strlen(key) > 0) {
32653 		GtkTextBuffer *expression_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(w));
32654 		gtk_text_buffer_delete_selection(expression_buffer, FALSE, TRUE);
32655 		gtk_text_buffer_insert_at_cursor(expression_buffer, key, -1);
32656 		return TRUE;
32657 	}
32658 	return FALSE;
32659 }
on_function_edit_button_subfunctions_clicked(GtkButton *,gpointer)32660 void on_function_edit_button_subfunctions_clicked(GtkButton*, gpointer) {
32661 	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")));
32662 	gtk_dialog_run(GTK_DIALOG(gtk_builder_get_object(functionedit_builder, "function_edit_dialog_subfunctions")));
32663 	gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_dialog_subfunctions")));
32664 }
on_function_edit_button_add_subfunction_clicked(GtkButton *,gpointer)32665 void on_function_edit_button_add_subfunction_clicked(GtkButton*, gpointer) {
32666 	GtkTreeIter iter;
32667 	gtk_list_store_append(tSubfunctions_store, &iter);
32668 	string str = "\\";
32669 	last_subfunction_index++;
32670 	str += i2s(last_subfunction_index);
32671 	if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(functionedit_builder, "function_edit_checkbutton_precalculate")))) {
32672 		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);
32673 	} else {
32674 		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);
32675 	}
32676 	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(functionedit_builder, "function_edit_entry_subexpression")), "");
32677 	on_function_changed();
32678 }
on_function_edit_button_modify_subfunction_clicked(GtkButton *,gpointer)32679 void on_function_edit_button_modify_subfunction_clicked(GtkButton*, gpointer) {
32680 	GtkTreeModel *model;
32681 	GtkTreeIter iter;
32682 	if(gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(tSubfunctions)), &model, &iter)) {
32683 		if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(functionedit_builder, "function_edit_checkbutton_precalculate")))) {
32684 			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);
32685 		} else {
32686 			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);
32687 		}
32688 		on_function_changed();
32689 	}
32690 }
on_function_edit_button_remove_subfunction_clicked(GtkButton *,gpointer)32691 void on_function_edit_button_remove_subfunction_clicked(GtkButton*, gpointer) {
32692 	GtkTreeModel *model;
32693 	GtkTreeIter iter;
32694 	if(gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(tSubfunctions)), &model, &iter)) {
32695 		GtkTreeIter iter2 = iter;
32696 		while(gtk_tree_model_iter_next(GTK_TREE_MODEL(tSubfunctions_store), &iter2)) {
32697 			guint index;
32698 			gtk_tree_model_get(GTK_TREE_MODEL(tSubfunctions_store), &iter2, 3, &index, -1);
32699 			index--;
32700 			string str = "\\";
32701 			str += i2s(index);
32702 			gtk_list_store_set(tSubfunctions_store, &iter2, 0, str.c_str(), 3, index, -1);
32703 		}
32704 		gtk_list_store_remove(tSubfunctions_store, &iter);
32705 		last_subfunction_index--;
32706 		on_function_changed();
32707 	}
32708 }
on_function_edit_entry_subexpression_activate(GtkEntry *,gpointer)32709 void on_function_edit_entry_subexpression_activate(GtkEntry*, gpointer) {
32710 	if(gtk_widget_get_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_button_add_subfunction")))) {
32711 		on_function_edit_button_add_subfunction_clicked(GTK_BUTTON(gtk_builder_get_object(functionedit_builder, "function_edit_button_add_subfunction")), NULL);
32712 	} else if(gtk_widget_get_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_button_modify_subfunction")))) {
32713 		on_function_edit_button_modify_subfunction_clicked(GTK_BUTTON(gtk_builder_get_object(functionedit_builder, "function_edit_button_modify_subfunction")), NULL);
32714 	}
32715 }
on_function_edit_button_add_argument_clicked(GtkButton *,gpointer)32716 void on_function_edit_button_add_argument_clicked(GtkButton*, gpointer) {
32717 	GtkTreeIter iter;
32718 	gtk_list_store_append(tFunctionArguments_store, &iter);
32719 	Argument *arg;
32720 	if(edited_function && edited_function->isBuiltin()) {
32721 		arg = new Argument();
32722 	} else {
32723 		int menu_index = gtk_combo_box_get_active(GTK_COMBO_BOX(gtk_builder_get_object(functionedit_builder, "function_edit_combobox_argument_type")));
32724 		switch(menu_index) {
32725 			case MENU_ARGUMENT_TYPE_TEXT: {arg = new TextArgument(); break;}
32726 			case MENU_ARGUMENT_TYPE_SYMBOLIC: {arg = new SymbolicArgument(); break;}
32727 			case MENU_ARGUMENT_TYPE_DATE: {arg = new DateArgument(); break;}
32728 			case MENU_ARGUMENT_TYPE_NONNEGATIVE_INTEGER: {arg = new IntegerArgument("", ARGUMENT_MIN_MAX_NONNEGATIVE); break;}
32729 			case MENU_ARGUMENT_TYPE_POSITIVE_INTEGER: {arg = new IntegerArgument("", ARGUMENT_MIN_MAX_POSITIVE); break;}
32730 			case MENU_ARGUMENT_TYPE_NONZERO_INTEGER: {arg = new IntegerArgument("", ARGUMENT_MIN_MAX_NONZERO); break;}
32731 			case MENU_ARGUMENT_TYPE_INTEGER: {arg = new IntegerArgument(); break;}
32732 			case MENU_ARGUMENT_TYPE_NONNEGATIVE: {arg = new NumberArgument("", ARGUMENT_MIN_MAX_NONNEGATIVE); break;}
32733 			case MENU_ARGUMENT_TYPE_POSITIVE: {arg = new NumberArgument("", ARGUMENT_MIN_MAX_POSITIVE); break;}
32734 			case MENU_ARGUMENT_TYPE_NONZERO: {arg = new NumberArgument("", ARGUMENT_MIN_MAX_NONZERO); break;}
32735 			case MENU_ARGUMENT_TYPE_NUMBER: {arg = new NumberArgument(); break;}
32736 			case MENU_ARGUMENT_TYPE_VECTOR: {arg = new VectorArgument(); break;}
32737 			case MENU_ARGUMENT_TYPE_MATRIX: {arg = new MatrixArgument(); break;}
32738 			case MENU_ARGUMENT_TYPE_EXPRESSION_ITEM: {arg = new ExpressionItemArgument(); break;}
32739 			case MENU_ARGUMENT_TYPE_FUNCTION: {arg = new FunctionArgument(); break;}
32740 			case MENU_ARGUMENT_TYPE_UNIT: {arg = new UnitArgument(); break;}
32741 			case MENU_ARGUMENT_TYPE_VARIABLE: {arg = new VariableArgument(); break;}
32742 			case MENU_ARGUMENT_TYPE_FILE: {arg = new FileArgument(); break;}
32743 			case MENU_ARGUMENT_TYPE_BOOLEAN: {arg = new BooleanArgument(); break;}
32744 			case MENU_ARGUMENT_TYPE_ANGLE: {arg = new AngleArgument(); break;}
32745 			case MENU_ARGUMENT_TYPE_DATA_OBJECT: {arg = new DataObjectArgument(NULL, ""); break;}
32746 			case MENU_ARGUMENT_TYPE_DATA_PROPERTY: {arg = new DataPropertyArgument(NULL, ""); break;}
32747 			default: {arg = new Argument();}
32748 		}
32749 	}
32750 	arg->setName(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(functionedit_builder, "function_edit_entry_argument_name"))));
32751 	gtk_list_store_set(tFunctionArguments_store, &iter, 0, arg->name().c_str(), 1, arg->printlong().c_str(), 2, arg, -1);
32752 	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(functionedit_builder, "function_edit_entry_argument_name")), "");
32753 	on_function_changed();
32754 }
on_function_edit_button_remove_argument_clicked(GtkButton *,gpointer)32755 void on_function_edit_button_remove_argument_clicked(GtkButton*, gpointer) {
32756 	GtkTreeModel *model;
32757 	GtkTreeIter iter;
32758 	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tFunctionArguments));
32759 	if(gtk_tree_selection_get_selected(select, &model, &iter)) {
32760 		if(selected_argument) {
32761 			delete selected_argument;
32762 			selected_argument = NULL;
32763 		}
32764 		gtk_list_store_remove(tFunctionArguments_store, &iter);
32765 		on_function_changed();
32766 	}
32767 	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(functionedit_builder, "function_edit_entry_argument_name")), "");
32768 }
on_function_edit_button_modify_argument_clicked(GtkButton *,gpointer)32769 void on_function_edit_button_modify_argument_clicked(GtkButton*, gpointer) {
32770 	GtkTreeModel *model;
32771 	GtkTreeIter iter;
32772 	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tFunctionArguments));
32773 	if(gtk_tree_selection_get_selected(select, &model, &iter)) {
32774 		int argtype = ARGUMENT_TYPE_FREE;
32775 		if(edited_function && edited_function->isBuiltin()) {
32776 			if(!selected_argument) {
32777 				selected_argument = new Argument();
32778 			}
32779 		} else {
32780 			int menu_index = gtk_combo_box_get_active(GTK_COMBO_BOX(gtk_builder_get_object(functionedit_builder, "function_edit_combobox_argument_type")));
32781 			switch(menu_index) {
32782 				case MENU_ARGUMENT_TYPE_TEXT: {argtype = ARGUMENT_TYPE_TEXT; break;}
32783 				case MENU_ARGUMENT_TYPE_SYMBOLIC: {argtype = ARGUMENT_TYPE_SYMBOLIC; break;}
32784 				case MENU_ARGUMENT_TYPE_DATE: {argtype = ARGUMENT_TYPE_DATE; break;}
32785 				case MENU_ARGUMENT_TYPE_NONNEGATIVE_INTEGER: {}
32786 				case MENU_ARGUMENT_TYPE_POSITIVE_INTEGER: {}
32787 				case MENU_ARGUMENT_TYPE_NONZERO_INTEGER: {}
32788 				case MENU_ARGUMENT_TYPE_INTEGER: {argtype = ARGUMENT_TYPE_INTEGER; break;}
32789 				case MENU_ARGUMENT_TYPE_NONNEGATIVE: {}
32790 				case MENU_ARGUMENT_TYPE_POSITIVE: {}
32791 				case MENU_ARGUMENT_TYPE_NONZERO: {}
32792 				case MENU_ARGUMENT_TYPE_NUMBER: {argtype = ARGUMENT_TYPE_NUMBER; break;}
32793 				case MENU_ARGUMENT_TYPE_VECTOR: {argtype = ARGUMENT_TYPE_VECTOR; break;}
32794 				case MENU_ARGUMENT_TYPE_MATRIX: {argtype = ARGUMENT_TYPE_MATRIX; break;}
32795 				case MENU_ARGUMENT_TYPE_EXPRESSION_ITEM: {argtype = ARGUMENT_TYPE_EXPRESSION_ITEM; break;}
32796 				case MENU_ARGUMENT_TYPE_FUNCTION: {argtype = ARGUMENT_TYPE_FUNCTION; break;}
32797 				case MENU_ARGUMENT_TYPE_UNIT: {argtype = ARGUMENT_TYPE_UNIT; break;}
32798 				case MENU_ARGUMENT_TYPE_VARIABLE: {argtype = ARGUMENT_TYPE_VARIABLE; break;}
32799 				case MENU_ARGUMENT_TYPE_FILE: {argtype = ARGUMENT_TYPE_FILE; break;}
32800 				case MENU_ARGUMENT_TYPE_BOOLEAN: {argtype = ARGUMENT_TYPE_BOOLEAN; break;}
32801 				case MENU_ARGUMENT_TYPE_ANGLE: {argtype = ARGUMENT_TYPE_ANGLE; break;}
32802 				case MENU_ARGUMENT_TYPE_DATA_OBJECT: {argtype = ARGUMENT_TYPE_DATA_OBJECT; break;}
32803 				case MENU_ARGUMENT_TYPE_DATA_PROPERTY: {argtype = ARGUMENT_TYPE_DATA_PROPERTY; break;}
32804 			}
32805 
32806 			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) {
32807 				if(selected_argument) {
32808 					delete selected_argument;
32809 				}
32810 				switch(menu_index) {
32811 					case MENU_ARGUMENT_TYPE_TEXT: {selected_argument = new TextArgument(); break;}
32812 					case MENU_ARGUMENT_TYPE_SYMBOLIC: {selected_argument = new SymbolicArgument(); break;}
32813 					case MENU_ARGUMENT_TYPE_DATE: {selected_argument = new DateArgument(); break;}
32814 					case MENU_ARGUMENT_TYPE_NONNEGATIVE_INTEGER: {selected_argument = new IntegerArgument("", ARGUMENT_MIN_MAX_NONNEGATIVE); break;}
32815 					case MENU_ARGUMENT_TYPE_POSITIVE_INTEGER: {selected_argument = new IntegerArgument("", ARGUMENT_MIN_MAX_POSITIVE); break;}
32816 					case MENU_ARGUMENT_TYPE_NONZERO_INTEGER: {selected_argument = new IntegerArgument("", ARGUMENT_MIN_MAX_NONZERO); break;}
32817 					case MENU_ARGUMENT_TYPE_INTEGER: {selected_argument = new IntegerArgument(); break;}
32818 					case MENU_ARGUMENT_TYPE_NONNEGATIVE: {selected_argument = new NumberArgument("", ARGUMENT_MIN_MAX_NONNEGATIVE); break;}
32819 					case MENU_ARGUMENT_TYPE_POSITIVE: {selected_argument = new NumberArgument("", ARGUMENT_MIN_MAX_POSITIVE); break;}
32820 					case MENU_ARGUMENT_TYPE_NONZERO: {selected_argument = new NumberArgument("", ARGUMENT_MIN_MAX_NONZERO); break;}
32821 					case MENU_ARGUMENT_TYPE_NUMBER: {selected_argument = new NumberArgument(); break;}
32822 					case MENU_ARGUMENT_TYPE_VECTOR: {selected_argument = new VectorArgument(); break;}
32823 					case MENU_ARGUMENT_TYPE_MATRIX: {selected_argument = new MatrixArgument(); break;}
32824 					case MENU_ARGUMENT_TYPE_EXPRESSION_ITEM: {selected_argument = new ExpressionItemArgument(); break;}
32825 					case MENU_ARGUMENT_TYPE_FUNCTION: {selected_argument = new FunctionArgument(); break;}
32826 					case MENU_ARGUMENT_TYPE_UNIT: {selected_argument = new UnitArgument(); break;}
32827 					case MENU_ARGUMENT_TYPE_VARIABLE: {selected_argument = new VariableArgument(); break;}
32828 					case MENU_ARGUMENT_TYPE_FILE: {selected_argument = new FileArgument(); break;}
32829 					case MENU_ARGUMENT_TYPE_BOOLEAN: {selected_argument = new BooleanArgument(); break;}
32830 					case MENU_ARGUMENT_TYPE_ANGLE: {selected_argument = new AngleArgument(); break;}
32831 					case MENU_ARGUMENT_TYPE_DATA_OBJECT: {selected_argument = new DataObjectArgument(NULL, ""); break;}
32832 					case MENU_ARGUMENT_TYPE_DATA_PROPERTY: {selected_argument = new DataPropertyArgument(NULL, ""); break;}
32833 					default: {selected_argument = new Argument();}
32834 				}
32835 			}
32836 
32837 		}
32838 		selected_argument->setName(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(functionedit_builder, "function_edit_entry_argument_name"))));
32839 		gtk_list_store_set(tFunctionArguments_store, &iter, 0, selected_argument->name().c_str(), 1, selected_argument->printlong().c_str(), 2, (gpointer) selected_argument, -1);
32840 		on_function_changed();
32841 	}
32842 }
on_function_edit_entry_argument_name_activate(GtkEntry *,gpointer)32843 void on_function_edit_entry_argument_name_activate(GtkEntry*, gpointer) {
32844 	if(gtk_widget_get_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_button_add_argument")))) {
32845 		on_function_edit_button_add_argument_clicked(GTK_BUTTON(gtk_builder_get_object(functionedit_builder, "function_edit_button_add_argument")), NULL);
32846 	} else if(gtk_widget_get_sensitive(GTK_WIDGET(gtk_builder_get_object(functionedit_builder, "function_edit_button_modify_argument")))) {
32847 		on_function_edit_button_modify_argument_clicked(GTK_BUTTON(gtk_builder_get_object(functionedit_builder, "function_edit_button_modify_argument")), NULL);
32848 	}
32849 }
on_function_edit_button_rules_clicked(GtkButton *,gpointer)32850 void on_function_edit_button_rules_clicked(GtkButton*, gpointer) {
32851 	if(edit_argument(get_selected_argument())) on_function_changed();
32852 }
on_argument_rules_checkbutton_enable_min_toggled(GtkToggleButton * w,gpointer)32853 void on_argument_rules_checkbutton_enable_min_toggled(GtkToggleButton *w, gpointer) {
32854 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(argumentrules_builder, "argument_rules_spinbutton_min")), gtk_toggle_button_get_active(w));
32855 }
on_argument_rules_checkbutton_enable_max_toggled(GtkToggleButton * w,gpointer)32856 void on_argument_rules_checkbutton_enable_max_toggled(GtkToggleButton *w, gpointer) {
32857 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(argumentrules_builder, "argument_rules_spinbutton_max")), gtk_toggle_button_get_active(w));
32858 }
on_argument_rules_checkbutton_enable_condition_toggled(GtkToggleButton * w,gpointer)32859 void on_argument_rules_checkbutton_enable_condition_toggled(GtkToggleButton *w, gpointer) {
32860 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(argumentrules_builder, "argument_rules_entry_condition")), gtk_toggle_button_get_active(w));
32861 }
32862 #define SET_NAMES_LE(x,y,z)	GtkTreeIter iter;\
32863 				string str;\
32864 				if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tNames_store), &iter)) {\
32865 					gchar *gstr;\
32866 					gtk_tree_model_get(GTK_TREE_MODEL(tNames_store), &iter, NAMES_NAME_COLUMN, &gstr, -1);\
32867 					if(strlen(gstr) > 0) {\
32868 						gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(x, y)), gstr);\
32869 					}\
32870 					g_free(gstr);\
32871 					if(gtk_tree_model_iter_next(GTK_TREE_MODEL(tNames_store), &iter)) {\
32872 						str += "+ ";\
32873 						while(true) {\
32874 							gtk_tree_model_get(GTK_TREE_MODEL(tNames_store), &iter, NAMES_NAME_COLUMN, &gstr, -1);\
32875 							str += gstr;\
32876 							g_free(gstr);\
32877 							if(!gtk_tree_model_iter_next(GTK_TREE_MODEL(tNames_store), &iter)) break;\
32878 							str += ", ";\
32879 						}\
32880 					}\
32881 				}\
32882 				gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(x, z)), str.c_str());
32883 
on_variable_edit_button_names_clicked(GtkButton *,gpointer)32884 void on_variable_edit_button_names_clicked(GtkButton*, gpointer) {
32885 	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")));
32886 	SET_NAMES_LE(variableedit_builder, "variable_edit_entry_name", "variable_edit_label_names")
32887 }
on_unknown_edit_button_names_clicked(GtkButton *,gpointer)32888 void on_unknown_edit_button_names_clicked(GtkButton*, gpointer) {
32889 	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")));
32890 	SET_NAMES_LE(unknownedit_builder, "unknown_edit_entry_name", "unknown_edit_label_names")
32891 }
on_matrix_edit_button_names_clicked(GtkButton *,gpointer)32892 void on_matrix_edit_button_names_clicked(GtkButton*, gpointer) {
32893 	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")));
32894 	SET_NAMES_LE(matrixedit_builder, "matrix_edit_entry_name", "matrix_edit_label_names")
32895 }
on_function_edit_button_names_clicked(GtkButton *,gpointer)32896 void on_function_edit_button_names_clicked(GtkButton*, gpointer) {
32897 	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")));
32898 	SET_NAMES_LE(functionedit_builder, "function_edit_entry_name", "function_edit_label_names")
32899 }
on_unit_edit_button_names_clicked(GtkButton *,gpointer)32900 void on_unit_edit_button_names_clicked(GtkButton*, gpointer) {
32901 	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")));
32902 	SET_NAMES_LE(unitedit_builder, "unit_edit_entry_name", "unit_edit_label_names")
32903 }
32904 
on_names_edit_checkbutton_abbreviation_toggled(GtkToggleButton * w,gpointer)32905 void on_names_edit_checkbutton_abbreviation_toggled(GtkToggleButton *w, gpointer) {
32906 	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));
32907 }
on_names_edit_button_add_clicked(GtkButton *,gpointer)32908 void on_names_edit_button_add_clicked(GtkButton*, gpointer) {
32909 	if(strlen(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(namesedit_builder, "names_edit_entry_name")))) == 0) {
32910 		gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(namesedit_builder, "names_edit_entry_name")));
32911 		show_message(_("Empty name field."), GTK_WIDGET(gtk_builder_get_object(namesedit_builder, "names_edit_dialog")));
32912 		return;
32913 	}
32914 	bool name_taken = false;
32915 	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;
32916 	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;
32917 	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;
32918 	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;
32919 	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;
32920 	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;
32921 	if(name_taken) {
32922 		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")))) {
32923 			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(namesedit_builder, "names_edit_entry_name")));
32924 			return;
32925 		}
32926 	}
32927 	GtkTreeIter iter;
32928 	gtk_list_store_append(tNames_store, &iter);
32929 	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,
32930 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);
32931 	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,
32932 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);
32933 	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(namesedit_builder, "names_edit_entry_name")), "");
32934 	on_name_changed();
32935 }
on_names_edit_button_modify_clicked(GtkButton *,gpointer)32936 void on_names_edit_button_modify_clicked(GtkButton*, gpointer) {
32937 	GtkTreeModel *model;
32938 	GtkTreeIter iter;
32939 	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tNames));
32940 	if(gtk_tree_selection_get_selected(select, &model, &iter)) {
32941 		char *gstr;
32942 		gtk_tree_model_get(GTK_TREE_MODEL(tNames_store), &iter, NAMES_NAME_COLUMN, &gstr, -1);
32943 		if(strcmp(gstr, gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(namesedit_builder, "names_edit_entry_name")))) != 0) {
32944 			bool name_taken = false;
32945 			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;
32946 			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;
32947 			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;
32948 			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;
32949 			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;
32950 			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;
32951 			if(name_taken) {
32952 				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")))) {
32953 					g_free(gstr);
32954 					return;
32955 				}
32956 			}
32957 		}
32958 		g_free(gstr);
32959 		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);
32960 		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);
32961 		on_name_changed();
32962 	}
32963 }
on_name_changed()32964 void on_name_changed() {
32965 	if(editing_function) on_function_changed();
32966 	if(editing_unknown) on_unknown_changed();
32967 	if(editing_matrix) on_matrix_changed();
32968 	if(editing_unit) on_unit_changed();
32969 	if(editing_variable) on_variable_changed();
32970 	if(editing_dataproperty) on_dataproperty_changed();
32971 	else if(editing_dataset) on_dataset_changed();
32972 }
on_names_edit_button_remove_clicked(GtkButton *,gpointer)32973 void on_names_edit_button_remove_clicked(GtkButton*, gpointer) {
32974 	GtkTreeModel *model;
32975 	GtkTreeIter iter;
32976 	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tNames));
32977 	if(gtk_tree_selection_get_selected(select, &model, &iter)) {
32978 		gtk_list_store_remove(tNames_store, &iter);
32979 		on_name_changed();
32980 	}
32981 	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(namesedit_builder, "names_edit_entry_name")), "");
32982 }
on_names_edit_entry_name_activate(GtkEntry *,gpointer)32983 void on_names_edit_entry_name_activate(GtkEntry*, gpointer) {
32984 	if(gtk_widget_get_sensitive(GTK_WIDGET(gtk_builder_get_object(namesedit_builder, "names_edit_button_add")))) {
32985 		on_names_edit_button_add_clicked(GTK_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_button_add")), NULL);
32986 	} else if(gtk_widget_get_sensitive(GTK_WIDGET(gtk_builder_get_object(namesedit_builder, "names_edit_button_modify")))) {
32987 		on_names_edit_button_modify_clicked(GTK_BUTTON(gtk_builder_get_object(namesedit_builder, "names_edit_button_modify")), NULL);
32988 	}
32989 }
on_names_edit_entry_name_changed(GtkEditable * editable,gpointer)32990 void on_names_edit_entry_name_changed(GtkEditable *editable, gpointer) {
32991 	int etype = -1;
32992 	if(editing_unit) etype = TYPE_UNIT;
32993 	else if(editing_function || editing_dataset) etype = TYPE_FUNCTION;
32994 	else if(!editing_dataproperty) etype = TYPE_VARIABLE;
32995 	if(etype >= 0) correct_name_entry(editable, (ExpressionItemType) etype, (gpointer) on_names_edit_entry_name_changed);
32996 }
32997 
on_menu_item_customize_buttons_activate(GtkMenuItem *,gpointer)32998 void on_menu_item_customize_buttons_activate(GtkMenuItem*, gpointer) {
32999 	bool set_sr = !buttonsedit_builder;
33000 	GtkWidget *dialog = get_buttons_edit_dialog();
33001 	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(buttonsedit_builder, "buttons_edit_treeview")));
33002 	gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")));
33003 	gtk_widget_show(dialog);
33004 	if(set_sr) {
33005 		gint w;
33006 		gtk_window_get_size(GTK_WINDOW(dialog), &w, NULL);
33007 		gtk_widget_set_size_request(dialog, w, -1);
33008 	}
33009 	gtk_window_present_with_time(GTK_WINDOW(dialog), GDK_CURRENT_TIME);
33010 }
33011 
on_menu_item_edit_shortcuts_activate(GtkMenuItem *,gpointer)33012 void on_menu_item_edit_shortcuts_activate(GtkMenuItem*, gpointer) {
33013 	GtkWidget *dialog = get_shortcuts_dialog();
33014 	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(shortcuts_builder, "shortcuts_treeview")));
33015 	gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gtk_builder_get_object(main_builder, "main_window")));
33016 	gtk_widget_show(dialog);
33017 	gtk_window_present_with_time(GTK_WINDOW(dialog), GDK_CURRENT_TIME);
33018 }
33019 
on_tShortcuts_selection_changed(GtkTreeSelection * treeselection,gpointer)33020 void on_tShortcuts_selection_changed(GtkTreeSelection *treeselection, gpointer) {
33021 	GtkTreeModel *model;
33022 	GtkTreeIter iter;
33023 	selected_subfunction = 0;
33024 	if(gtk_tree_selection_get_selected(treeselection, &model, &iter)) {
33025 		guint64 val = 0;
33026 		gtk_tree_model_get(model, &iter, 3, &val, -1);
33027 		unordered_map<guint64, keyboard_shortcut>::iterator it = keyboard_shortcuts.find(val);
33028 		if(it != keyboard_shortcuts.end()) {
33029 			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(shortcuts_builder, "shortcuts_button_remove")), TRUE);
33030 			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(shortcuts_builder, "shortcuts_button_edit")), TRUE);
33031 		}
33032 	} else {
33033 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(shortcuts_builder, "shortcuts_button_remove")), FALSE);
33034 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(shortcuts_builder, "shortcuts_button_edit")), FALSE);
33035 	}
33036 }
on_tShortcutsType_selection_changed(GtkTreeSelection * treeselection,gpointer)33037 void on_tShortcutsType_selection_changed(GtkTreeSelection *treeselection, gpointer) {
33038 	GtkTreeModel *model;
33039 	GtkTreeIter iter;
33040 	selected_subfunction = 0;
33041 	if(gtk_tree_selection_get_selected(treeselection, &model, &iter)) {
33042 		int type = 0;
33043 		gtk_tree_model_get(model, &iter, 1, &type, -1);
33044 		switch(type) {
33045 			case SHORTCUT_TYPE_FUNCTION: {}
33046 			case SHORTCUT_TYPE_FUNCTION_WITH_DIALOG: {}
33047 			case SHORTCUT_TYPE_VARIABLE: {}
33048 			case SHORTCUT_TYPE_UNIT: {}
33049 			case SHORTCUT_TYPE_TEXT: {}
33050 			case SHORTCUT_TYPE_CONVERT: {}
33051 			case SHORTCUT_TYPE_TO_NUMBER_BASE: {}
33052 			case SHORTCUT_TYPE_META_MODE: {}
33053 			case SHORTCUT_TYPE_INPUT_BASE: {}
33054 			case SHORTCUT_TYPE_OUTPUT_BASE: {
33055 				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(shortcuts_builder, "shortcuts_entry_value")), TRUE);
33056 				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(shortcuts_builder, "shortcuts_label_value")), TRUE);
33057 				break;
33058 			}
33059 			default: {
33060 				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(shortcuts_builder, "shortcuts_entry_value")), FALSE);
33061 				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(shortcuts_builder, "shortcuts_label_value")), FALSE);
33062 			}
33063 		}
33064 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(shortcuts_builder, "shortcuts_button_ok")), TRUE);
33065 	} else {
33066 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(shortcuts_builder, "shortcuts_button_ok")), FALSE);
33067 	}
33068 }
on_tButtonsEditType_selection_changed(GtkTreeSelection * treeselection,gpointer)33069 void on_tButtonsEditType_selection_changed(GtkTreeSelection *treeselection, gpointer) {
33070 	GtkTreeModel *model;
33071 	GtkTreeIter iter;
33072 	if(gtk_tree_selection_get_selected(treeselection, &model, &iter)) {
33073 		int type = 0;
33074 		gtk_tree_model_get(model, &iter, 1, &type, -1);
33075 		switch(type) {
33076 			case SHORTCUT_TYPE_FUNCTION: {}
33077 			case SHORTCUT_TYPE_FUNCTION_WITH_DIALOG: {}
33078 			case SHORTCUT_TYPE_VARIABLE: {}
33079 			case SHORTCUT_TYPE_UNIT: {}
33080 			case SHORTCUT_TYPE_TEXT: {}
33081 			case SHORTCUT_TYPE_CONVERT: {}
33082 			case SHORTCUT_TYPE_TO_NUMBER_BASE: {}
33083 			case SHORTCUT_TYPE_META_MODE: {}
33084 			case SHORTCUT_TYPE_INPUT_BASE: {}
33085 			case SHORTCUT_TYPE_OUTPUT_BASE: {
33086 				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(buttonsedit_builder, "shortcuts_entry_value")), TRUE);
33087 				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(buttonsedit_builder, "shortcuts_label_value")), TRUE);
33088 				break;
33089 			}
33090 			default: {
33091 				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(buttonsedit_builder, "shortcuts_entry_value")), FALSE);
33092 				gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(buttonsedit_builder, "shortcuts_label_value")), FALSE);
33093 			}
33094 		}
33095 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(buttonsedit_builder, "shortcuts_button_ok")), TRUE);
33096 	} else {
33097 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(buttonsedit_builder, "shortcuts_button_ok")), FALSE);
33098 	}
33099 }
33100 
33101 GtkWidget *shortcut_label = NULL;
on_shortcut_key_released(GtkWidget * w,GdkEventKey * event,gpointer)33102 gboolean on_shortcut_key_released(GtkWidget *w, GdkEventKey *event, gpointer) {
33103 #if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 18
33104 	guint state = event->state & gdk_keymap_get_modifier_mask(gdk_keymap_get_for_display(gtk_widget_get_display(mainwindow)), GDK_MODIFIER_INTENT_DEFAULT_MOD_MASK);
33105 #else
33106 	guint state = event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK | GDK_MOD1_MASK | GDK_SUPER_MASK | GDK_HYPER_MASK | GDK_META_MASK);
33107 #endif
33108 	if(event->keyval == 0 || (event->keyval >= GDK_KEY_Shift_L && event->keyval <= GDK_KEY_Hyper_R)) return FALSE;
33109 	if(state == 0 && event->keyval == GDK_KEY_Escape) {
33110 		gtk_dialog_response(GTK_DIALOG(w), GTK_RESPONSE_CANCEL);
33111 		return TRUE;
33112 	}
33113 	if(state == 0 && event->keyval >= GDK_KEY_ampersand && event->keyval <= GDK_KEY_z) return FALSE;
33114 	current_shortcut_key = event->keyval;
33115 	current_shortcut_modifier = state;
33116 	gtk_dialog_response(GTK_DIALOG(w), GTK_RESPONSE_OK);
33117 	return TRUE;
33118 }
on_shortcut_key_pressed(GtkWidget * w,GdkEventKey * event,gpointer)33119 gboolean on_shortcut_key_pressed(GtkWidget *w, GdkEventKey *event, gpointer) {
33120 #if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 18
33121 	guint state = event->state & gdk_keymap_get_modifier_mask(gdk_keymap_get_for_display(gtk_widget_get_display(mainwindow)), GDK_MODIFIER_INTENT_DEFAULT_MOD_MASK);
33122 #else
33123 	guint state = event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK | GDK_MOD1_MASK | GDK_SUPER_MASK | GDK_HYPER_MASK | GDK_META_MASK);
33124 #endif
33125 	string str = "<span size=\"large\">";
33126 	str += shortcut_to_text(event->keyval, state);
33127 	str += "</span>";
33128 	gtk_label_set_markup(GTK_LABEL(shortcut_label), str.c_str());
33129 	return FALSE;
33130 }
get_keyboard_shortcut(GtkWindow * parent)33131 bool get_keyboard_shortcut(GtkWindow *parent) {
33132 	GtkWidget *dialog = gtk_dialog_new();
33133 	gtk_window_set_transient_for(GTK_WINDOW(dialog), parent);
33134 	gtk_window_set_title(GTK_WINDOW(dialog), _("Set key combination"));
33135 	gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
33136 	gtk_container_set_border_width(GTK_CONTAINER(dialog), 6);
33137 	// Make the line reasonably long, but not to short (at least around 40 characters)
33138 	string str = "<i>"; str += _("Press the key combination you wish to use for the action\n(press Escape to cancel)."); str += "</i>";
33139 	GtkWidget *label = gtk_label_new(str.c_str());
33140 	gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
33141 #if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 16
33142 	gtk_label_set_xalign(GTK_LABEL(label), 0.0);
33143 #else
33144 	gtk_widget_set_halign(label, GTK_ALIGN_START);
33145 #endif
33146 	gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), label, FALSE, TRUE, 6);
33147 	gtk_widget_show(label);
33148 	str = "<span size=\"large\">"; str += _("No keys"); str += "</span>";
33149 	shortcut_label = gtk_label_new(str.c_str());
33150 	gtk_label_set_use_markup(GTK_LABEL(shortcut_label), TRUE);
33151 	g_signal_connect(dialog, "key-press-event", G_CALLBACK(on_shortcut_key_pressed), dialog);
33152 	g_signal_connect(dialog, "key-release-event", G_CALLBACK(on_shortcut_key_released), dialog);
33153 	gtk_box_pack_end(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), shortcut_label, TRUE, TRUE, 18);
33154 	gtk_widget_show(shortcut_label);
33155 	if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) {
33156 		gtk_widget_destroy(dialog);
33157 		return current_shortcut_key != 0 && current_shortcut_modifier != 0;
33158 	}
33159 	gtk_widget_destroy(dialog);
33160 	return false;
33161 }
on_shortcuts_entry_value_activate(GtkEntry *,gpointer d)33162 void on_shortcuts_entry_value_activate(GtkEntry*, gpointer d) {
33163 	gtk_dialog_response(GTK_DIALOG(gtk_builder_get_object(shortcuts_builder, "shortcuts_type_dialog")), GTK_RESPONSE_ACCEPT);
33164 }
on_buttonsedit_entry_value_activate(GtkEntry *,gpointer d)33165 void on_buttonsedit_entry_value_activate(GtkEntry*, gpointer d) {
33166 	gtk_dialog_response(GTK_DIALOG(gtk_builder_get_object(buttonsedit_builder, "shortcuts_type_dialog")), GTK_RESPONSE_ACCEPT);
33167 }
on_shortcuts_type_treeview_row_activated(GtkTreeView *,GtkTreePath *,GtkTreeViewColumn *,gpointer)33168 void on_shortcuts_type_treeview_row_activated(GtkTreeView*, GtkTreePath*, GtkTreeViewColumn*, gpointer) {
33169 	if(gtk_widget_get_sensitive(GTK_WIDGET(gtk_builder_get_object(shortcuts_builder, "shortcuts_entry_value")))) gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(shortcuts_builder, "shortcuts_entry_value")));
33170 	else gtk_dialog_response(GTK_DIALOG(gtk_builder_get_object(shortcuts_builder, "shortcuts_type_dialog")), GTK_RESPONSE_ACCEPT);
33171 }
on_buttonsedit_type_treeview_row_activated(GtkTreeView *,GtkTreePath *,GtkTreeViewColumn *,gpointer)33172 void on_buttonsedit_type_treeview_row_activated(GtkTreeView*, GtkTreePath*, GtkTreeViewColumn*, gpointer) {
33173 	if(gtk_widget_get_sensitive(GTK_WIDGET(gtk_builder_get_object(buttonsedit_builder, "shortcuts_entry_value")))) gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(buttonsedit_builder, "shortcuts_entry_value")));
33174 	else gtk_dialog_response(GTK_DIALOG(gtk_builder_get_object(buttonsedit_builder, "shortcuts_type_dialog")), GTK_RESPONSE_ACCEPT);
33175 }
on_shortcuts_button_new_clicked(GtkButton *,gpointer)33176 void on_shortcuts_button_new_clicked(GtkButton*, gpointer) {
33177 	GtkWidget *d = GTK_WIDGET(gtk_builder_get_object(shortcuts_builder, "shortcuts_type_dialog"));
33178 	gtk_widget_grab_focus(tShortcutsType);
33179 	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(shortcuts_builder, "shortcuts_entry_value")), "");
33180 	run_shortcuts_dialog:
33181 	if(gtk_dialog_run(GTK_DIALOG(d)) == GTK_RESPONSE_ACCEPT) {
33182 		GtkTreeModel *model;
33183 		GtkTreeIter iter;
33184 		GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tShortcutsType));
33185 		keyboard_shortcut ks;
33186 		if(gtk_tree_selection_get_selected(select, &model, &iter)) gtk_tree_model_get(GTK_TREE_MODEL(tShortcutsType_store), &iter, 1, &ks.type, -1);
33187 		else goto run_shortcuts_dialog;
33188 		if(gtk_widget_is_sensitive(GTK_WIDGET(gtk_builder_get_object(shortcuts_builder, "shortcuts_entry_value")))) {
33189 			ks.value = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(shortcuts_builder, "shortcuts_entry_value")));
33190 			remove_blank_ends(ks.value);
33191 			if(ks.value.empty()) {
33192 				gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(shortcuts_builder, "shortcuts_entry_value")));
33193 				show_message(_("Empty value."), d);
33194 				goto run_shortcuts_dialog;
33195 			}
33196 			switch(ks.type) {
33197 				case SHORTCUT_TYPE_FUNCTION: {}
33198 				case SHORTCUT_TYPE_FUNCTION_WITH_DIALOG: {
33199 					remove_blanks(ks.value);
33200 					if(ks.value.length() > 2 && ks.value.substr(ks.value.length() - 2, 2) == "()") ks.value = ks.value.substr(0, ks.value.length() - 2);
33201 					if(!CALCULATOR->getActiveFunction(ks.value)) {
33202 						gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(shortcuts_builder, "shortcuts_entry_value")));
33203 						show_message(_("Function not found."), GTK_WIDGET(gtk_builder_get_object(shortcuts_builder, "shortcuts_dialog")));
33204 						goto run_shortcuts_dialog;
33205 					}
33206 					break;
33207 				}
33208 				case SHORTCUT_TYPE_VARIABLE: {
33209 					if(!CALCULATOR->getActiveVariable(ks.value)) {
33210 						gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(shortcuts_builder, "shortcuts_entry_value")));
33211 						show_message(_("Variable not found."), GTK_WIDGET(gtk_builder_get_object(shortcuts_builder, "shortcuts_dialog")));
33212 						goto run_shortcuts_dialog;
33213 					}
33214 					break;
33215 				}
33216 				case SHORTCUT_TYPE_UNIT: {
33217 					if(!CALCULATOR->getActiveUnit(ks.value)) {
33218 						gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(shortcuts_builder, "shortcuts_entry_value")));
33219 						show_message(_("Unit not found."), GTK_WIDGET(gtk_builder_get_object(shortcuts_builder, "shortcuts_dialog")));
33220 						goto run_shortcuts_dialog;
33221 					}
33222 					break;
33223 				}
33224 				case SHORTCUT_TYPE_META_MODE: {
33225 					bool b = false;
33226 					for(size_t i = 0; i < modes.size(); i++) {
33227 						if(equalsIgnoreCase(modes[i].name, ks.value)) {
33228 							b = true;
33229 							break;
33230 						}
33231 					}
33232 					if(!b) {
33233 						show_message(_("Mode not found."), mainwindow);
33234 						goto run_shortcuts_dialog;
33235 					}
33236 					break;
33237 				}
33238 				case SHORTCUT_TYPE_TO_NUMBER_BASE: {}
33239 				case SHORTCUT_TYPE_INPUT_BASE: {}
33240 				case SHORTCUT_TYPE_OUTPUT_BASE: {
33241 					Number nbase; int base;
33242 					base_from_string(ks.value, base, nbase, ks.type == SHORTCUT_TYPE_INPUT_BASE);
33243 					if(base == BASE_CUSTOM && nbase.isZero()) {
33244 						show_message(_("Unsupported base."), GTK_WIDGET(gtk_builder_get_object(shortcuts_builder, "shortcuts_dialog")));
33245 						goto run_shortcuts_dialog;
33246 					}
33247 					break;
33248 				}
33249 			}
33250 		} else {
33251 			ks.value = "";
33252 		}
33253 		ask_keyboard_shortcut:
33254 		if(get_keyboard_shortcut(GTK_WINDOW(gtk_builder_get_object(shortcuts_builder, "shortcuts_type_dialog")))) {
33255 			ks.key = current_shortcut_key;
33256 			ks.modifier = current_shortcut_modifier;
33257 			guint64 id = (guint64) ks.key + (guint64) G_MAXUINT32 * (guint64) ks.modifier;
33258 			unordered_map<guint64, keyboard_shortcut>::iterator it = keyboard_shortcuts.find(id);
33259 			if(it != keyboard_shortcuts.end()) {
33260 				if(!ask_question(_("The key combination is already in use.\nDo you wish to replace the current action?"), GTK_WIDGET(gtk_builder_get_object(shortcuts_builder, "shortcuts_type_dialog")))) {
33261 					goto ask_keyboard_shortcut;
33262 				}
33263 				GtkTreeIter iter;
33264 				if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tShortcuts_store), &iter)) {
33265 					do {
33266 						guint64 id2 = 0;
33267 						gtk_tree_model_get(GTK_TREE_MODEL(tShortcuts_store), &iter, 3, &id2, -1);
33268 						if(id2 == id) {
33269 							gtk_list_store_remove(tShortcuts_store, &iter);
33270 							break;
33271 						}
33272 					} while(gtk_tree_model_iter_next(GTK_TREE_MODEL(tShortcuts_store), &iter));
33273 				}
33274 				keyboard_shortcuts.erase(id);
33275 			}
33276 			default_shortcuts = false;
33277 			GtkTreeIter iter;
33278 			gtk_list_store_append(tShortcuts_store, &iter);
33279 			gtk_list_store_set(tShortcuts_store, &iter, 0, shortcut_type_text(ks.type), 1, ks.value.c_str(), 2, shortcut_to_text(ks.key, ks.modifier).c_str(), 3, id, -1);
33280 			keyboard_shortcuts[id] = ks;
33281 			gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(shortcuts_builder, "shortcuts_entry_value")), "");
33282 			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(shortcuts_builder, "shortcuts_button_remove")), FALSE);
33283 			gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(shortcuts_builder, "shortcuts_button_edit")), FALSE);
33284 			gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(tShortcuts)));
33285 		}
33286 	}
33287 	gtk_widget_hide(d);
33288 }
on_shortcuts_button_remove_clicked(GtkButton *,gpointer)33289 void on_shortcuts_button_remove_clicked(GtkButton*, gpointer) {
33290 	GtkTreeModel *model;
33291 	GtkTreeIter iter;
33292 	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tShortcuts));
33293 	if(gtk_tree_selection_get_selected(select, &model, &iter)) {
33294 		guint64 id = 0;
33295 		gtk_tree_model_get(GTK_TREE_MODEL(tShortcuts_store), &iter, 3, &id, -1);
33296 		keyboard_shortcuts.erase(id);
33297 		gtk_list_store_remove(tShortcuts_store, &iter);
33298 		default_shortcuts = false;
33299 	}
33300 }
on_shortcuts_button_edit_clicked(GtkButton *,gpointer)33301 void on_shortcuts_button_edit_clicked(GtkButton*, gpointer) {
33302 	GtkTreeModel *model;
33303 	GtkTreeIter iter;
33304 	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tShortcuts));
33305 	if(gtk_tree_selection_get_selected(select, &model, &iter)) {
33306 		guint64 id;
33307 		gtk_tree_model_get(GTK_TREE_MODEL(tShortcuts_store), &iter, 3, &id, -1);
33308 		unordered_map<guint64, keyboard_shortcut>::iterator it_old = keyboard_shortcuts.find(id);
33309 		if(it_old != keyboard_shortcuts.end() && get_keyboard_shortcut(GTK_WINDOW(gtk_builder_get_object(shortcuts_builder, "shortcuts_dialog")))) {
33310 			keyboard_shortcut ks;
33311 			ks.type = it_old->second.type;
33312 			ks.value = it_old->second.value;
33313 			ks.key = current_shortcut_key;
33314 			ks.modifier = current_shortcut_modifier;
33315 			id = (guint64) ks.key + (guint64) G_MAXUINT32 * (guint64) ks.modifier;
33316 			unordered_map<guint64, keyboard_shortcut>::iterator it = keyboard_shortcuts.find(id);
33317 			bool b_replace = false;
33318 			if(it != keyboard_shortcuts.end()) {
33319 				if(it == it_old || !ask_question(_("The key combination is already in use.\nDo you wish to replace the current action?"), GTK_WIDGET(gtk_builder_get_object(shortcuts_builder, "shortcuts_dialog")))) {
33320 					return;
33321 				}
33322 				b_replace = true;
33323 			}
33324 			keyboard_shortcuts.erase(it_old);
33325 			g_signal_handlers_block_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tShortcuts_selection_changed
33326 , NULL);
33327 			gtk_list_store_remove(tShortcuts_store, &iter);
33328 			g_signal_handlers_unblock_matched((gpointer) select, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_tShortcuts_selection_changed, NULL);
33329 			default_shortcuts = false;
33330 			if(b_replace) {
33331 				if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tShortcuts_store), &iter)) {
33332 					do {
33333 						guint64 id2 = 0;
33334 						gtk_tree_model_get(GTK_TREE_MODEL(tShortcuts_store), &iter, 3, &id2, -1);
33335 						if(id2 == id) {
33336 							gtk_list_store_remove(tShortcuts_store, &iter);
33337 							break;
33338 						}
33339 					} while(gtk_tree_model_iter_next(GTK_TREE_MODEL(tShortcuts_store), &iter));
33340 				}
33341 				keyboard_shortcuts.erase(id);
33342 			}
33343 			keyboard_shortcuts[id] = ks;
33344 			gtk_list_store_append(tShortcuts_store, &iter);
33345 			gtk_list_store_set(tShortcuts_store, &iter, 0, shortcut_type_text(ks.type), 1, ks.value.c_str(), 2, shortcut_to_text(ks.key, ks.modifier).c_str(), 3, id, -1);
33346 			gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tShortcuts)), &iter);
33347 		}
33348 		default_shortcuts = false;
33349 	}
33350 }
on_shortcuts_treeview_row_activated(GtkTreeView * w,GtkTreePath * path,GtkTreeViewColumn * column,gpointer)33351 void on_shortcuts_treeview_row_activated(GtkTreeView *w, GtkTreePath *path, GtkTreeViewColumn *column, gpointer) {
33352 	if(column == gtk_tree_view_get_column(w, 2)) {
33353 		on_shortcuts_button_edit_clicked(NULL, NULL);
33354 		return;
33355 	}
33356 	GtkTreeIter iter;
33357 	if(!gtk_tree_model_get_iter(GTK_TREE_MODEL(tShortcuts_store), &iter, path)) return;
33358 	guint64 id;
33359 	gtk_tree_model_get(GTK_TREE_MODEL(tShortcuts_store), &iter, 3, &id, -1);
33360 	unordered_map<guint64, keyboard_shortcut>::iterator it = keyboard_shortcuts.find(id);
33361 	if(it == keyboard_shortcuts.end()) return;
33362 	GtkWidget *d = GTK_WIDGET(gtk_builder_get_object(shortcuts_builder, "shortcuts_type_dialog"));
33363 	GtkTreeIter iter2;
33364 	GtkTreeModel *model;
33365 	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tShortcutsType));
33366 	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(shortcuts_builder, "shortcuts_entry_value")), it->second.value.c_str());
33367 	if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tShortcutsType_store), &iter2)) {
33368 		do {
33369 			int type = 0;
33370 			gtk_tree_model_get(GTK_TREE_MODEL(tShortcutsType_store), &iter2, 1, &type, -1);
33371 			if(type == it->second.type) {
33372 				gtk_tree_selection_select_iter(select, &iter2);
33373 				GtkTreePath *path = gtk_tree_model_get_path(gtk_tree_view_get_model(GTK_TREE_VIEW(tShortcutsType)), &iter2);
33374 				gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(tShortcutsType), path, NULL, TRUE, 0.5, 0);
33375 				gtk_tree_path_free(path);
33376 				break;
33377 			}
33378 		} while(gtk_tree_model_iter_next(GTK_TREE_MODEL(tShortcutsType_store), &iter2));
33379 	}
33380 	if(column == gtk_tree_view_get_column(w, 1)) gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(shortcuts_builder, "shortcuts_entry_value")));
33381 	else gtk_widget_grab_focus(GTK_WIDGET(w));
33382 	run_shortcuts_dialog:
33383 	if(gtk_dialog_run(GTK_DIALOG(d)) == GTK_RESPONSE_ACCEPT) {
33384 		keyboard_shortcut ks;
33385 		if(gtk_tree_selection_get_selected(select, &model, &iter2)) gtk_tree_model_get(GTK_TREE_MODEL(tShortcutsType_store), &iter2, 1, &ks.type, -1);
33386 		else goto run_shortcuts_dialog;
33387 		if(gtk_widget_is_sensitive(GTK_WIDGET(gtk_builder_get_object(shortcuts_builder, "shortcuts_entry_value")))) {
33388 			ks.value = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(shortcuts_builder, "shortcuts_entry_value")));
33389 			remove_blank_ends(ks.value);
33390 			if(ks.value.empty()) {
33391 				gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(shortcuts_builder, "shortcuts_entry_value")));
33392 				show_message(_("Empty value."), d);
33393 				goto run_shortcuts_dialog;
33394 			}
33395 			switch(ks.type) {
33396 				case SHORTCUT_TYPE_FUNCTION: {}
33397 				case SHORTCUT_TYPE_FUNCTION_WITH_DIALOG: {
33398 					remove_blanks(ks.value);
33399 					if(ks.value.length() > 2 && ks.value.substr(ks.value.length() - 2, 2) == "()") ks.value = ks.value.substr(0, ks.value.length() - 2);
33400 					if(!CALCULATOR->getActiveFunction(ks.value)) {
33401 						gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(shortcuts_builder, "shortcuts_entry_value")));
33402 						show_message(_("Function not found."), GTK_WIDGET(gtk_builder_get_object(shortcuts_builder, "shortcuts_dialog")));
33403 						goto run_shortcuts_dialog;
33404 					}
33405 					break;
33406 				}
33407 				case SHORTCUT_TYPE_VARIABLE: {
33408 					if(!CALCULATOR->getActiveVariable(ks.value)) {
33409 						gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(shortcuts_builder, "shortcuts_entry_value")));
33410 						show_message(_("Variable not found."), GTK_WIDGET(gtk_builder_get_object(shortcuts_builder, "shortcuts_dialog")));
33411 						goto run_shortcuts_dialog;
33412 					}
33413 					break;
33414 				}
33415 				case SHORTCUT_TYPE_UNIT: {
33416 					if(!CALCULATOR->getActiveUnit(ks.value)) {
33417 						gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(shortcuts_builder, "shortcuts_entry_value")));
33418 						show_message(_("Unit not found."), GTK_WIDGET(gtk_builder_get_object(shortcuts_builder, "shortcuts_dialog")));
33419 						goto run_shortcuts_dialog;
33420 					}
33421 					break;
33422 				}
33423 				case SHORTCUT_TYPE_META_MODE: {
33424 					bool b = false;
33425 					for(size_t i = 0; i < modes.size(); i++) {
33426 						if(equalsIgnoreCase(modes[i].name, ks.value)) {
33427 							b = true;
33428 							break;
33429 						}
33430 					}
33431 					if(!b) {
33432 						show_message(_("Mode not found."), mainwindow);
33433 						goto run_shortcuts_dialog;
33434 					}
33435 					break;
33436 				}
33437 				case SHORTCUT_TYPE_TO_NUMBER_BASE: {}
33438 				case SHORTCUT_TYPE_INPUT_BASE: {}
33439 				case SHORTCUT_TYPE_OUTPUT_BASE: {
33440 					Number nbase; int base;
33441 					base_from_string(ks.value, base, nbase, ks.type == SHORTCUT_TYPE_INPUT_BASE);
33442 					if(base == BASE_CUSTOM && nbase.isZero()) {
33443 						show_message(_("Unsupported base."), GTK_WIDGET(gtk_builder_get_object(shortcuts_builder, "shortcuts_dialog")));
33444 						goto run_shortcuts_dialog;
33445 					}
33446 					break;
33447 				}
33448 			}
33449 		} else {
33450 			ks.value = "";
33451 		}
33452 		it->second.type = ks.type;
33453 		it->second.value = ks.value;
33454 		gtk_list_store_set(tShortcuts_store, &iter, 0, shortcut_type_text(ks.type), 1, ks.value.c_str(), -1);
33455 	}
33456 	gtk_widget_hide(d);
33457 }
33458 
on_buttons_edit_entry_label_changed(GtkEditable * w,gpointer user_data)33459 void on_buttons_edit_entry_label_changed(GtkEditable *w, gpointer user_data) {
33460 	int i = 0;
33461 	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tButtonsEdit));
33462 	GtkTreeModel *model;
33463 	GtkTreeIter iter;
33464 	if(!gtk_tree_selection_get_selected(select, &model, &iter)) return;
33465 	gtk_tree_model_get(model, &iter, 0, &i, -1);
33466 	gtk_entry_get_text(GTK_ENTRY(w));
33467 	custom_buttons[i].text = gtk_entry_get_text(GTK_ENTRY(w));
33468 	update_custom_buttons(i);
33469 	update_custom_buttons_edit(i, false);
33470 }
on_tButtonsEdit_update_selection(GtkTreeSelection * treeselection,bool update_label_entry)33471 void on_tButtonsEdit_update_selection(GtkTreeSelection *treeselection, bool update_label_entry) {
33472 	GtkTreeModel *model;
33473 	GtkTreeIter iter;
33474 	selected_subfunction = 0;
33475 	if(update_label_entry) g_signal_handlers_block_matched((gpointer) gtk_builder_get_object(buttonsedit_builder, "buttons_edit_entry_label"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_buttons_edit_entry_label_changed, NULL);
33476 	if(gtk_tree_selection_get_selected(treeselection, &model, &iter)) {
33477 		int i = 0;
33478 		gchar *gstr, *gstr2, *gstr3, *gstr4;
33479 		gtk_tree_model_get(model, &iter, 0, &i, 1, &gstr, 2, &gstr2, 3, &gstr3, 4, &gstr4, -1);
33480 		gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(buttonsedit_builder, "buttons_edit_button_1")), gstr2);
33481 		gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(buttonsedit_builder, "buttons_edit_button_2")), gstr3);
33482 		gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(buttonsedit_builder, "buttons_edit_button_3")), gstr4);
33483 		if(update_label_entry) {
33484 			if(i <= 1) gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(buttonsedit_builder, "buttons_edit_entry_label")), custom_buttons[i].text.c_str());
33485 			else gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(buttonsedit_builder, "buttons_edit_entry_label")), gstr);
33486 		}
33487 		g_free(gstr); g_free(gstr2); g_free(gstr3); g_free(gstr4);
33488 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(buttonsedit_builder, "buttons_edit_box_edit")), TRUE);
33489 	} else {
33490 		if(update_label_entry) gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(buttonsedit_builder, "buttons_edit_entry_label")), "");
33491 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(buttonsedit_builder, "buttons_edit_box_edit")), FALSE);
33492 		gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(buttonsedit_builder, "buttons_edit_button_1")), "");
33493 		gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(buttonsedit_builder, "buttons_edit_button_2")), "");
33494 		gtk_widget_set_tooltip_text(GTK_WIDGET(gtk_builder_get_object(buttonsedit_builder, "buttons_edit_button_3")), "");
33495 	}
33496 	if(update_label_entry) g_signal_handlers_unblock_matched((gpointer) gtk_builder_get_object(buttonsedit_builder, "buttons_edit_entry_label"), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) on_buttons_edit_entry_label_changed, NULL);
33497 }
on_tButtonsEdit_selection_changed(GtkTreeSelection * treeselection,gpointer)33498 void on_tButtonsEdit_selection_changed(GtkTreeSelection *treeselection, gpointer) {
33499 	on_tButtonsEdit_update_selection(treeselection, true);
33500 }
on_buttonsedit_button_x_clicked(int b_i)33501 void on_buttonsedit_button_x_clicked(int b_i) {
33502 	int i = 0;
33503 	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tButtonsEdit));
33504 	GtkTreeModel *model;
33505 	GtkTreeIter iter;
33506 	if(!gtk_tree_selection_get_selected(select, &model, &iter)) return;
33507 	gtk_tree_model_get(model, &iter, 0, &i, -1);
33508 	GtkWidget *d = GTK_WIDGET(gtk_builder_get_object(buttonsedit_builder, "shortcuts_type_dialog"));
33509 	GtkTreeIter iter2;
33510 	select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tButtonsEditType));
33511 	gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(buttonsedit_builder, "shortcuts_entry_value")), custom_buttons[i].value[b_i].c_str());
33512 	if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tButtonsEditType_store), &iter2)) {
33513 		int type = 0;
33514 		gtk_tree_model_get(GTK_TREE_MODEL(tButtonsEditType_store), &iter2, 1, &type, -1);
33515 		if(type == -1 && i >= 29) {
33516 			gtk_list_store_remove(tButtonsEditType_store, &iter2);
33517 		} else if(type == -2 && i < 29) {
33518 			gtk_list_store_insert(tButtonsEditType_store, &iter2, 0);
33519 			gtk_list_store_set(tButtonsEditType_store, &iter2, 0, _("Default"), 1, -1, -1);
33520 		}
33521 		do {
33522 			int type = 0;
33523 			gtk_tree_model_get(GTK_TREE_MODEL(tButtonsEditType_store), &iter2, 1, &type, -1);
33524 			if(type == -2 && i >= 29) type = -1;
33525 			if(type == custom_buttons[i].type[b_i]) {
33526 				gtk_tree_selection_select_iter(select, &iter2);
33527 				GtkTreePath *path = gtk_tree_model_get_path(gtk_tree_view_get_model(GTK_TREE_VIEW(tButtonsEditType)), &iter2);
33528 				gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(tButtonsEditType), path, NULL, TRUE, 0.5, 0);
33529 				gtk_tree_path_free(path);
33530 				break;
33531 			}
33532 		} while(gtk_tree_model_iter_next(GTK_TREE_MODEL(tButtonsEditType_store), &iter2));
33533 	}
33534 	gtk_widget_grab_focus(tButtonsEditType);
33535 	run_shortcuts_dialog:
33536 	if(gtk_dialog_run(GTK_DIALOG(d)) == GTK_RESPONSE_ACCEPT) {
33537 		int type = 0;
33538 		string value;
33539 		if(gtk_tree_selection_get_selected(select, &model, &iter2)) gtk_tree_model_get(GTK_TREE_MODEL(tButtonsEditType_store), &iter2, 1, &type, -1);
33540 		else goto run_shortcuts_dialog;
33541 		if(i >= 29 && type == -2) type = -1;
33542 		if(gtk_widget_is_sensitive(GTK_WIDGET(gtk_builder_get_object(buttonsedit_builder, "shortcuts_entry_value")))) {
33543 			value = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(buttonsedit_builder, "shortcuts_entry_value")));
33544 			remove_blank_ends(value);
33545 			if(value.empty()) {
33546 				gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(buttonsedit_builder, "shortcuts_entry_value")));
33547 				show_message(_("Empty value."), d);
33548 				goto run_shortcuts_dialog;
33549 			}
33550 			switch(type) {
33551 				case SHORTCUT_TYPE_FUNCTION: {}
33552 				case SHORTCUT_TYPE_FUNCTION_WITH_DIALOG: {
33553 					remove_blanks(value);
33554 					if(value.length() > 2 && value.substr(value.length() - 2, 2) == "()") value = value.substr(0, value.length() - 2);
33555 					if(!CALCULATOR->getActiveFunction(value)) {
33556 						gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(buttonsedit_builder, "shortcuts_entry_value")));
33557 						show_message(_("Function not found."), GTK_WIDGET(gtk_builder_get_object(buttonsedit_builder, "shortcuts_dialog")));
33558 						goto run_shortcuts_dialog;
33559 					}
33560 					break;
33561 				}
33562 				case SHORTCUT_TYPE_VARIABLE: {
33563 					if(!CALCULATOR->getActiveVariable(value)) {
33564 						gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(buttonsedit_builder, "shortcuts_entry_value")));
33565 						show_message(_("Variable not found."), GTK_WIDGET(gtk_builder_get_object(buttonsedit_builder, "shortcuts_dialog")));
33566 						goto run_shortcuts_dialog;
33567 					}
33568 					break;
33569 				}
33570 				case SHORTCUT_TYPE_UNIT: {
33571 					if(!CALCULATOR->getActiveUnit(value)) {
33572 						gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(buttonsedit_builder, "shortcuts_entry_value")));
33573 						show_message(_("Unit not found."), GTK_WIDGET(gtk_builder_get_object(buttonsedit_builder, "shortcuts_dialog")));
33574 						goto run_shortcuts_dialog;
33575 					}
33576 					break;
33577 				}
33578 				case SHORTCUT_TYPE_META_MODE: {
33579 					bool b = false;
33580 					for(size_t i = 0; i < modes.size(); i++) {
33581 						if(equalsIgnoreCase(modes[i].name, value)) {
33582 							b = true;
33583 							break;
33584 						}
33585 					}
33586 					if(!b) {
33587 						show_message(_("Mode not found."), mainwindow);
33588 						goto run_shortcuts_dialog;
33589 					}
33590 					break;
33591 				}
33592 				case SHORTCUT_TYPE_TO_NUMBER_BASE: {}
33593 				case SHORTCUT_TYPE_INPUT_BASE: {}
33594 				case SHORTCUT_TYPE_OUTPUT_BASE: {
33595 					Number nbase; int base;
33596 					base_from_string(value, base, nbase, type == SHORTCUT_TYPE_INPUT_BASE);
33597 					if(base == BASE_CUSTOM && nbase.isZero()) {
33598 						show_message(_("Unsupported base."), GTK_WIDGET(gtk_builder_get_object(buttonsedit_builder, "shortcuts_dialog")));
33599 						goto run_shortcuts_dialog;
33600 					}
33601 					break;
33602 				}
33603 			}
33604 		} else {
33605 			value = "";
33606 		}
33607 		custom_buttons[i].type[b_i] = type;
33608 		custom_buttons[i].value[b_i] = value;
33609 		update_custom_buttons(i);
33610 		update_custom_buttons_edit(i, false);
33611 	}
33612 	gtk_widget_hide(d);
33613 }
on_buttons_edit_button_1_clicked(GtkButton *,gpointer user_data)33614 void on_buttons_edit_button_1_clicked(GtkButton*, gpointer user_data) {
33615 	on_buttonsedit_button_x_clicked(0);
33616 }
on_buttons_edit_button_2_clicked(GtkButton *,gpointer user_data)33617 void on_buttons_edit_button_2_clicked(GtkButton*, gpointer user_data) {
33618 	on_buttonsedit_button_x_clicked(1);
33619 }
on_buttons_edit_button_3_clicked(GtkButton *,gpointer user_data)33620 void on_buttons_edit_button_3_clicked(GtkButton*, gpointer user_data) {
33621 	on_buttonsedit_button_x_clicked(2);
33622 }
on_buttons_edit_button_defaults_clicked(GtkButton * w,gpointer user_data)33623 void on_buttons_edit_button_defaults_clicked(GtkButton *w, gpointer user_data) {
33624 	int i = 0;
33625 	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tButtonsEdit));
33626 	GtkTreeModel *model;
33627 	GtkTreeIter iter;
33628 	if(!gtk_tree_selection_get_selected(select, &model, &iter)) return;
33629 	gtk_tree_model_get(model, &iter, 0, &i, -1);
33630 	custom_buttons[i].type[0] = -1;
33631 	custom_buttons[i].value[0] = "";
33632 	custom_buttons[i].type[1] = -1;
33633 	custom_buttons[i].value[1] = "";
33634 	custom_buttons[i].type[2] = -1;
33635 	custom_buttons[i].value[2] = "";
33636 	custom_buttons[i].text = "";
33637 	update_custom_buttons(i);
33638 	update_custom_buttons_edit(i, true);
33639 }
on_buttons_edit_treeview_row_activated(GtkTreeView * w,GtkTreePath * path,GtkTreeViewColumn * column,gpointer)33640 void on_buttons_edit_treeview_row_activated(GtkTreeView *w, GtkTreePath *path, GtkTreeViewColumn *column, gpointer) {
33641 	GtkTreeIter iter;
33642 	if(!gtk_tree_model_get_iter(GTK_TREE_MODEL(tButtonsEdit_store), &iter, path)) return;
33643 	int i = 0;
33644 	gtk_tree_model_get(GTK_TREE_MODEL(tButtonsEdit_store), &iter, 0, &i, -1);
33645 	if(column == gtk_tree_view_get_column(w, 0)) {
33646 		gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(buttonsedit_builder, "buttons_edit_entry_label")));
33647 	} else if(column == gtk_tree_view_get_column(w, 1)) {
33648 		on_buttons_edit_button_1_clicked(NULL, NULL);
33649 	} else if(column == gtk_tree_view_get_column(w, 2)) {
33650 		on_buttons_edit_button_2_clicked(NULL, NULL);
33651 	} else if(column == gtk_tree_view_get_column(w, 3)) {
33652 		on_buttons_edit_button_3_clicked(NULL, NULL);
33653 	}
33654 }
33655 
33656 
generate_plot(PlotParameters & pp,vector<MathStructure> & y_vectors,vector<MathStructure> & x_vectors,vector<PlotDataParameters * > & pdps)33657 bool generate_plot(PlotParameters &pp, vector<MathStructure> &y_vectors, vector<MathStructure> &x_vectors, vector<PlotDataParameters*> &pdps) {
33658 	GtkTreeIter iter;
33659 	bool b = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tPlotFunctions_store), &iter);
33660 	if(!b) {
33661 		return false;
33662 	}
33663 	while(b) {
33664 		int count = 1;
33665 		gchar *gstr1, *gstr2;
33666 		gint type = 0, style = 0, smoothing = 0, axis = 1, rows = 0;
33667 		MathStructure *y_vector, *x_vector;
33668 		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);
33669 		if(type == 1) {
33670 			if(y_vector->isMatrix()) {
33671 				count = 0;
33672 				if(rows) {
33673 					for(size_t i = 1; i <= y_vector->rows(); i++) {
33674 						y_vectors.push_back(m_undefined);
33675 						y_vector->rowToVector(i, y_vectors[y_vectors.size() - 1]);
33676 						x_vectors.push_back(m_undefined);
33677 						count++;
33678 					}
33679 				} else {
33680 					for(size_t i = 1; i <= y_vector->columns(); i++) {
33681 						y_vectors.push_back(m_undefined);
33682 						y_vector->columnToVector(i, y_vectors[y_vectors.size() - 1]);
33683 						x_vectors.push_back(m_undefined);
33684 						count++;
33685 					}
33686 				}
33687 			} else if(y_vector->isVector()) {
33688 				y_vectors.push_back(*y_vector);
33689 				x_vectors.push_back(m_undefined);
33690 			} else {
33691 				y_vectors.push_back(*y_vector);
33692 				y_vectors[y_vectors.size() - 1].transform(STRUCT_VECTOR);
33693 				x_vectors.push_back(m_undefined);
33694 			}
33695 		} else if(type == 2) {
33696 			if(y_vector->isMatrix()) {
33697 				count = 0;
33698 				if(rows) {
33699 					for(size_t i = 1; i <= y_vector->rows(); i += 2) {
33700 						y_vectors.push_back(m_undefined);
33701 						y_vector->rowToVector(i, y_vectors[y_vectors.size() - 1]);
33702 						x_vectors.push_back(m_undefined);
33703 						y_vector->rowToVector(i + 1, x_vectors[x_vectors.size() - 1]);
33704 						count++;
33705 					}
33706 				} else {
33707 					for(size_t i = 1; i <= y_vector->columns(); i += 2) {
33708 						y_vectors.push_back(m_undefined);
33709 						y_vector->columnToVector(i, y_vectors[y_vectors.size() - 1]);
33710 						x_vectors.push_back(m_undefined);
33711 						y_vector->columnToVector(i + 1, x_vectors[x_vectors.size() - 1]);
33712 						count++;
33713 					}
33714 				}
33715 			} else if(y_vector->isVector()) {
33716 				y_vectors.push_back(*y_vector);
33717 				x_vectors.push_back(m_undefined);
33718 			} else {
33719 				y_vectors.push_back(*y_vector);
33720 				y_vectors[y_vectors.size() - 1].transform(STRUCT_VECTOR);
33721 				x_vectors.push_back(m_undefined);
33722 			}
33723 		} else {
33724 			y_vectors.push_back(*y_vector);
33725 			x_vectors.push_back(*x_vector);
33726 		}
33727 		for(int i = 0; i < count; i++) {
33728 			PlotDataParameters *pdp = new PlotDataParameters();
33729 			pdp->title = gstr1;
33730 			if(count > 1) {
33731 				pdp->title += " :";
33732 				pdp->title += i2s(i + 1);
33733 			}
33734 			remove_blank_ends(pdp->title);
33735 			if(pdp->title.empty()) {
33736 				pdp->title = gstr2;
33737 			}
33738 			pdp->test_continuous = type != 1 && type != 2;
33739 			switch(smoothing) {
33740 				case SMOOTHING_MENU_NONE: {pdp->smoothing = PLOT_SMOOTHING_NONE; break;}
33741 				case SMOOTHING_MENU_UNIQUE: {pdp->smoothing = PLOT_SMOOTHING_UNIQUE; break;}
33742 				case SMOOTHING_MENU_CSPLINES: {pdp->smoothing = PLOT_SMOOTHING_CSPLINES; break;}
33743 				case SMOOTHING_MENU_BEZIER: {pdp->smoothing = PLOT_SMOOTHING_BEZIER; break;}
33744 				case SMOOTHING_MENU_SBEZIER: {pdp->smoothing = PLOT_SMOOTHING_SBEZIER; break;}
33745 			}
33746 			switch(style) {
33747 				case PLOTSTYLE_MENU_LINES: {pdp->style = PLOT_STYLE_LINES; break;}
33748 				case PLOTSTYLE_MENU_POINTS: {pdp->style = PLOT_STYLE_POINTS; break;}
33749 				case PLOTSTYLE_MENU_LINESPOINTS: {pdp->style = PLOT_STYLE_POINTS_LINES; break;}
33750 				case PLOTSTYLE_MENU_DOTS: {pdp->style = PLOT_STYLE_DOTS; break;}
33751 				case PLOTSTYLE_MENU_BOXES: {pdp->style = PLOT_STYLE_BOXES; break;}
33752 				case PLOTSTYLE_MENU_HISTEPS: {pdp->style = PLOT_STYLE_HISTOGRAM; break;}
33753 				case PLOTSTYLE_MENU_STEPS: {pdp->style = PLOT_STYLE_STEPS; break;}
33754 				case PLOTSTYLE_MENU_CANDLESTICKS: {pdp->style = PLOT_STYLE_CANDLESTICKS; break;}
33755 			}
33756 			pdp->yaxis2 = (axis == 2);
33757 			pdps.push_back(pdp);
33758 		}
33759 		g_free(gstr1);
33760 		g_free(gstr2);
33761 		b = gtk_tree_model_iter_next(GTK_TREE_MODEL(tPlotFunctions_store), &iter);
33762 	}
33763 	switch(gtk_combo_box_get_active(GTK_COMBO_BOX(gtk_builder_get_object(plot_builder, "plot_combobox_legend_place")))) {
33764 		case PLOTLEGEND_MENU_NONE: {pp.legend_placement = PLOT_LEGEND_NONE; break;}
33765 		case PLOTLEGEND_MENU_TOP_LEFT: {pp.legend_placement = PLOT_LEGEND_TOP_LEFT; break;}
33766 		case PLOTLEGEND_MENU_TOP_RIGHT: {pp.legend_placement = PLOT_LEGEND_TOP_RIGHT; break;}
33767 		case PLOTLEGEND_MENU_BOTTOM_LEFT: {pp.legend_placement = PLOT_LEGEND_BOTTOM_LEFT; break;}
33768 		case PLOTLEGEND_MENU_BOTTOM_RIGHT: {pp.legend_placement = PLOT_LEGEND_BOTTOM_RIGHT; break;}
33769 		case PLOTLEGEND_MENU_BELOW: {pp.legend_placement = PLOT_LEGEND_BELOW; break;}
33770 		case PLOTLEGEND_MENU_OUTSIDE: {pp.legend_placement = PLOT_LEGEND_OUTSIDE; break;}
33771 	}
33772 	pp.title = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_plottitle")));
33773 	pp.x_label = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_xlabel")));
33774 	pp.y_label = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_ylabel")));
33775 	pp.grid = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_checkbutton_grid")));
33776 	pp.x_log = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_checkbutton_xlog")));
33777 	pp.y_log = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_checkbutton_ylog")));
33778 	pp.x_log_base = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_builder_get_object(plot_builder, "plot_spinbutton_xlog_base")));
33779 	pp.y_log_base = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_builder_get_object(plot_builder, "plot_spinbutton_ylog_base")));
33780 	pp.auto_y_min = !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_checkbutton_ymin")));
33781 	pp.auto_y_max = !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_checkbutton_ymax")));
33782 	pp.y_min = gtk_spin_button_get_value(GTK_SPIN_BUTTON(gtk_builder_get_object(plot_builder, "plot_spinbutton_ymin")));
33783 	pp.y_max = gtk_spin_button_get_value(GTK_SPIN_BUTTON(gtk_builder_get_object(plot_builder, "plot_spinbutton_ymax")));
33784 	pp.color = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_radiobutton_color")));
33785 	pp.show_all_borders = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_checkbutton_full_border")));
33786 	pp.linewidth = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_builder_get_object(plot_builder, "plot_spinbutton_linewidth")));
33787 	return true;
33788 }
on_plot_button_help_clicked(GtkButton,gpointer)33789 void on_plot_button_help_clicked(GtkButton, gpointer) {
33790 	show_help("qalculate-plotting.html", gtk_builder_get_object(plot_builder, "plot_dialog"));
33791 }
on_plot_button_save_clicked(GtkButton *,gpointer)33792 void on_plot_button_save_clicked(GtkButton*, gpointer) {
33793 	GtkWidget *d;
33794 	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);
33795 	gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(d), TRUE);
33796 	GtkFileFilter *filter = gtk_file_filter_new();
33797 	gtk_file_filter_set_name(filter, _("Allowed File Types"));
33798 	gtk_file_filter_add_mime_type(filter, "image/x-xfig");
33799 	gtk_file_filter_add_mime_type(filter, "image/svg");
33800 	gtk_file_filter_add_mime_type(filter, "text/x-tex");
33801 	gtk_file_filter_add_mime_type(filter, "application/pdf");
33802 	gtk_file_filter_add_mime_type(filter, "application/postscript");
33803 	gtk_file_filter_add_mime_type(filter, "image/x-eps");
33804 	gtk_file_filter_add_mime_type(filter, "image/png");
33805 	gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(d), filter);
33806 	GtkFileFilter *filter_all = gtk_file_filter_new();
33807 	gtk_file_filter_add_pattern(filter_all, "*");
33808 	gtk_file_filter_set_name(filter_all, _("All Files"));
33809 	gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(d), filter_all);
33810 	string title = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_plottitle")));
33811 	if(title.empty()) {
33812 		gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(d), "plot.png");
33813 	} else {
33814 		title += ".png";
33815 		gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(d), title.c_str());
33816 	}
33817 	if(gtk_dialog_run(GTK_DIALOG(d)) == GTK_RESPONSE_ACCEPT) {
33818 		vector<MathStructure> y_vectors;
33819 		vector<MathStructure> x_vectors;
33820 		vector<PlotDataParameters*> pdps;
33821 		PlotParameters pp;
33822 		if(generate_plot(pp, y_vectors, x_vectors, pdps)) {
33823 			pp.filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(d));
33824 			pp.filetype = PLOT_FILETYPE_AUTO;
33825 			do_timeout = false;
33826 			CALCULATOR->plotVectors(&pp, y_vectors, x_vectors, pdps, false, max_plot_time * 1000);
33827 			display_errors(NULL, GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_dialog")));
33828 			do_timeout = true;
33829 			for(size_t i = 0; i < pdps.size(); i++) {
33830 				if(pdps[i]) delete pdps[i];
33831 			}
33832 		}
33833 	}
33834 	gtk_widget_destroy(d);
33835 }
update_plot()33836 void update_plot() {
33837 	vector<MathStructure> y_vectors;
33838 	vector<MathStructure> x_vectors;
33839 	vector<PlotDataParameters*> pdps;
33840 	PlotParameters pp;
33841 	if(!generate_plot(pp, y_vectors, x_vectors, pdps)) {
33842 		CALCULATOR->closeGnuplot();
33843 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_button_save")), false);
33844 		return;
33845 	}
33846 	do_timeout = false;
33847 	CALCULATOR->plotVectors(&pp, y_vectors, x_vectors, pdps, false, max_plot_time * 1000);
33848 	display_errors(NULL, GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_dialog")));
33849 	do_timeout = true;
33850 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_button_save")), true);
33851 	for(size_t i = 0; i < pdps.size(); i++) {
33852 		if(pdps[i]) delete pdps[i];
33853 	}
33854 }
33855 
generate_plot_series(MathStructure ** x_vector,MathStructure ** y_vector,int type,string str,string str_x)33856 void generate_plot_series(MathStructure **x_vector, MathStructure **y_vector, int type, string str, string str_x) {
33857 	CALCULATOR->beginTemporaryStopIntervalArithmetic();
33858 	EvaluationOptions eo;
33859 	eo.approximation = APPROXIMATION_APPROXIMATE;
33860 	eo.parse_options = evalops.parse_options;
33861 	eo.parse_options.base = 10;
33862 	eo.parse_options.read_precision = DONT_READ_PRECISION;
33863 	do_timeout = false;
33864 	if(type == 1 || type == 2) {
33865 		*y_vector = new MathStructure();
33866 		if(!CALCULATOR->calculate(*y_vector, CALCULATOR->unlocalizeExpression(str, eo.parse_options), max_plot_time * 1000, eo)) {
33867 			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."));
33868 			gtk_dialog_run(GTK_DIALOG(d));
33869 			gtk_widget_destroy(d);
33870 		}
33871 		*x_vector = NULL;
33872 	} else {
33873 		*x_vector = new MathStructure();
33874 		(*x_vector)->clearVector();
33875 		MathStructure min;
33876 		if(!CALCULATOR->calculate(&min, CALCULATOR->unlocalizeExpression(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_min"))), eo.parse_options), 1000, eo)) {
33877 			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."));
33878 			gtk_dialog_run(GTK_DIALOG(d));
33879 			gtk_widget_destroy(d);
33880 			display_errors(NULL, GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_dialog")));
33881 			do_timeout = true;
33882 			return;
33883 		}
33884 		MathStructure max;
33885 		if(!CALCULATOR->calculate(&max, CALCULATOR->unlocalizeExpression(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_max"))), eo.parse_options), 1000, eo)) {
33886 			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."));
33887 			gtk_dialog_run(GTK_DIALOG(d));
33888 			gtk_widget_destroy(d);
33889 			display_errors(NULL, GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_dialog")));
33890 			do_timeout = true;
33891 			return;
33892 		}
33893 		if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_radiobutton_step")))) {
33894 			*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"))), eo.parse_options), eo), *x_vector, str_x, eo.parse_options, max_plot_time * 1000));
33895 		} else {
33896 			*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, eo.parse_options, max_plot_time * 1000));
33897 		}
33898 	}
33899 	CALCULATOR->endTemporaryStopIntervalArithmetic();
33900 	display_errors(NULL, GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_dialog")));
33901 	do_timeout = true;
33902 }
on_plot_button_add_clicked(GtkButton *,gpointer)33903 void on_plot_button_add_clicked(GtkButton*, gpointer) {
33904 	string expression = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_expression")));
33905 	if(expression.find_first_not_of(SPACES) == string::npos) {
33906 		gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_entry_expression")));
33907 		show_message(_("Empty expression."), GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_dialog")));
33908 		return;
33909 	}
33910 	gint type = 0, axis = 1, rows = 0;
33911 	string title = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_title")));
33912 	if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_radiobutton_vector")))) {
33913 		type = 1;
33914 	} else if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_radiobutton_paired")))) {
33915 		type = 2;
33916 	}
33917 	string str_x = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_variable")));
33918 	remove_blank_ends(str_x);
33919 	if(str_x.empty() && type == 0) {
33920 		gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_entry_variable")));
33921 		show_message(_("Empty x variable."), GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_dialog")));
33922 		return;
33923 	}
33924 	if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_radiobutton_yaxis2")))) {
33925 		axis = 2;
33926 	}
33927 	if((type == 1 || type == 2) && title.empty()) {
33928 		Variable *v = CALCULATOR->getActiveVariable(expression);
33929 		if(v) {
33930 			title = v->title(false);
33931 		}
33932 	}
33933 	MathStructure *x_vector, *y_vector;
33934 	generate_plot_series(&x_vector, &y_vector, type, expression, str_x);
33935 	rows = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_checkbutton_rows")));
33936 	GtkTreeIter iter;
33937 	gtk_list_store_append(tPlotFunctions_store, &iter);
33938 	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);
33939 	gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(tPlotFunctions)), &iter);
33940 	gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_entry_expression")));
33941 	update_plot();
33942 }
on_plot_button_modify_clicked(GtkButton *,gpointer)33943 void on_plot_button_modify_clicked(GtkButton*, gpointer) {
33944 
33945 	GtkTreeModel *model;
33946 	GtkTreeIter iter;
33947 	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tPlotFunctions));
33948 	if(gtk_tree_selection_get_selected(select, &model, &iter)) {
33949 		string expression = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_expression")));
33950 		if(expression.find_first_not_of(SPACES) == string::npos) {
33951 			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_entry_expression")));
33952 			show_message(_("Empty expression."), GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_dialog")));
33953 			return;
33954 		}
33955 		gint type = 0, axis = 1, rows = 0;
33956 		string title = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_title")));
33957 		if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_radiobutton_vector")))) {
33958 			type = 1;
33959 		} else if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_radiobutton_paired")))) {
33960 			type = 2;
33961 		}
33962 		string str_x = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(plot_builder, "plot_entry_variable")));
33963 		remove_blank_ends(str_x);
33964 		if(str_x.empty() && type == 0) {
33965 			gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_entry_variable")));
33966 			show_message(_("Empty x variable."), GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_dialog")));
33967 			return;
33968 		}
33969 		if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_radiobutton_yaxis2")))) {
33970 			axis = 2;
33971 		}
33972 		if((type == 1 || type == 2) && title.empty()) {
33973 			Variable *v = CALCULATOR->getActiveVariable(expression);
33974 			if(v) {
33975 				title = v->title(false);
33976 			}
33977 		}
33978 		MathStructure *x_vector, *y_vector;
33979 		gtk_tree_model_get(GTK_TREE_MODEL(tPlotFunctions_store), &iter, 7, &x_vector, 8, &y_vector, -1);
33980 		if(x_vector) delete x_vector;
33981 		if(y_vector) delete y_vector;
33982 		x_vector = NULL;
33983 		y_vector = NULL;
33984 		generate_plot_series(&x_vector, &y_vector, type, expression, str_x);
33985 		rows = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(plot_builder, "plot_checkbutton_rows")));
33986 		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);
33987 		gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_entry_expression")));
33988 		update_plot();
33989 	}
33990 }
on_plot_button_remove_clicked(GtkButton *,gpointer)33991 void on_plot_button_remove_clicked(GtkButton*, gpointer) {
33992 	GtkTreeModel *model;
33993 	GtkTreeIter iter;
33994 	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tPlotFunctions));
33995 	if(gtk_tree_selection_get_selected(select, &model, &iter)) {
33996 		MathStructure *x_vector, *y_vector;
33997 		gtk_tree_model_get(GTK_TREE_MODEL(tPlotFunctions_store), &iter, 7, &x_vector, 8, &y_vector, -1);
33998 		if(x_vector) delete x_vector;
33999 		if(y_vector) delete y_vector;
34000 		gtk_list_store_remove(tPlotFunctions_store, &iter);
34001 		gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_entry_expression")));
34002 		update_plot();
34003 	}
34004 }
34005 
on_plot_checkbutton_xlog_toggled(GtkToggleButton * w,gpointer)34006 void on_plot_checkbutton_xlog_toggled(GtkToggleButton *w, gpointer) {
34007 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_spinbutton_xlog_base")), gtk_toggle_button_get_active(w));
34008 }
on_plot_checkbutton_ylog_toggled(GtkToggleButton * w,gpointer)34009 void on_plot_checkbutton_ylog_toggled(GtkToggleButton *w, gpointer) {
34010 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_spinbutton_ylog_base")), gtk_toggle_button_get_active(w));
34011 }
on_plot_checkbutton_ymin_toggled(GtkToggleButton * w,gpointer)34012 void on_plot_checkbutton_ymin_toggled(GtkToggleButton *w, gpointer) {
34013 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_spinbutton_ymin")), gtk_toggle_button_get_active(w));
34014 }
on_plot_checkbutton_ymax_toggled(GtkToggleButton * w,gpointer)34015 void on_plot_checkbutton_ymax_toggled(GtkToggleButton *w, gpointer) {
34016 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_spinbutton_ymax")), gtk_toggle_button_get_active(w));
34017 }
on_plot_radiobutton_step_toggled(GtkToggleButton * w,gpointer)34018 void on_plot_radiobutton_step_toggled(GtkToggleButton *w, gpointer) {
34019 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_entry_step")), gtk_toggle_button_get_active(w));
34020 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_spinbutton_steps")), !gtk_toggle_button_get_active(w));
34021 }
on_plot_radiobutton_steps_toggled(GtkToggleButton * w,gpointer)34022 void on_plot_radiobutton_steps_toggled(GtkToggleButton *w, gpointer) {
34023 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_entry_step")), !gtk_toggle_button_get_active(w));
34024 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_spinbutton_steps")), gtk_toggle_button_get_active(w));
34025 }
on_plot_entry_expression_activate(GtkEntry *,gpointer)34026 void on_plot_entry_expression_activate(GtkEntry*, gpointer) {
34027 	GtkTreeModel *model;
34028 	GtkTreeIter iter;
34029 	GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tPlotFunctions));
34030 	if(gtk_tree_selection_get_selected(select, &model, &iter)) {
34031 		on_plot_button_modify_clicked(GTK_BUTTON(gtk_builder_get_object(plot_builder, "plot_button_modify")), NULL);
34032 	} else {
34033 		on_plot_button_add_clicked(GTK_BUTTON(gtk_builder_get_object(plot_builder, "plot_button_add")), NULL);
34034 	}
34035 }
on_plot_entry_expression_key_press_event(GtkWidget * o,GdkEventKey * event,gpointer)34036 gboolean on_plot_entry_expression_key_press_event(GtkWidget *o, GdkEventKey *event, gpointer) {
34037 	const gchar *key = key_press_get_symbol(event, false);
34038 	if(!key) return FALSE;
34039 	if(strlen(key) > 0) entry_insert_text(o, key);
34040 	return TRUE;
34041 }
34042 
on_plot_radiobutton_function_toggled(GtkToggleButton * w,gpointer)34043 void on_plot_radiobutton_function_toggled(GtkToggleButton *w, gpointer) {
34044 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_box_variable")), gtk_toggle_button_get_active(w));
34045 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_checkbutton_rows")), !gtk_toggle_button_get_active(w));
34046 }
on_plot_radiobutton_vector_toggled(GtkToggleButton * w,gpointer)34047 void on_plot_radiobutton_vector_toggled(GtkToggleButton *w, gpointer) {
34048 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_box_variable")), !gtk_toggle_button_get_active(w));
34049 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_checkbutton_rows")), gtk_toggle_button_get_active(w));
34050 }
on_plot_radiobutton_paired_toggled(GtkToggleButton * w,gpointer)34051 void on_plot_radiobutton_paired_toggled(GtkToggleButton *w, gpointer) {
34052 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_box_variable")), !gtk_toggle_button_get_active(w));
34053 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(plot_builder, "plot_checkbutton_rows")), gtk_toggle_button_get_active(w));
34054 }
on_plot_button_range_apply_clicked(GtkButton *,gpointer)34055 void on_plot_button_range_apply_clicked(GtkButton*, gpointer) {
34056 	GtkTreeIter iter;
34057 	bool b = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tPlotFunctions_store), &iter);
34058 	while(b) {
34059 		gchar *gstr2, *gstr3;
34060 		gint type = 0;
34061 		MathStructure *y_vector, *x_vector;
34062 		gtk_tree_model_get(GTK_TREE_MODEL(tPlotFunctions_store), &iter, 1, &gstr2, 4, &type, 7, &x_vector, 8, &y_vector, 9, &gstr3, -1);
34063 		if(y_vector) delete y_vector;
34064 		if(x_vector) delete x_vector;
34065 		x_vector = NULL;
34066 		y_vector = NULL;
34067 		generate_plot_series(&x_vector, &y_vector, type, gstr2, gstr3);
34068 		g_free(gstr2);
34069 		g_free(gstr3);
34070 		gtk_list_store_set(tPlotFunctions_store, &iter, 7, x_vector, 8, y_vector, -1);
34071 		b = gtk_tree_model_iter_next(GTK_TREE_MODEL(tPlotFunctions_store), &iter);
34072 	}
34073 	update_plot();
34074 }
on_plot_button_appearance_apply_clicked(GtkButton *,gpointer)34075 void on_plot_button_appearance_apply_clicked(GtkButton*, gpointer) {
34076 	update_plot();
34077 }
34078 
convert_from_convert_entry_unit()34079 void convert_from_convert_entry_unit() {
34080 	do_timeout = false;
34081 	ParseOptions pa = evalops.parse_options; pa.base = 10;
34082 	string ceu_str = CALCULATOR->unlocalizeExpression(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(main_builder, "convert_entry_unit"))), pa);
34083 	if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(main_builder, "convert_button_set_missing_prefixes"))) && !ceu_str.empty()) {
34084 		remove_blank_ends(ceu_str);
34085 		if(!ceu_str.empty() && ceu_str[0] != '0' && ceu_str[0] != '?' && ceu_str[0] != '+' && ceu_str[0] != '-' && (ceu_str.length() == 1 || ceu_str[1] != '?')) {
34086 			ceu_str = "?" + ceu_str;
34087 		}
34088 	}
34089 	bool b_puup = printops.use_unit_prefixes;
34090 	to_prefix = 0;
34091 	printops.use_unit_prefixes = true;
34092 	block_conversion_category_switch++;
34093 	executeCommand(COMMAND_CONVERT_STRING, true, ceu_str);
34094 	block_conversion_category_switch--;
34095 	printops.use_unit_prefixes = b_puup;
34096 	do_timeout = true;
34097 }
on_convert_button_set_missing_prefixes_toggled(GtkToggleButton * w,gpointer)34098 void on_convert_button_set_missing_prefixes_toggled(GtkToggleButton *w, gpointer) {
34099 	if(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(main_builder, "convert_entry_unit"))) != 0) {
34100 		convert_from_convert_entry_unit();
34101 	}
34102 }
on_convert_button_convert_clicked(GtkButton *,gpointer)34103 void on_convert_button_convert_clicked(GtkButton*, gpointer) {
34104 	convert_from_convert_entry_unit();
34105 	focus_keeping_selection();
34106 }
on_convert_entry_unit_activate(GtkEntry *,gpointer)34107 void on_convert_entry_unit_activate(GtkEntry*, gpointer) {
34108 	convert_from_convert_entry_unit();
34109 	focus_keeping_selection();
34110 }
34111 
34112 vector<GtkWidget*> ewindows;
34113 vector<DataObject*> eobjects;
34114 
on_element_button_function_clicked(GtkButton * w,gpointer user_data)34115 void on_element_button_function_clicked(GtkButton *w, gpointer user_data) {
34116 	DataProperty *dp = (DataProperty*) user_data;
34117 	DataSet *ds = NULL;
34118 	DataObject *o = NULL;
34119 	GtkWidget *win = gtk_widget_get_toplevel(GTK_WIDGET(w));
34120 	for(size_t i = 0; i < ewindows.size(); i++) {
34121 		if(ewindows[i] == win) {
34122 			o = eobjects[i];
34123 			break;
34124 		}
34125 	}
34126 	if(dp) ds = dp->parentSet();
34127 	if(ds && o) {
34128 		string str = ds->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressiontext).name;
34129 		str += "(";
34130 		str += o->getProperty(ds->getPrimaryKeyProperty());
34131 		str += CALCULATOR->getComma();
34132 		str += " ";
34133 		str += dp->getName();
34134 		str += ")";
34135 		insert_text(str.c_str());
34136 	}
34137 }
on_element_button_close_clicked(GtkButton * w,gpointer user_data)34138 void on_element_button_close_clicked(GtkButton *w, gpointer user_data) {
34139 	GtkWidget *win = gtk_widget_get_toplevel(GTK_WIDGET(w));
34140 	for(size_t i = 0; i < ewindows.size(); i++) {
34141 		if(ewindows[i] == win) {
34142 			ewindows.erase(ewindows.begin() + i);
34143 			eobjects.erase(eobjects.begin() + i);
34144 			break;
34145 		}
34146 	}
34147 	gtk_widget_destroy((GtkWidget*) user_data);
34148 }
on_element_button_clicked(GtkButton *,gpointer user_data)34149 void on_element_button_clicked(GtkButton*, gpointer user_data) {
34150 	DataObject *e = (DataObject*) user_data;
34151 	if(e) {
34152 		DataSet *ds = e->parentSet();
34153 		if(!ds) return;
34154 		GtkWidget *dialog = gtk_dialog_new();
34155 		ewindows.push_back(dialog);
34156 		eobjects.push_back(e);
34157 		GtkWidget *close_button = gtk_dialog_add_button(GTK_DIALOG(dialog), _("_Close"), GTK_RESPONSE_CLOSE);
34158 		g_signal_connect(G_OBJECT(close_button), "clicked", G_CALLBACK(on_element_button_close_clicked), (gpointer) dialog);
34159 		gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gtk_builder_get_object(periodictable_builder, "periodic_dialog")));
34160 		gtk_window_set_title(GTK_WINDOW(dialog), _("Element Data"));
34161 		gtk_container_set_border_width(GTK_CONTAINER(dialog), 6);
34162 		GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12);
34163 		gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
34164 		gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), vbox);
34165 
34166 		GtkWidget *vbox2 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
34167 		gtk_box_pack_start(GTK_BOX(vbox), vbox2, FALSE, TRUE, 0);
34168 
34169 		DataProperty *p_number = ds->getProperty("number");
34170 		DataProperty *p_symbol = ds->getProperty("symbol");
34171 		DataProperty *p_class = ds->getProperty("class");
34172 		DataProperty *p_name = ds->getProperty("name");
34173 
34174 		GtkWidget *label;
34175 		label = gtk_label_new(NULL);
34176 		string str = "<span size=\"large\">"; str += e->getProperty(p_number); str += "</span>";
34177 		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);
34178 		gtk_box_pack_start(GTK_BOX(vbox2), label, FALSE, TRUE, 0);
34179 		label = gtk_label_new(NULL);
34180 		str = "<span size=\"xx-large\">"; str += e->getProperty(p_symbol); str += "</span>";
34181 		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);
34182 		gtk_box_pack_start(GTK_BOX(vbox2), label, FALSE, TRUE, 0);
34183 		label = gtk_label_new(NULL);
34184 		str = "<span size=\"x-large\">"; str += e->getProperty(p_name); str += "</span>  ";
34185 		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);
34186 		gtk_box_pack_start(GTK_BOX(vbox2), label, FALSE, TRUE, 0);
34187 
34188 		GtkWidget *button;
34189 		GtkWidget *ptable = gtk_grid_new();
34190 		gtk_grid_set_column_spacing(GTK_GRID(ptable), 6);
34191 		gtk_box_pack_start(GTK_BOX(vbox), ptable, FALSE, TRUE, 0);
34192 		int rows = 0;
34193 
34194 		int group = s2i(e->getProperty(p_class));
34195 		if(group > 0) {
34196 			rows++;
34197 			label = gtk_label_new(NULL);
34198 			str = "<span weight=\"bold\">"; str += _("Classification"); str += ":"; str += "</span>";
34199 			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);
34200 			gtk_grid_attach(GTK_GRID(ptable), label, 0, rows - 1, 1, 1);
34201 			label = gtk_label_new(NULL);
34202 			switch(group) {
34203 				case ALKALI_METALS: {gtk_label_set_markup(GTK_LABEL(label), _("Alkali Metal")); break;}
34204 				case ALKALI_EARTH_METALS: {gtk_label_set_markup(GTK_LABEL(label), _("Alkaline-Earth Metal")); break;}
34205 				case LANTHANIDES: {gtk_label_set_markup(GTK_LABEL(label), _("Lanthanide")); break;}
34206 				case ACTINIDES: {gtk_label_set_markup(GTK_LABEL(label), _("Actinide")); break;}
34207 				case TRANSITION_METALS: {gtk_label_set_markup(GTK_LABEL(label), _("Transition Metal")); break;}
34208 				case METALS: {gtk_label_set_markup(GTK_LABEL(label), _("Metal")); break;}
34209 				case METALLOIDS: {gtk_label_set_markup(GTK_LABEL(label), _("Metalloid")); break;}
34210 				case NONMETALS: {gtk_label_set_markup(GTK_LABEL(label), _("Polyatomic Non-Metal")); break;}
34211 				case HALOGENS: {gtk_label_set_markup(GTK_LABEL(label), _("Diatomic Non-Metal")); break;}
34212 				case NOBLE_GASES: {gtk_label_set_markup(GTK_LABEL(label), _("Noble Gas")); break;}
34213 				case TRANSACTINIDES: {gtk_label_set_markup(GTK_LABEL(label), _("Unknown chemical properties")); break;}
34214 				default: {gtk_label_set_markup(GTK_LABEL(label), _("Unknown")); break;}
34215 			}
34216 			gtk_widget_set_halign(label, GTK_ALIGN_START); gtk_label_set_selectable(GTK_LABEL(label), TRUE);
34217 #if GTK_MAJOR_VERSION > 3 || GTK_MINOR_VERSION >= 12
34218 			gtk_widget_set_margin_end(label, 10);
34219 #else
34220 			gtk_widget_set_margin_right(label, 10);
34221 #endif
34222 			gtk_grid_attach(GTK_GRID(ptable), label, 1, rows - 1, 1, 1);
34223 		}
34224 
34225 		DataPropertyIter it;
34226 		DataProperty *dp = ds->getFirstProperty(&it);
34227 		string sval;
34228 		while(dp) {
34229 			if(!dp->isHidden() && dp != p_number && dp != p_class && dp != p_symbol && dp != p_name) {
34230 				sval = e->getPropertyDisplayString(dp);
34231 				if(!sval.empty()) {
34232 					rows++;
34233 					label = gtk_label_new(NULL);
34234 					str = "<span weight=\"bold\">"; str += dp->title(); str += ":"; str += "</span>";
34235 					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);
34236 					gtk_grid_attach(GTK_GRID(ptable), label, 0, rows - 1, 1, 1);
34237 					label = gtk_label_new(NULL);
34238 					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);
34239 					gtk_grid_attach(GTK_GRID(ptable), label, 1, rows - 1, 1, 1);
34240 					button = gtk_button_new();
34241 					gtk_container_add(GTK_CONTAINER(button), gtk_image_new_from_icon_name("edit-paste", GTK_ICON_SIZE_BUTTON));
34242 					gtk_grid_attach(GTK_GRID(ptable), button, 2, rows - 1, 1, 1);
34243 					g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(on_element_button_function_clicked), (gpointer) dp);
34244 				}
34245 			}
34246 			dp = ds->getNextProperty(&it);
34247 		}
34248 
34249 		gtk_widget_show_all(dialog);
34250 
34251 	}
34252 }
34253 
on_dataset_edit_entry_name_changed(GtkEditable * editable,gpointer)34254 void on_dataset_edit_entry_name_changed(GtkEditable *editable, gpointer) {
34255 	correct_name_entry(editable, TYPE_FUNCTION,  (gpointer) on_dataset_edit_entry_name_changed);
34256 }
on_dataset_edit_button_new_property_clicked(GtkButton *,gpointer)34257 void on_dataset_edit_button_new_property_clicked(GtkButton*, gpointer) {
34258 	DataProperty *dp = new DataProperty(edited_dataset);
34259 	dp->setUserModified(true);
34260 	if(edit_dataproperty(dp, true)) {
34261 		tmp_props.push_back(dp);
34262 		tmp_props_orig.push_back(NULL);
34263 		update_dataset_property_list(edited_dataset);
34264 		on_dataset_changed();
34265 	} else {
34266 		delete dp;
34267 	}
34268 }
on_dataset_edit_button_edit_property_clicked(GtkButton *,gpointer)34269 void on_dataset_edit_button_edit_property_clicked(GtkButton*, gpointer) {
34270 	if(selected_dataproperty) {
34271 		if(edit_dataproperty(selected_dataproperty, false)) {
34272 			update_dataset_property_list(edited_dataset);
34273 			on_dataset_changed();
34274 		}
34275 	}
34276 }
on_dataset_edit_button_del_property_clicked(GtkButton *,gpointer)34277 void on_dataset_edit_button_del_property_clicked(GtkButton*, gpointer) {
34278 	if(edited_dataset && selected_dataproperty && selected_dataproperty->isUserModified()) {
34279 		for(size_t i = 0; i < tmp_props.size(); i++) {
34280 			if(tmp_props[i] == selected_dataproperty) {
34281 				if(tmp_props_orig[i]) {
34282 					tmp_props[i] = NULL;
34283 				} else {
34284 					tmp_props.erase(tmp_props.begin() + i);
34285 					tmp_props_orig.erase(tmp_props_orig.begin() + i);
34286 				}
34287 				break;
34288 			}
34289 		}
34290 		update_dataset_property_list(edited_dataset);
34291 		on_dataset_changed();
34292 	}
34293 }
on_dataset_edit_button_names_clicked(GtkButton *,gpointer)34294 void on_dataset_edit_button_names_clicked(GtkButton*, gpointer) {
34295 	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")));
34296 	SET_NAMES_LE(datasetedit_builder, "dataset_edit_entry_name", "dataset_edit_label_names")
34297 }
34298 
on_dataproperty_edit_button_names_clicked(GtkButton *,gpointer)34299 void on_dataproperty_edit_button_names_clicked(GtkButton*, gpointer) {
34300 	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());
34301 	SET_NAMES_LE(datasetedit_builder, "dataproperty_edit_entry_name", "dataproperty_edit_label_names")
34302 }
34303 
on_menu_item_set_unknowns_activate(GtkMenuItem *,gpointer)34304 void on_menu_item_set_unknowns_activate(GtkMenuItem*, gpointer) {
34305 	if(expression_has_changed && !expression_is_empty() && !rpn_mode) execute_expression(true);
34306 	MathStructure unknowns;
34307 	mstruct->findAllUnknowns(unknowns);
34308 	if(unknowns.size() == 0) {
34309 		show_message(_("No unknowns in result."), GTK_WIDGET(gtk_builder_get_object(main_builder, "main_window")));
34310 		return;
34311 	}
34312 	unknowns.setType(STRUCT_ADDITION);
34313 	unknowns.sort();
34314 
34315 	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), _("_Cancel"), GTK_RESPONSE_REJECT, _("_Apply"), GTK_RESPONSE_APPLY, _("_OK"), GTK_RESPONSE_ACCEPT, NULL);
34316 	gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_MOUSE);
34317 	gtk_container_set_border_width(GTK_CONTAINER(dialog), 6);
34318 	GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6);
34319 	gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
34320 	gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), vbox);
34321 	GtkWidget *label;
34322 	vector<GtkWidget*> entry;
34323 	entry.resize(unknowns.size(), NULL);
34324 	GtkWidget *ptable = gtk_grid_new();
34325 	gtk_grid_set_column_spacing(GTK_GRID(ptable), 6);
34326 	gtk_grid_set_row_spacing(GTK_GRID(ptable), 6);
34327 	gtk_box_pack_start(GTK_BOX(vbox), ptable, FALSE, TRUE, 0);
34328 	int rows = 0;
34329 	for(size_t i = 0; i < unknowns.size(); i++) {
34330 		rows++;
34331 		label = gtk_label_new(unknowns[i].print().c_str());
34332 		gtk_widget_set_halign(label, GTK_ALIGN_START);
34333 		gtk_grid_attach(GTK_GRID(ptable), label, 0, rows - 1, 1, 1);
34334 		entry[i] = gtk_entry_new();
34335 		g_signal_connect(G_OBJECT(entry[i]), "key-press-event", G_CALLBACK(on_math_entry_key_press_event), NULL);
34336 		gtk_widget_set_hexpand(entry[i], TRUE);
34337 		gtk_grid_attach(GTK_GRID(ptable), entry[i], 1, rows - 1, 1, 1);
34338 	}
34339 	MathStructure msave(*mstruct);
34340 	string result_save = get_result_text();
34341 	gtk_widget_show_all(dialog);
34342 	bool b_changed = false;
34343 	vector<string> unknown_text;
34344 	unknown_text.resize(unknowns.size());
34345 	while(true) {
34346 		gint response = gtk_dialog_run(GTK_DIALOG(dialog));
34347 		bool b1 = false, b2 = false;
34348 		if(response == GTK_RESPONSE_ACCEPT || response == GTK_RESPONSE_APPLY) {
34349 			string str, result_mod = "";
34350 			do_timeout = false;
34351 			for(size_t i = 0; i < unknowns.size(); i++) {
34352 				str = gtk_entry_get_text(GTK_ENTRY(entry[i]));
34353 				remove_blank_ends(str);
34354 				if(((b1 || !b_changed) && !str.empty()) || (b_changed && unknown_text[i] != str)) {
34355 					if(!result_mod.empty()) {
34356 						result_mod += CALCULATOR->getComma();
34357 						result_mod += " ";
34358 					} else {
34359 						b1 = true;
34360 						mstruct->set(msave);
34361 						for(size_t i2 = 0; i2 < i; i2++) {
34362 							if(!unknown_text[i2].empty()) {
34363 								mstruct->replace(unknowns[i2], CALCULATOR->parse(CALCULATOR->unlocalizeExpression(unknown_text[i2], evalops.parse_options), evalops.parse_options));
34364 								b2 = true;
34365 							}
34366 						}
34367 					}
34368 					result_mod += unknowns[i].print().c_str();
34369 					result_mod += "=";
34370 					if(str.empty()) {
34371 						result_mod += "?";
34372 					} else {
34373 						result_mod += str;
34374 						mstruct->replace(unknowns[i], CALCULATOR->parse(CALCULATOR->unlocalizeExpression(str, evalops.parse_options), evalops.parse_options));
34375 						b2 = true;
34376 					}
34377 					unknown_text[i] = str;
34378 				}
34379 			}
34380 			if(response == GTK_RESPONSE_ACCEPT) {
34381 				gtk_widget_destroy(dialog);
34382 			}
34383 			if(b2) {
34384 				b_changed = true;
34385 				if(response != GTK_RESPONSE_ACCEPT) {
34386 					gtk_window_set_modal(GTK_WINDOW(dialog), FALSE);
34387 					gtk_widget_set_sensitive(GTK_WIDGET(dialog), FALSE);
34388 				}
34389 				executeCommand(COMMAND_TRANSFORM, true, result_mod);
34390 			} else if(b1) {
34391 				b_changed = false;
34392 				printops.allow_factorization = (evalops.structuring == STRUCTURING_FACTORIZE);
34393 				setResult(NULL, true, false, false, result_mod);
34394 			}
34395 			do_timeout = true;
34396 			if(response == GTK_RESPONSE_ACCEPT) {
34397 				break;
34398 			}
34399 			gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
34400 			gtk_widget_set_sensitive(GTK_WIDGET(dialog), TRUE);
34401 		} else {
34402 			if(b_changed && response == GTK_RESPONSE_REJECT) {
34403 				string result_mod = "";
34404 				mstruct->set(msave);
34405 				for(size_t i = 0; i < unknowns.size(); i++) {
34406 					if(!unknown_text[i].empty()) {
34407 						if(!result_mod.empty()) {
34408 							result_mod += CALCULATOR->getComma();
34409 							result_mod += " ";
34410 						}
34411 						result_mod += unknowns[i].print().c_str();
34412 						result_mod += "=";
34413 						result_mod += "?";
34414 					}
34415 				}
34416 				printops.allow_factorization = (evalops.structuring == STRUCTURING_FACTORIZE);
34417 				setResult(NULL, true, false, false, result_mod);
34418 			}
34419 			gtk_widget_destroy(dialog);
34420 			break;
34421 		}
34422 	}
34423 }
34424 
34425 #ifdef __cplusplus
34426 }
34427 #endif
34428 
34429