1/* -*- Mode: vala; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- 2 * Gnome Nibbles: Gnome Worm Game 3 * Copyright (C) 2015 Iulian-Gabriel Radu <iulian.radu67@gmail.com> 4 * Copyright (C) 2020 Arnaud Bonatti <arnaud.bonatti@gmail.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 3 of the License, or 9 * (at your option) any later version. 10 * 11 * This program 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 this program. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20using Gtk; 21 22[GtkTemplate (ui = "/org/gnome/Nibbles/ui/controls.ui")] 23private class Controls : Box 24{ 25 [GtkChild] private Box grids_box; 26 private Gee.LinkedList<ControlsGrid> grids = new Gee.LinkedList<ControlsGrid> (); 27 28 private Gdk.Pixbuf arrow_pixbuf; 29 30 internal void load_pixmaps (int tile_size) 31 { 32 arrow_pixbuf = NibblesView.load_pixmap_file ("arrow.svg", 5 * tile_size, 5 * tile_size); 33 } 34 35 internal void prepare (Gee.LinkedList<Worm> worms, Gee.HashMap<Worm, WormProperties> worm_props) 36 { 37 foreach (var grid in grids_box.get_children ()) 38 grid.destroy (); 39 40 GenericSet<uint> duplicate_keys = new GenericSet<uint> (direct_hash, direct_equal); 41 GenericSet<uint> encountered_keys = new GenericSet<uint> (direct_hash, direct_equal); 42 foreach (var worm in worms) 43 { 44 if (worm.is_human) 45 { 46 WormProperties worm_prop = worm_props.@get (worm); 47 48 var grid = new ControlsGrid (worm.id, worm_prop, arrow_pixbuf); 49 grids_box.add (grid); 50 grids.add (grid); 51 52 check_for_duplicates (worm_prop.up, ref encountered_keys, ref duplicate_keys); 53 check_for_duplicates (worm_prop.down, ref encountered_keys, ref duplicate_keys); 54 check_for_duplicates (worm_prop.left, ref encountered_keys, ref duplicate_keys); 55 check_for_duplicates (worm_prop.right, ref encountered_keys, ref duplicate_keys); 56 } 57 } 58 foreach (ControlsGrid grid in grids) 59 { 60 grid.external_handler = grid.worm_props.notify.connect (() => { 61 GenericSet<uint> _duplicate_keys = new GenericSet<uint> (direct_hash, direct_equal); 62 GenericSet<uint> _encountered_keys = new GenericSet<uint> (direct_hash, direct_equal); 63 foreach (var worm in worms) 64 { 65 if (worm.is_human) 66 { 67 WormProperties worm_prop = worm_props.@get (worm); 68 69 check_for_duplicates (worm_prop.up, ref _encountered_keys, ref _duplicate_keys); 70 check_for_duplicates (worm_prop.down, ref _encountered_keys, ref _duplicate_keys); 71 check_for_duplicates (worm_prop.left, ref _encountered_keys, ref _duplicate_keys); 72 check_for_duplicates (worm_prop.right, ref _encountered_keys, ref _duplicate_keys); 73 } 74 } 75 foreach (ControlsGrid _grid in grids) 76 _grid.mark_duplicated_keys (_duplicate_keys); 77 }); 78 grid.mark_duplicated_keys (duplicate_keys); 79 } 80 } 81 private void check_for_duplicates (uint key, ref GenericSet<uint> encountered_keys, ref GenericSet<uint> duplicate_keys) 82 { 83 if (encountered_keys.contains (key)) 84 duplicate_keys.add (key); 85 else 86 encountered_keys.add (key); 87 } 88 89 internal void clean () 90 { 91 foreach (ControlsGrid grid in grids) 92 { 93 grid.worm_props.disconnect (grid.external_handler); 94 grid.disconnect_stuff (); 95 } 96 grids.clear (); 97 } 98} 99 100[GtkTemplate (ui = "/org/gnome/Nibbles/ui/controls-grid.ui")] 101private class ControlsGrid : Button 102{ 103 [GtkChild] private Label name_label; 104 [GtkChild] private Image arrow_up; 105 [GtkChild] private Image arrow_down; 106 [GtkChild] private Image arrow_left; 107 [GtkChild] private Image arrow_right; 108 [GtkChild] private Label move_up_label; 109 [GtkChild] private Label move_down_label; 110 [GtkChild] private Label move_left_label; 111 [GtkChild] private Label move_right_label; 112 113 internal WormProperties worm_props; 114 internal ulong external_handler; 115 private ulong up_handler; 116 private ulong down_handler; 117 private ulong left_handler; 118 private ulong right_handler; 119 private ulong color_handler; 120 121 internal ControlsGrid (int worm_id, WormProperties worm_props, Gdk.Pixbuf arrow) 122 { 123 this.worm_props = worm_props; 124 125 set_action_target ("i", worm_id + 1); 126 127 /* Translators: text displayed in a screen showing the keys used by the players; the %d is replaced by the number that identifies the player */ 128 var player_id = _("Player %d").printf (worm_id + 1); 129 color_handler = worm_props.notify ["color"].connect (() => { 130 var color = Pango.Color (); 131 color.parse (NibblesView.colorval_name_untranslated (worm_props.color)); 132 name_label.set_markup (@"<b><span font-family=\"Sans\" color=\"$(color.to_string ())\">$(player_id)</span></b>"); 133 }); 134 var color = Pango.Color (); 135 color.parse (NibblesView.colorval_name_untranslated (worm_props.color)); 136 name_label.set_markup (@"<b><span font-family=\"Sans\" color=\"$(color.to_string ())\">$(player_id)</span></b>"); 137 138 arrow_up.set_from_pixbuf (arrow.rotate_simple (Gdk.PixbufRotation.NONE)); 139 arrow_down.set_from_pixbuf (arrow.rotate_simple (Gdk.PixbufRotation.UPSIDEDOWN)); 140 arrow_left.set_from_pixbuf (arrow.rotate_simple (Gdk.PixbufRotation.COUNTERCLOCKWISE)); 141 arrow_right.set_from_pixbuf (arrow.rotate_simple (Gdk.PixbufRotation.CLOCKWISE)); 142 143 up_handler = worm_props.notify ["up"].connect (() => configure_label (worm_props.up, ref move_up_label)); 144 down_handler = worm_props.notify ["down"].connect (() => configure_label (worm_props.down, ref move_down_label)); 145 left_handler = worm_props.notify ["left"].connect (() => configure_label (worm_props.left, ref move_left_label)); 146 right_handler = worm_props.notify ["right"].connect (() => configure_label (worm_props.right, ref move_right_label)); 147 148 configure_label (worm_props.up, ref move_up_label); 149 configure_label (worm_props.down, ref move_down_label); 150 configure_label (worm_props.left, ref move_left_label); 151 configure_label (worm_props.right, ref move_right_label); 152 } 153 154 internal void mark_duplicated_keys (GenericSet<uint> duplicate_keys) 155 { 156 set_duplicate_class (worm_props.up in duplicate_keys, ref move_up_label); 157 set_duplicate_class (worm_props.down in duplicate_keys, ref move_down_label); 158 set_duplicate_class (worm_props.left in duplicate_keys, ref move_left_label); 159 set_duplicate_class (worm_props.right in duplicate_keys, ref move_right_label); 160 } 161 private static void set_duplicate_class (bool new_value, ref Label label) 162 { 163 if (new_value) 164 label.get_style_context ().add_class ("duplicate"); 165 else 166 label.get_style_context ().remove_class ("duplicate"); 167 } 168 169 internal void disconnect_stuff () 170 { 171 worm_props.disconnect ( up_handler); 172 worm_props.disconnect ( down_handler); 173 worm_props.disconnect ( left_handler); 174 worm_props.disconnect (right_handler); 175 worm_props.disconnect (color_handler); 176 } 177 178 private static void configure_label (uint key_value, ref Label label) 179 { 180 string? key_name = Gdk.keyval_name (key_value); 181 if (key_name == "Up") 182 { 183 label.get_style_context ().add_class ("arrow"); 184 label.set_text ("↑"); 185 } 186 else if (key_name == "Down") 187 { 188 label.get_style_context ().add_class ("arrow"); 189 label.set_text ("↓"); 190 } 191 else if (key_name == "Left") 192 { 193 label.get_style_context ().add_class ("arrow"); 194 label.set_text ("←"); 195 } 196 else if (key_name == "Right") 197 { 198 label.get_style_context ().add_class ("arrow"); 199 label.set_text ("→"); 200 } 201 else if (key_name == null || key_name == "") 202 { 203 label.get_style_context ().remove_class ("arrow"); 204 label.set_text (""); 205 } 206 else 207 { 208 label.get_style_context ().remove_class ("arrow"); 209 label.set_text (@"$(accelerator_get_label (key_value, 0))"); 210 } 211 } 212} 213