diff --git a/src/MainWindow.vala b/src/MainWindow.vala index 12cd0bbc..665e76c7 100644 --- a/src/MainWindow.vala +++ b/src/MainWindow.vala @@ -20,6 +20,47 @@ public class PantheonCalculator.MainWindow : Gtk.ApplicationWindow { private static GLib.Settings settings; + private Gdk.Clipboard clipboard; + private Gtk.EventControllerKey event_controller; + + private Button button_0; + private Button button_1; + private Button button_2; + private Button button_3; + private Button button_4; + private Button button_5; + private Button button_6; + private Button button_7; + private Button button_8; + private Button button_9; + private Button button_add; + private Button button_sub; + private Button button_mult; + private Button button_div; + private Button button_point; + private Button button_percent; + private Button button_clr; + private Button button_par_left; + private Button button_par_right; + private Button button_pow; + private Button button_sr; + private Button button_sin; + private Button button_sinh; + private Button button_cos; + private Button button_cosh; + private Button button_tan; + private Button button_tanh; + private Button button_pi; + private Button button_e; + private Button button_log; + private Button button_ln; + private Button button_asin; + private Button button_acos; + private Button button_atan; + private Button button_reciprocal; + private Button button_m_add; + private Button button_m_sub; + private Button button_ms; private Gtk.Revealer extended_revealer; private Gtk.Entry entry; @@ -76,7 +117,6 @@ public class PantheonCalculator.MainWindow : Gtk.ApplicationWindow { add_action_entries (ACTION_ENTRIES, this); var application_instance = (Gtk.Application) GLib.Application.get_default (); - application_instance.set_accels_for_action (ACTION_PREFIX + ACTION_CLEAR, {"Escape"}); application_instance.set_accels_for_action (ACTION_PREFIX + ACTION_UNDO, {"z"}); application_instance.set_accels_for_action (ACTION_PREFIX + ACTION_COPY, {"c"}); application_instance.set_accels_for_action (ACTION_PREFIX + ACTION_PASTE, {"v"}); @@ -84,6 +124,12 @@ public class PantheonCalculator.MainWindow : Gtk.ApplicationWindow { resizable = false; title = _("Calculator"); + var display = Gdk.Display.get_default (); + clipboard = display.get_clipboard (); + + event_controller = new Gtk.EventControllerKey (); + event_controller.key_pressed.connect (on_key_press); + decimal_places = settings.get_int ("decimal-places"); eval = new Core.Evaluation (); @@ -115,9 +161,11 @@ public class PantheonCalculator.MainWindow : Gtk.ApplicationWindow { entry = new Gtk.Entry () { xalign = 1, vexpand = true, + sensitive = false, valign = Gtk.Align.FILL }; entry.add_css_class (Granite.STYLE_CLASS_H2_LABEL); + entry.set_placeholder_text ("0"); button_calc = new Button ("=") { tooltip_text = _("Calculate Result") @@ -134,7 +182,7 @@ public class PantheonCalculator.MainWindow : Gtk.ApplicationWindow { tooltip_text = _("Backspace") }; - var button_clr = new Button ("C") { + button_clr = new Button ("C") { action_name = ACTION_PREFIX + ACTION_CLEAR }; button_clr.tooltip_markup = Granite.markup_accel_tooltip ( @@ -143,91 +191,91 @@ public class PantheonCalculator.MainWindow : Gtk.ApplicationWindow { ); button_clr.add_css_class (Granite.STYLE_CLASS_DESTRUCTIVE_ACTION); - var button_add = new Button (" + ") { + button_add = new Button (" + ") { action_name = ACTION_PREFIX + ACTION_INSERT, action_target = new Variant.string ("+"), tooltip_text = _("Add") }; button_add.add_css_class (Granite.STYLE_CLASS_H3_LABEL); - var button_sub = new Button (" − ") { + button_sub = new Button (" − ") { action_name = ACTION_PREFIX + ACTION_INSERT, action_target = new Variant.string ("-"), tooltip_text = _("Subtract") }; button_sub.add_css_class (Granite.STYLE_CLASS_H3_LABEL); - var button_mult = new Button (" × ") { + button_mult = new Button (" × ") { action_name = ACTION_PREFIX + ACTION_INSERT, action_target = new Variant.string ("×"), tooltip_text = _("Multiply") }; button_mult.add_css_class (Granite.STYLE_CLASS_H3_LABEL); - var button_div = new Button (" ÷ ") { + button_div = new Button (" ÷ ") { action_name = ACTION_PREFIX + ACTION_INSERT, action_target = new Variant.string ("÷"), tooltip_text = _("Divide") }; button_div.add_css_class (Granite.STYLE_CLASS_H3_LABEL); - var button_0 = new Button ("0") { + button_0 = new Button ("0") { action_name = ACTION_PREFIX + ACTION_INSERT, action_target = new Variant.string ("0") }; - var button_point = new Button (Posix.nl_langinfo (Posix.NLItem.RADIXCHAR)) { + button_point = new Button (Posix.nl_langinfo (Posix.NLItem.RADIXCHAR)) { action_name = ACTION_PREFIX + ACTION_INSERT, action_target = new Variant.string (Posix.nl_langinfo (Posix.NLItem.RADIXCHAR)) }; - var button_percent = new Button ("%") { + button_percent = new Button ("%") { action_name = ACTION_PREFIX + ACTION_INSERT, action_target = new Variant.string ("%"), tooltip_text = _("Percentage") }; - var button_1 = new Button ("1") { + button_1 = new Button ("1") { action_name = ACTION_PREFIX + ACTION_INSERT, action_target = new Variant.string ("1") }; - var button_2 = new Button ("2") { + button_2 = new Button ("2") { action_name = ACTION_PREFIX + ACTION_INSERT, action_target = new Variant.string ("2") }; - var button_3 = new Button ("3") { + button_3 = new Button ("3") { action_name = ACTION_PREFIX + ACTION_INSERT, action_target = new Variant.string ("3") }; - var button_4 = new Button ("4") { + button_4 = new Button ("4") { action_name = ACTION_PREFIX + ACTION_INSERT, action_target = new Variant.string ("4") }; - var button_5 = new Button ("5") { + button_5 = new Button ("5") { action_name = ACTION_PREFIX + ACTION_INSERT, action_target = new Variant.string ("5") }; - var button_6 = new Button ("6") { + button_6 = new Button ("6") { action_name = ACTION_PREFIX + ACTION_INSERT, action_target = new Variant.string ("6") }; - var button_7 = new Button ("7") { + button_7 = new Button ("7") { action_name = ACTION_PREFIX + ACTION_INSERT, action_target = new Variant.string ("7") }; - var button_8 = new Button ("8") { + button_8 = new Button ("8") { action_name = ACTION_PREFIX + ACTION_INSERT, action_target = new Variant.string ("8") }; - var button_9 = new Button ("9") { + button_9 = new Button ("9") { action_name = ACTION_PREFIX + ACTION_INSERT, action_target = new Variant.string ("9") }; @@ -265,7 +313,7 @@ public class PantheonCalculator.MainWindow : Gtk.ApplicationWindow { basic_grid.attach (button_ans, 2, 5, 1, 1); basic_grid.attach (button_calc, 3, 5, 1, 1); - var button_ms = new Button ("MS") { + button_ms = new Button ("MS") { tooltip_text = _("Set memory value") }; @@ -274,11 +322,11 @@ public class PantheonCalculator.MainWindow : Gtk.ApplicationWindow { tooltip_text = _("Recall value from memory") }; - var button_m_add = new Button ("M+") { + button_m_add = new Button ("M+") { tooltip_text = _("Add to stored value") }; - var button_m_sub = new Button ("M−") { + button_m_sub = new Button ("M−") { tooltip_text = _("Subtract from stored value") }; @@ -292,109 +340,109 @@ public class PantheonCalculator.MainWindow : Gtk.ApplicationWindow { tooltip_text = _("Grand Total") }; - var button_par_left = new Button ("(") { + button_par_left = new Button ("(") { action_name = ACTION_PREFIX + ACTION_INSERT, action_target = new Variant.string ("("), tooltip_text = _("Start Group") }; - var button_par_right = new Button (")") { + button_par_right = new Button (")") { action_name = ACTION_PREFIX + ACTION_INSERT, action_target = new Variant.string (")"), tooltip_text = _("End Group") }; - var button_pow = new Button ("xy") { + button_pow = new Button ("xy") { action_name = ACTION_PREFIX + ACTION_INSERT, action_target = new Variant.string ("^"), tooltip_text = _("Exponent") }; - var button_sr = new Button ("√") { + button_sr = new Button ("√") { action_name = ACTION_PREFIX + ACTION_FUNCTION, action_target = new Variant.string ("√"), tooltip_text = _("Root") }; - var button_sin = new Button ("sin") { + button_sin = new Button ("sin") { action_name = ACTION_PREFIX + ACTION_FUNCTION, action_target = new Variant.string ("sin"), tooltip_text = _("Sine") }; - var button_sinh = new Button ("sinh") { + button_sinh = new Button ("sinh") { action_name = ACTION_PREFIX + ACTION_FUNCTION, action_target = new Variant.string ("sinh"), tooltip_text = _("Hyperbolic Sine") }; - var button_cos = new Button ("cos") { + button_cos = new Button ("cos") { action_name = ACTION_PREFIX + ACTION_FUNCTION, action_target = new Variant.string ("cos"), tooltip_text = _("Cosine") }; - var button_cosh = new Button ("cosh") { + button_cosh = new Button ("cosh") { action_name = ACTION_PREFIX + ACTION_FUNCTION, action_target = new Variant.string ("cosh"), tooltip_text = _("Hyperbolic Cosine") }; - var button_tan = new Button ("tan") { + button_tan = new Button ("tan") { action_name = ACTION_PREFIX + ACTION_FUNCTION, action_target = new Variant.string ("tan"), tooltip_text = _("Tangent") }; - var button_tanh = new Button ("tanh") { + button_tanh = new Button ("tanh") { action_name = ACTION_PREFIX + ACTION_FUNCTION, action_target = new Variant.string ("tanh"), tooltip_text = _("Hyperbolic Tangent") }; - var button_pi = new Button ("π") { + button_pi = new Button ("π") { action_name = ACTION_PREFIX + ACTION_INSERT, action_target = new Variant.string ("π"), tooltip_text = _("Pi") }; - var button_e = new Button ("e") { + button_e = new Button ("e") { action_name = ACTION_PREFIX + ACTION_INSERT, action_target = new Variant.string ("e"), tooltip_text = _("Euler's Number") }; - var button_log = new Button ("log10") { + button_log = new Button ("log10") { action_name = ACTION_PREFIX + ACTION_FUNCTION, action_target = new Variant.string ("log"), tooltip_text = _("Logarithm Base 10") }; - var button_ln = new Button ("ln") { + button_ln = new Button ("ln") { action_name = ACTION_PREFIX + ACTION_FUNCTION, action_target = new Variant.string ("ln"), tooltip_text = _("Natural Logarithm") }; - var button_asin = new Button ("sin-1") { + button_asin = new Button ("sin-1") { action_name = ACTION_PREFIX + ACTION_FUNCTION, action_target = new Variant.string ("asin"), tooltip_text = _("Inverse Sine") }; - var button_acos = new Button ("cos-1") { + button_acos = new Button ("cos-1") { action_name = ACTION_PREFIX + ACTION_FUNCTION, action_target = new Variant.string ("acos"), tooltip_text = _("Inverse Cosine") }; - var button_atan = new Button ("tan-1") { + button_atan = new Button ("tan-1") { action_name = ACTION_PREFIX + ACTION_FUNCTION, action_target = new Variant.string ("atan"), tooltip_text = _("Inverse Tangent") }; - var button_reciprocal = new Button ("x-1") { + button_reciprocal = new Button ("x-1") { tooltip_text = _("Reciprocal") }; @@ -463,16 +511,11 @@ public class PantheonCalculator.MainWindow : Gtk.ApplicationWindow { var global_box = new Gtk.Box (Gtk.Orientation.VERTICAL, 0); global_box.append (infobar); global_box.append (main_grid); + ((Gtk.Widget) this).add_controller (event_controller); child = global_box; set_titlebar (headerbar); - entry.grab_focus (); - - entry.changed.connect (remove_error); - entry.activate.connect (button_calc_clicked); - entry.get_delegate ().insert_text.connect (replace_text); - button_calc.clicked.connect (() => {button_calc_clicked ();}); button_del.clicked.connect (() => {button_del_clicked ();}); button_ans.clicked.connect (() => {button_ans_clicked ();}); @@ -509,47 +552,33 @@ public class PantheonCalculator.MainWindow : Gtk.ApplicationWindow { } } - private void copy () { - int start, end; - entry.get_selection_bounds (out start, out end); - var text_selected = end - start != 0; - - // we have to copy text in both cases - // because seems like application action blocks entry's action - if (!text_selected) { - entry.get_clipboard ().set_text (entry.text); - } else { - entry.get_clipboard ().set_text (entry.text.slice (start, end)); + public void copy () { + if (entry.get_text () != "") { + try { + var output = eval.evaluate (entry.get_text (), decimal_places); + clipboard.set_text (output); + } catch (Core.OUT_ERROR e) { + infobar_label.label = e.message; + infobar.revealed = true; + } } } - private void paste () { - get_clipboard_text.begin ((obj, res) => { - var text = get_clipboard_text.end (res); - if (text == null) { - return; + public void paste () { + var cancellable = new GLib.Cancellable (); + clipboard.read_text_async.begin (cancellable, (source, res) => { + try { + var output = eval.evaluate (clipboard.read_text_async.end (res), decimal_places); + if (entry.get_text () != output) { + entry.set_text (output); + } + } catch (Error e) { + infobar_label.label = e.message; + infobar.revealed = true; } - - int start, end; - entry.get_selection_bounds (out start, out end); - - var before = entry.text.slice (0, start); - var after = entry.text.slice (end, entry.text_length); - - entry.text = before + text + after; - entry.set_position (before.char_count () + text.char_count ()); }); } - private async string? get_clipboard_text () { - try { - return yield entry.get_clipboard ().read_text_async (null); - } catch (Error e) { - warning (e.message); - return null; - } - } - private void action_insert (SimpleAction action, Variant? variant) { var token = variant.get_string (); int new_position = entry.get_position (); @@ -566,7 +595,6 @@ public class PantheonCalculator.MainWindow : Gtk.ApplicationWindow { entry.do_insert_text (token, -1, ref cursor_position); new_position += token.char_count (); - entry.grab_focus (); entry.set_position (new_position); } @@ -581,7 +609,6 @@ public class PantheonCalculator.MainWindow : Gtk.ApplicationWindow { entry.delete_text (selection_start, selection_end); entry.insert_text (function_call, -1, ref selection_start); new_position += function_call.char_count (); - entry.grab_focus (); entry.set_position (new_position); } else { activate_action (ACTION_INSERT, variant); @@ -613,7 +640,6 @@ public class PantheonCalculator.MainWindow : Gtk.ApplicationWindow { remove_error (); } - entry.grab_focus (); entry.set_position (position); } @@ -643,7 +669,6 @@ public class PantheonCalculator.MainWindow : Gtk.ApplicationWindow { entry.set_text (new_text); } - entry.grab_focus (); entry.set_position (position - 1); } @@ -755,10 +780,8 @@ public class PantheonCalculator.MainWindow : Gtk.ApplicationWindow { private void action_clear () { position = 0; entry.set_text (""); - set_focus (entry); remove_error (); - entry.grab_focus (); entry.set_position (position); } @@ -784,7 +807,6 @@ public class PantheonCalculator.MainWindow : Gtk.ApplicationWindow { extended_revealer.reveal_child = false; } /* Focusing button_calc because without a new focus it will cause weird window drawing problems. */ - entry.grab_focus (); entry.set_position (position); } @@ -818,7 +840,6 @@ public class PantheonCalculator.MainWindow : Gtk.ApplicationWindow { var cursor_position = entry.cursor_position; entry.do_insert_text (input, -1, ref cursor_position); position += input.length; - entry.grab_focus (); entry.set_position (position); } @@ -826,25 +847,95 @@ public class PantheonCalculator.MainWindow : Gtk.ApplicationWindow { infobar.revealed = false; } - private void replace_text (string new_text, int new_text_length, ref int position) { - var replacement_text = ""; - - switch (new_text) { - case ".": - case ",": - replacement_text = Posix.nl_langinfo (Posix.NLItem.RADIXCHAR); - break; - case "/": - replacement_text = "÷"; - break; - case "*": - replacement_text = "×"; - break; + private bool on_key_press (Gtk.EventControllerKey controller, uint keyval, uint keycode, Gdk.ModifierType mod_state) { + event_controller.forward (entry.get_delegate ()); + switch (keyval) { + case Gdk.Key.@0: + case Gdk.Key.KP_0: + button_0.activate (); + return true; + case Gdk.Key.@1: + case Gdk.Key.KP_1: + button_1.activate (); + return true; + case Gdk.Key.@2: + case Gdk.Key.KP_2: + button_2.activate (); + return true; + case Gdk.Key.@3: + case Gdk.Key.KP_3: + button_3.activate (); + return true; + case Gdk.Key.@4: + case Gdk.Key.KP_4: + button_4.activate (); + return true; + case Gdk.Key.@5: + case Gdk.Key.KP_5: + button_5.activate (); + return true; + case Gdk.Key.@6: + case Gdk.Key.KP_6: + button_6.activate (); + return true; + case Gdk.Key.@7: + case Gdk.Key.KP_7: + button_7.activate (); + return true; + case Gdk.Key.@8: + case Gdk.Key.KP_8: + button_8.activate (); + return true; + case Gdk.Key.@9: + case Gdk.Key.KP_9: + button_9.activate (); + return true; + case Gdk.Key.plus: + case Gdk.Key.KP_Add: + button_add.activate (); + return true; + case Gdk.Key.minus: + case Gdk.Key.KP_Subtract: + button_sub.activate (); + return true; + case Gdk.Key.asterisk: + case Gdk.Key.KP_Multiply: + button_mult.activate (); + return true; + case Gdk.Key.slash: + case Gdk.Key.KP_Divide: + button_div.activate (); + return true; + case Gdk.Key.period: + case Gdk.Key.decimalpoint: + case Gdk.Key.KP_Decimal: + button_point.activate (); + return true; + case Gdk.Key.BackSpace: + case Gdk.Key.KP_Delete: + button_del.activate (); + return true; + case Gdk.Key.equal: + case Gdk.Key.KP_Enter: + case Gdk.Key.KP_Equal: + button_calc.activate (); + return true; + case Gdk.Key.Escape: + button_clr.activate (); + return true; } - if (replacement_text != "" && replacement_text != new_text) { - entry.do_insert_text (replacement_text, entry.cursor_position + replacement_text.char_count (), ref position); - Signal.stop_emission_by_name ((void*) entry.get_delegate (), "insert-text"); + switch (keyval) { + case Gdk.Key.percent: + button_percent.activate (); + return true; + case Gdk.Key.parenleft: + button_par_left.activate (); + return true; + case Gdk.Key.parenright: + button_par_right.activate (); + return true; } + return Gdk.EVENT_PROPAGATE; } }