Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoe Lee <joe@jotaro.com>2008-03-30 05:00:51 (GMT)
committer Joe Lee <joe@jotaro.com>2008-03-30 05:00:51 (GMT)
commit26cd1b9ec3da1186a2c6157c128cf19851b97099 (patch)
treee729b16ca45f87ba592f70886cba4258d0b9234f
parentd24881f4add199245a25f1794c1df8fe885d7ffc (diff)
Added initial gamepad/keyboard support.
-rw-r--r--NEWS2
-rw-r--r--gridwidget.py102
-rw-r--r--implodeactivity.py1
-rw-r--r--implodegame.py19
-rw-r--r--sugarless.py1
5 files changed, 122 insertions, 3 deletions
diff --git a/NEWS b/NEWS
index 9cb287d..bab21e7 100644
--- a/NEWS
+++ b/NEWS
@@ -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()