1/* 2 * Copyright (c) 2019-2021 Alecaddd (https://alecaddd.com) 3 * 4 * This file is part of Akira. 5 * 6 * Akira 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 3 of the License, or 9 * (at your option) any later version. 10 * 11 * Akira is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with Akira. If not, see <https://www.gnu.org/licenses/>. 18 * 19 * Authored by: Alessandro "Alecaddd" Castellani <castellani.ale@gmail.com> 20 */ 21 22public class Akira.Widgets.InputField : Gtk.EventBox { 23 public Gtk.SpinButton entry { get; construct set; } 24 25 public int chars { get; construct set; } 26 public bool rtl { get; construct set; } 27 public bool icon_right { get; construct set; } 28 public Unit unit { get; construct set; } 29 public string? icon { get; set; } 30 31 public double step { get; set; default = 1; } 32 33 public enum Unit { 34 PIXEL, 35 HASH, 36 PERCENTAGE, 37 DEGREES, 38 NONE 39 } 40 41 public InputField ( 42 Unit unit, 43 int chars, 44 bool icon_right = false, 45 bool rtl = false) { 46 Object ( 47 unit: unit, 48 chars: chars, 49 icon_right: icon_right, 50 rtl: rtl 51 ); 52 } 53 54 construct { 55 valign = Gtk.Align.CENTER; 56 57 entry = new Gtk.SpinButton.with_range (0, 100, step); 58 entry.hexpand = true; 59 entry.width_chars = chars; 60 entry.sensitive = false; 61 62 entry.key_press_event.connect (handle_key_press); 63 entry.scroll_event.connect (handle_scroll_event); 64 entry.focus_in_event.connect (handle_focus_in); 65 entry.focus_out_event.connect (handle_focus_out); 66 67 switch (unit) { 68 case Unit.HASH: 69 icon = "input-hash-symbolic"; 70 break; 71 case Unit.PERCENTAGE: 72 icon = "input-percentage-symbolic"; 73 break; 74 case Unit.PIXEL: 75 icon = "input-pixel-symbolic"; 76 break; 77 case Unit.DEGREES: 78 icon = "input-degrees-symbolic"; 79 break; 80 default: 81 icon = null; 82 break; 83 } 84 85 if (icon != null) { 86 if (icon_right) { 87 entry.get_style_context ().add_class ("input-icon-right"); 88 entry.secondary_icon_name = icon; 89 entry.secondary_icon_sensitive = false; 90 entry.secondary_icon_activatable = false; 91 } else { 92 entry.get_style_context ().add_class ("input-icon-left"); 93 entry.primary_icon_name = icon; 94 entry.primary_icon_sensitive = false; 95 entry.primary_icon_activatable = false; 96 } 97 } 98 99 if (rtl) { 100 entry.xalign = 1.0f; 101 } 102 103 add (entry); 104 } 105 106 public void set_range (double min_value, double max_value) { 107 entry.set_range (min_value, max_value); 108 } 109 110 private bool handle_key_press (Gdk.EventKey event) { 111 // Arrow UP 112 if (event.keyval == Gdk.Key.Up && (event.state & Gdk.ModifierType.SHIFT_MASK) > 0) { 113 entry.spin (Gtk.SpinType.STEP_FORWARD, 10); 114 return true; 115 } 116 117 // Arrow DOWN 118 if (event.keyval == Gdk.Key.Down && (event.state & Gdk.ModifierType.SHIFT_MASK) > 0) { 119 entry.spin (Gtk.SpinType.STEP_BACKWARD, 10); 120 return true; 121 } 122 123 // Enter or Escape 124 if (event.keyval == Gdk.Key.Return || event.keyval == Gdk.Key.Escape) { 125 Akira.Window window = get_toplevel () as Akira.Window; 126 window.event_bus.set_focus_on_canvas (); 127 return true; 128 } 129 130 return false; 131 } 132 133 private bool handle_scroll_event (Gdk.EventScroll event) { 134 // If the input field is not focused, don't change the value. 135 if (!entry.has_focus) { 136 return true; 137 } 138 return false; 139 } 140 141 private bool handle_focus_in (Gdk.EventFocus event) { 142 Akira.Window window = get_toplevel () as Akira.Window; 143 if (!(window is Akira.Window)) { 144 return true; 145 } 146 window.event_bus.disconnect_typing_accel (); 147 148 return false; 149 } 150 151 private bool handle_focus_out (Gdk.EventFocus event) { 152 Akira.Window window = get_toplevel () as Akira.Window; 153 if (!(window is Akira.Window)) { 154 return true; 155 } 156 window.event_bus.connect_typing_accel (); 157 158 return false; 159 } 160} 161