///////////////////////////////////////////////////////////////////////// // Copyright 2011-2018 Simon Schneegans // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ///////////////////////////////////////////////////////////////////////// namespace GnomePie { ///////////////////////////////////////////////////////////////////////// /// This window allows the selection of a hotkey. It is returned in form /// of a Trigger. Therefore it can be either a keyboard driven hotkey or /// a mouse based hotkey. ///////////////////////////////////////////////////////////////////////// public class TriggerSelectButton : Gtk.ToggleButton { ///////////////////////////////////////////////////////////////////// /// This signal is emitted when the user selects a new hot key. ///////////////////////////////////////////////////////////////////// public signal void on_select(Trigger trigger); ///////////////////////////////////////////////////////////////////// /// The currently contained Trigger. ///////////////////////////////////////////////////////////////////// private Trigger trigger = null; ///////////////////////////////////////////////////////////////////// /// True, if mouse buttons can be bound as well. ///////////////////////////////////////////////////////////////////// private bool enable_mouse = false; ///////////////////////////////////////////////////////////////////// /// These modifiers are ignored. ///////////////////////////////////////////////////////////////////// private Gdk.ModifierType lock_modifiers = Gdk.ModifierType.MOD2_MASK |Gdk.ModifierType.MOD4_MASK |Gdk.ModifierType.MOD5_MASK |Gdk.ModifierType.LOCK_MASK; ///////////////////////////////////////////////////////////////////// /// C'tor, constructs a new TriggerSelectButton. ///////////////////////////////////////////////////////////////////// public TriggerSelectButton(bool enable_mouse) { this.enable_mouse = enable_mouse; this.toggled.connect(() => { if (this.active) { this.set_label(_("Press a hotkey ...")); Gtk.grab_add(this); FocusGrabber.grab(this.get_window()); } }); this.button_press_event.connect(this.on_button_press); this.key_press_event.connect(this.on_key_press); this.set_trigger(new Trigger()); } ///////////////////////////////////////////////////////////////////// /// Makes the button display the given Trigger. ///////////////////////////////////////////////////////////////////// public void set_trigger(Trigger trigger) { this.trigger = trigger; this.set_label(trigger.label); } ///////////////////////////////////////////////////////////////////// /// Can be called to cancel the selection process. ///////////////////////////////////////////////////////////////////// private void cancel() { this.set_label(trigger.label); this.set_active(false); Gtk.grab_remove(this); FocusGrabber.ungrab(); } ///////////////////////////////////////////////////////////////////// /// Makes the button display the given Trigger. ///////////////////////////////////////////////////////////////////// private void update_trigger(Trigger trigger) { if (this.trigger.name != trigger.name) { this.set_trigger(trigger); this.on_select(this.trigger); } this.cancel(); } ///////////////////////////////////////////////////////////////////// /// Called when the user presses a keyboard key. ///////////////////////////////////////////////////////////////////// private bool on_key_press(Gdk.EventKey event) { if (this.active) { if (Gdk.keyval_name(event.keyval) == "Escape") { this.cancel(); } else if (Gdk.keyval_name(event.keyval) == "BackSpace") { this.update_trigger(new Trigger()); } else if (event.is_modifier == 0) { Gdk.ModifierType state = event.state & ~ this.lock_modifiers; this.update_trigger(new Trigger.from_values(event.keyval, state, false, false, false, false, false, 5)); } return true; } return false; } ///////////////////////////////////////////////////////////////////// /// Called when the user presses a button of the mouse. ///////////////////////////////////////////////////////////////////// private bool on_button_press(Gdk.EventButton event) { if (this.active) { Gtk.Allocation rect; this.get_allocation(out rect); if (event.x < 0 || event.x > rect.width || event.y < 0 || event.y > rect.height) { this.cancel(); return true; } } if (this.active && this.enable_mouse) { Gdk.ModifierType state = event.state & ~ this.lock_modifiers; var new_trigger = new Trigger.from_values((int)event.button, state, true, false, false, false, false, 5); if (new_trigger.key_code != 1) this.update_trigger(new_trigger); else this.cancel(); return true; } else if (this.active) { this.cancel(); return true; } return false; } } }