Package horizons :: Package gui :: Package modules :: Module hotkeys_settings
[hide private]
[frames] | no frames]

Source Code for Module horizons.gui.modules.hotkeys_settings

  1  # ################################################### 
  2  # Copyright (C) 2008-2017 The Unknown Horizons Team 
  3  # team@unknown-horizons.org 
  4  # This file is part of Unknown Horizons. 
  5  # 
  6  # Unknown Horizons 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  # 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, write to the 
 18  # Free Software Foundation, Inc., 
 19  # 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA 
 20  # ################################################### 
 21   
 22   
 23  from fife import fife 
 24  from fife.extensions.pychan.widgets import Button 
 25   
 26  import horizons.globals 
 27  from horizons.gui.keylisteners.ingamekeylistener import KeyConfig 
 28  from horizons.gui.util import load_uh_widget 
 29  from horizons.gui.widgets.imagebutton import OkButton 
 30  from horizons.i18n import gettext as T 
 31  from horizons.util.python.callback import Callback 
 32   
 33   
34 -class HotkeyConfiguration:
35
36 - def __init__(self):
37 super().__init__() # TODO: check whether this call is needed 38 39 self.widget = load_uh_widget('hotkeys.xml') 40 self.buttons = [] 41 self.secondary_buttons = [] 42 43 self.keyconf = KeyConfig() 44 self.actions = self.keyconf.get_bindable_actions_by_name() 45 self.keys = self.keyconf.get_keys_by_value() 46 47 self.HELPSTRING_LAYOUT = None 48 self._build_interface() 49 50 # When `detecting` is True, the interface detects keypresses and binds them to actions 51 self.detecting = False 52 self.current_button = None 53 self.current_index = None 54 self.last_combination = [] 55 # Stores whether the last button pressed was for a primary or secondary binding (1 or 2) 56 self.last_column = 1 57 58 # This used to go though the widget's key events, but fifechan has different keynames 59 # Using a fife keylistener ensures that the in-game keys always match 60 self.listener = HotkeysListener(self._detect_keypress) 61 62 self.widget.findChild(name=OkButton.DEFAULT_NAME).capture(self.save_settings) 63 self.widget.mapEvents({OkButton.DEFAULT_NAME: self.save_settings}) 64 self.widget.findChild(name="reset_to_default").capture(self.reset_to_default)
65
66 - def _build_interface(self):
67 button_container = self.widget.findChild(name='button_container') 68 sec_button_container = self.widget.findChild(name='sec_button_container') 69 for i, action in enumerate(self.actions): 70 button = self._create_button(action, i) 71 sec_button = self._create_button(action, i) 72 button.mapEvents({button.name + '/mouseClicked': Callback(self._detect_click_on_button, button, 1)}) 73 sec_button.mapEvents({button.name + '/mouseClicked': Callback(self._detect_click_on_button, sec_button, 2)}) 74 button_container.addChild(button) 75 sec_button_container.addChild(sec_button) 76 self.buttons.append(button) 77 self.secondary_buttons.append(sec_button) 78 self.update_buttons_text()
79
80 - def _create_button(self, action, index):
81 """Important! The button name is set to index so that when a button is pressed, we know its index""" 82 button = Button(is_focusable=False) 83 button.name = str(index) 84 button.max_size = button.min_size = (100, 18) 85 return button
86
87 - def _detect_click_on_button(self, button, column):
88 """Starts the listener and remembers the position and index of the pressed button""" 89 self.detecting = True 90 self.current_button = button 91 self.current_index = int(button.name) 92 self.current_column = column 93 self.listener.activate() 94 self.update_buttons_text() 95 button.font = 'default' 96 button.text = T("Press key…")
97
98 - def _detect_keypress(self, event):
99 if not self.detecting: 100 return 101 key = event.getKey() 102 # if the key is not supported, act as if it was not detected 103 if not self.key_name(key): 104 return 105 self.last_combination.append(key) 106 self.detecting = False 107 self.listener.deactivate() 108 self.apply_change()
109
110 - def update_buttons_text(self):
111 for i, button in enumerate(self.buttons): 112 button.font = 'default_bold' 113 action = self.actions[i] 114 bindings = self.keyconf.get_current_keys(action) 115 for j in range(len(bindings)): 116 if bindings[j] == 'UNASSIGNED': 117 bindings[j] = '' 118 secondary_button = self.secondary_buttons[i] 119 button.text = str(bindings[0]) 120 if len(bindings) > 1: 121 secondary_button.font = 'default_bold' 122 secondary_button.text = str(bindings[1]) 123 else: 124 secondary_button.text = ''
125
126 - def apply_change(self):
127 """Binds the last keypress to the corresponding action and resets the interface to the state where it is listening for clicks on buttons""" 128 key = self.last_combination[0] 129 key_name = self.key_name(key) 130 action = self.actions[self.current_index] 131 132 # Escape is used to unassign bindings 133 if key_name == 'ESCAPE': 134 key_name = 'UNASSIGNED' 135 136 # If *key* is already set, replace the entry for *key* with UNASSIGNED for the last action. 137 # This is done to avoid binding one key for two actions. 138 elif self.key_is_set(key): 139 oldaction = self.get_action_name(key) 140 if action == oldaction and key_name in self.keyconf.get_current_keys(action): 141 self.update_buttons_text() 142 self.last_combination = [] 143 return 144 145 message = T("{key} is already set to {action}.").format(key=key_name, action=oldaction) 146 message += " " + T("Would you like to overwrite it?") 147 confirmed = horizons.main.gui.open_popup(T("Confirmation for overwriting"), message, show_cancel_button=True) 148 if confirmed: 149 horizons.globals.fife.replace_key_for_action(oldaction, key_name, "UNASSIGNED") 150 else: 151 self.update_buttons_text() 152 self.last_combination = [] 153 return 154 155 bindings = self.keyconf.get_current_keys(action) 156 if self.current_column == 1: 157 bindings[0] = key_name 158 elif self.current_column == 2: 159 if len(bindings) < 2: 160 bindings.append(key_name) 161 else: 162 bindings[1] = key_name 163 164 horizons.globals.fife.set_key_for_action(action, bindings) 165 166 self.update_buttons_text() 167 self.last_combination = []
168
169 - def key_name(self, key):
170 value = key.getValue() 171 return self.keys.get(value)
172
173 - def key_is_set(self, key):
174 key_name = self.key_name(key) 175 custom_key_actions = horizons.globals.fife.get_hotkey_settings() 176 for k in custom_key_actions.values(): 177 if key_name in k: 178 return True 179 return False
180
181 - def get_current_bindings(self):
182 """ Returns a dict mapping action -> list of keys """ 183 bindings = {} 184 for action in self.actions: 185 keys = self.keyconf.get_current_keys(action) 186 bindings[action] = keys 187 return bindings
188
189 - def get_action_name(self, key):
190 key_name = self.key_name(key) 191 custom_key_actions = horizons.globals.fife.get_hotkey_settings() 192 for action in custom_key_actions: 193 k = custom_key_actions[action] 194 if key_name in k: 195 return action 196 print("Action name not found. Key name (" + key_name + ") must be wrong. This is not supposed to ever happen")
197
198 - def reset_to_default(self):
199 """Resets all bindings to default""" 200 for action in self.actions: 201 default_key = horizons.globals.fife.get_keys_for_action(action, default=True) 202 horizons.globals.fife.set_key_for_action(action, default_key) 203 204 self.update_buttons_text()
205
206 - def save_settings(self):
207 """Saves the settings and reloads the keyConfiguration so that the settings take effect without a restart""" 208 horizons.globals.fife.save_settings() 209 self.keyconf.loadKeyConfiguration()
210
211 - def show(self):
212 self.widget.show()
213
214 - def hide(self):
215 self.widget.hide()
216 217
218 -class HotkeysListener(fife.IKeyListener):
219 """HotkeysListener Class to process events of hotkeys binding interface""" 220
221 - def __init__(self, detect_keypress):
222 super().__init__() 223 fife.IKeyListener.__init__(self) 224 225 self.detect = detect_keypress
226
227 - def activate(self):
228 horizons.globals.fife.eventmanager.addKeyListenerFront(self)
229
230 - def deactivate(self):
231 horizons.globals.fife.eventmanager.removeKeyListener(self)
232
233 - def end(self):
234 horizons.globals.fife.eventmanager.removeKeyListener(self) 235 super().end()
236
237 - def keyPressed(self, evt):
238 self.detect(evt) 239 evt.consume()
240
241 - def keyReleased(self, evt):
242 pass
243