diff options
author | Joe Lee <joe@jotaro.com> | 2008-03-30 05:00:51 (GMT) |
---|---|---|
committer | Joe Lee <joe@jotaro.com> | 2008-03-30 05:00:51 (GMT) |
commit | 26cd1b9ec3da1186a2c6157c128cf19851b97099 (patch) | |
tree | e729b16ca45f87ba592f70886cba4258d0b9234f | |
parent | d24881f4add199245a25f1794c1df8fe885d7ffc (diff) |
Added initial gamepad/keyboard support.
-rw-r--r-- | NEWS | 2 | ||||
-rw-r--r-- | gridwidget.py | 102 | ||||
-rw-r--r-- | implodeactivity.py | 1 | ||||
-rw-r--r-- | implodegame.py | 19 | ||||
-rw-r--r-- | sugarless.py | 1 |
5 files changed, 122 insertions, 3 deletions
@@ -22,9 +22,9 @@ - Added Arabic translation courtesy of khaled. - Modified colors for better contrast in b/w mode. - Fixed ticket #5737: Implode smiley face draws over new game. + - Added initial gamepad/keyboard support. TODO: -- Gamepad/keyboard controls need to be added. - The activity needs to save/restore the current game on exit/restart (maybe using the Journal?). - Maybe include a way to regenerate earlier games or games from another diff --git a/gridwidget.py b/gridwidget.py index ed28843..e237524 100644 --- a/gridwidget.py +++ b/gridwidget.py @@ -59,6 +59,38 @@ _SMILEY = """ ..xxxxxx.. """ +_KEY_MAP = { + gtk.keysyms.KP_Up : 'up', + gtk.keysyms.KP_Down : 'down', + gtk.keysyms.KP_Left : 'left', + gtk.keysyms.KP_Right : 'right', + + gtk.keysyms.Up : 'up', + gtk.keysyms.Down : 'down', + gtk.keysyms.Left : 'left', + gtk.keysyms.Right : 'right', + + gtk.keysyms.uparrow : 'up', + gtk.keysyms.downarrow : 'down', + gtk.keysyms.leftarrow : 'left', + gtk.keysyms.rightarrow : 'right', + + gtk.keysyms.Return : 'select', + gtk.keysyms.KP_Space : 'select', + gtk.keysyms.KP_Enter : 'select', + gtk.keysyms.space : 'select', + gtk.keysyms.End : 'select', + gtk.keysyms.KP_End : 'select', + + gtk.keysyms.Home : 'new', + gtk.keysyms.KP_Home : 'new', + gtk.keysyms.Page_Down : 'redo', + gtk.keysyms.KP_Page_Down : 'redo', + gtk.keysyms.Page_Up : 'undo', + gtk.keysyms.KP_Page_Up : 'undo', +} + + # Animation modes. ANIMATE_NONE = 0 ANIMATE_SHRINK = 1 @@ -85,8 +117,12 @@ class GridWidget(gtk.DrawingArea): """Gtk widget for rendering the game board.""" __gsignals__ = { - 'piece-selected': (gobject.SIGNAL_RUN_LAST, None, (int, int)), + 'piece-selected' : (gobject.SIGNAL_RUN_LAST, None, (int, int)), + 'undo-key-pressed': (gobject.SIGNAL_RUN_LAST, None, (int,)), + 'redo-key-pressed': (gobject.SIGNAL_RUN_LAST, None, (int,)), + 'new-key-pressed' : (gobject.SIGNAL_RUN_LAST, None, (int,)), 'button-press-event': 'override', + 'key-press-event': 'override', 'expose-event': 'override', 'size-allocate': 'override', 'motion-notify-event': 'override', @@ -95,7 +131,9 @@ class GridWidget(gtk.DrawingArea): def __init__(self, *args, **kwargs): super(GridWidget, self).__init__(*args, **kwargs) self.set_events(gtk.gdk.BUTTON_PRESS_MASK - | gtk.gdk.POINTER_MOTION_MASK) + | gtk.gdk.POINTER_MOTION_MASK + | gtk.gdk.KEY_PRESS_MASK) + self.set_flags(gtk.CAN_FOCUS) self._board = None self._board_width = 0 self._board_height = 0 @@ -129,6 +167,12 @@ class GridWidget(gtk.DrawingArea): self._recalc_contiguous_map() self._init_board_layout(self.allocation.width, self.allocation.height) + if self._selected_cell is not None: + # If a cell is selected, clamp it to new board boundaries. + (x, y) = self._selected_cell + x = max(0, min(self._board_width - 1, x)) + y = max(0, min(self._board_height - 1, y)) + self._selected_cell = (x, y) self._invalidate_board() def set_removal_block_set(self, value): @@ -172,10 +216,64 @@ class GridWidget(gtk.DrawingArea): # Ignore mouse clicks while animating. if self._animation_mode != ANIMATE_NONE: return + self.grab_focus() self._set_mouse_selection(event.x, event.y) if self._selected_cell is not None: self.emit('piece-selected', *self._selected_cell) + def select_center_cell(self): + if not self._board_is_valid(): + return + if self._selected_cell is not None: + self._invalidate_selection(self._selected_cell) + self._selected_cell = (int(self._board_width / 2), + self._board_height - 1) + self._invalidate_selection(self._selected_cell) + + @_log_errors + def do_key_press_event(self, event): + action = _KEY_MAP.get(event.keyval, None) + if action == 'new': + self.emit('new-key-pressed', 0) + return True + # Ignore key presses while animating. + if self._animation_mode != ANIMATE_NONE: + return False + if not self._board_is_valid(): + self._selected_cell = None + return False + else: + if self._selected_cell is None: + self.select_center_cell() + return True + else: + if action == 'select': + self.emit('piece-selected', *self._selected_cell) + return True + elif action == 'undo': + self.emit('undo-key-pressed', 0) + return True + elif action == 'redo': + self.emit('redo-key-pressed', 0) + return True + else: + (x, y) = self._selected_cell + if action == 'up': + y = min(self._board_height - 1, y + 1) + elif action == 'down': + y = max(0, y - 1) + elif action == 'left': + x = max(0, x - 1) + elif action == 'right': + x = min(self._board_width - 1, x + 1) + if self._selected_cell != (x, y): + self._invalidate_selection(self._selected_cell) + self._selected_cell = (x, y) + self._invalidate_selection(self._selected_cell) + return True + else: + return False + @_log_errors def do_motion_notify_event(self, event): if event.is_hint: diff --git a/implodeactivity.py b/implodeactivity.py index 365ab0d..5b76b74 100644 --- a/implodeactivity.py +++ b/implodeactivity.py @@ -67,6 +67,7 @@ class ImplodeActivity(Activity): self.set_canvas(self._game) self.show_all() + self._game.grab_focus() class _Toolbox(ActivityToolbox): __gsignals__ = { diff --git a/implodegame.py b/implodegame.py index c3b2c9a..93409db 100644 --- a/implodegame.py +++ b/implodegame.py @@ -73,10 +73,17 @@ class ImplodeGame(gtk.EventBox): self._grid = gridwidget.GridWidget() self._grid.connect('piece-selected', self._piece_selected_cb) + self._grid.connect('undo-key-pressed', self._undo_key_pressed_cb) + self._grid.connect('redo-key-pressed', self._redo_key_pressed_cb) + self._grid.connect('new-key-pressed', self._new_key_pressed_cb) self.add(self._grid) self.new_game() + def grab_focus(self): + self._grid.grab_focus() + self._grid.select_center_cell() + def new_game(self): _logger.debug('New game.') self._finish_animation() @@ -150,6 +157,18 @@ class ImplodeGame(gtk.EventBox): self._end_anim_func = self._end_removal_animation gobject.timeout_add(_TIMER_INTERVAL, self._removal_timer) + def _undo_key_pressed_cb(self, widget, dummy): + self.undo() + + def _redo_key_pressed_cb(self, widget, dummy): + self.redo() + + def _new_key_pressed_cb(self, widget, dummy): + # Only invoke new command via game pad if board is clear, to prevent + # terrible accidents. + if self._board.is_empty(): + self.new_game() + def _finish_animation(self): if self._end_anim_func: temp_animate = self._animate diff --git a/sugarless.py b/sugarless.py index 4fa460f..118f828 100644 --- a/sugarless.py +++ b/sugarless.py @@ -79,6 +79,7 @@ class ImplodeWindow(gtk.Window): self.add(main_box) self.show_all() + self.game.grab_focus() def _delete_event_cb(self, window, event): gtk.main_quit() |