[gnome-games/glines-vala] swell-foop: Make the game playable by keyboard



commit f190f9b1c7010046d6e14243a2e9efe056763637
Author: Daniel Buch <boogiewasthere gmail com>
Date:   Sun Jul 15 01:01:13 2012 +0200

    swell-foop: Make the game playable by keyboard
    
    To handle the mixed mouse/keyboard highlighting a field is added to hold the highlighted tile.
    
    The svg for the cursor actor is copied from lightsoff.

 swell-foop/data/themes/colors/Makefile.am          |    6 +-
 swell-foop/data/themes/colors/highlight.svg        |   99 ++++++++++++++++++
 swell-foop/data/themes/shapesandcolors/Makefile.am |    6 +-
 .../data/themes/shapesandcolors/highlight.svg      |   99 ++++++++++++++++++
 swell-foop/src/game-view.vala                      |  108 ++++++++++++++++++--
 swell-foop/src/swell-foop.vala                     |   35 ++++++-
 6 files changed, 339 insertions(+), 14 deletions(-)
---
diff --git a/swell-foop/data/themes/colors/Makefile.am b/swell-foop/data/themes/colors/Makefile.am
index c6532ed..7b046c0 100644
--- a/swell-foop/data/themes/colors/Makefile.am
+++ b/swell-foop/data/themes/colors/Makefile.am
@@ -4,13 +4,15 @@ theme_DATA = \
 	blue.svg \
 	green.svg \
 	red.svg \
-	yellow.svg
+	yellow.svg \
+	highlight.svg
 
 EXTRA_DIST = \
 	bkg.svg \
 	blue.svg \
 	green.svg \
 	red.svg \
-	yellow.svg
+	yellow.svg \
+	highlight.svg
 
 -include $(top_srcdir)/git.mk
diff --git a/swell-foop/data/themes/colors/highlight.svg b/swell-foop/data/themes/colors/highlight.svg
new file mode 100644
index 0000000..a830854
--- /dev/null
+++ b/swell-foop/data/themes/colors/highlight.svg
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/";
+   xmlns:cc="http://creativecommons.org/ns#";
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+   xmlns:svg="http://www.w3.org/2000/svg";
+   xmlns="http://www.w3.org/2000/svg";
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
+   width="75"
+   height="75"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.46"
+   sodipodi:docname="highlight.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   version="1.0">
+  <defs
+     id="defs4">
+    <linearGradient
+       id="linearGradient3179">
+      <stop
+         style="stop-color:#35669b;stop-opacity:0.96078432;"
+         offset="0"
+         id="stop3181" />
+      <stop
+         style="stop-color:#5e92c8;stop-opacity:0.96078432;"
+         offset="1"
+         id="stop3183" />
+    </linearGradient>
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="0 : 526.18109 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="744.09448 : 526.18109 : 1"
+       inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+       id="perspective10" />
+    <filter
+       inkscape:collect="always"
+       id="filter3393"
+       x="-0.43563023"
+       width="1.8712605"
+       y="-0.43563023"
+       height="1.8712605">
+      <feGaussianBlur
+         inkscape:collect="always"
+         stdDeviation="5.5324044"
+         id="feGaussianBlur3395" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#000000"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     gridtolerance="10000"
+     guidetolerance="10"
+     objecttolerance="10"
+     inkscape:pageopacity="1"
+     inkscape:pageshadow="2"
+     inkscape:zoom="8.76"
+     inkscape:cx="17.522831"
+     inkscape:cy="37.5"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="1438"
+     inkscape:window-height="882"
+     inkscape:window-x="0"
+     inkscape:window-y="16" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage"; />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-164.71428,-194.21933)">
+    <path
+       sodipodi:type="arc"
+       style="opacity:0.64102568;fill:#ffffff;fill-opacity:1;stroke:none;stroke-opacity:1;filter:url(#filter3393)"
+       id="path3183"
+       sodipodi:cx="22.888128"
+       sodipodi:cy="25.285389"
+       sodipodi:rx="15.239726"
+       sodipodi:ry="15.239726"
+       d="M 38.127854,25.285389 A 15.239726,15.239726 0 1 1 7.6484022,25.285389 A 15.239726,15.239726 0 1 1 38.127854,25.285389 z"
+       transform="matrix(1.247191,0,0,1.247191,173.66841,200.18362)" />
+  </g>
+</svg>
diff --git a/swell-foop/data/themes/shapesandcolors/Makefile.am b/swell-foop/data/themes/shapesandcolors/Makefile.am
index 96c42f8..4e80ee4 100644
--- a/swell-foop/data/themes/shapesandcolors/Makefile.am
+++ b/swell-foop/data/themes/shapesandcolors/Makefile.am
@@ -4,13 +4,15 @@ theme_DATA = \
 	blue.svg \
 	green.svg \
 	red.svg \
-	yellow.svg
+	yellow.svg \
+	highlight.svg
 
 EXTRA_DIST = \
 	bkg.svg \
 	blue.svg \
 	green.svg \
 	red.svg \
-	yellow.svg
+	yellow.svg \
+	highlight.svg
 
 -include $(top_srcdir)/git.mk
diff --git a/swell-foop/data/themes/shapesandcolors/highlight.svg b/swell-foop/data/themes/shapesandcolors/highlight.svg
new file mode 100644
index 0000000..a830854
--- /dev/null
+++ b/swell-foop/data/themes/shapesandcolors/highlight.svg
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/";
+   xmlns:cc="http://creativecommons.org/ns#";
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+   xmlns:svg="http://www.w3.org/2000/svg";
+   xmlns="http://www.w3.org/2000/svg";
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
+   width="75"
+   height="75"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.46"
+   sodipodi:docname="highlight.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   version="1.0">
+  <defs
+     id="defs4">
+    <linearGradient
+       id="linearGradient3179">
+      <stop
+         style="stop-color:#35669b;stop-opacity:0.96078432;"
+         offset="0"
+         id="stop3181" />
+      <stop
+         style="stop-color:#5e92c8;stop-opacity:0.96078432;"
+         offset="1"
+         id="stop3183" />
+    </linearGradient>
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="0 : 526.18109 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="744.09448 : 526.18109 : 1"
+       inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+       id="perspective10" />
+    <filter
+       inkscape:collect="always"
+       id="filter3393"
+       x="-0.43563023"
+       width="1.8712605"
+       y="-0.43563023"
+       height="1.8712605">
+      <feGaussianBlur
+         inkscape:collect="always"
+         stdDeviation="5.5324044"
+         id="feGaussianBlur3395" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#000000"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     gridtolerance="10000"
+     guidetolerance="10"
+     objecttolerance="10"
+     inkscape:pageopacity="1"
+     inkscape:pageshadow="2"
+     inkscape:zoom="8.76"
+     inkscape:cx="17.522831"
+     inkscape:cy="37.5"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="1438"
+     inkscape:window-height="882"
+     inkscape:window-x="0"
+     inkscape:window-y="16" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage"; />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-164.71428,-194.21933)">
+    <path
+       sodipodi:type="arc"
+       style="opacity:0.64102568;fill:#ffffff;fill-opacity:1;stroke:none;stroke-opacity:1;filter:url(#filter3393)"
+       id="path3183"
+       sodipodi:cx="22.888128"
+       sodipodi:cy="25.285389"
+       sodipodi:rx="15.239726"
+       sodipodi:ry="15.239726"
+       d="M 38.127854,25.285389 A 15.239726,15.239726 0 1 1 7.6484022,25.285389 A 15.239726,15.239726 0 1 1 38.127854,25.285389 z"
+       transform="matrix(1.247191,0,0,1.247191,173.66841,200.18362)" />
+  </g>
+</svg>
diff --git a/swell-foop/src/game-view.vala b/swell-foop/src/game-view.vala
index 3c87964..b6e6e50 100644
--- a/swell-foop/src/game-view.vala
+++ b/swell-foop/src/game-view.vala
@@ -4,8 +4,27 @@
  *  with the model class by composite relation and with the control layer by means of signals and
  *  events.
  */
+
 public class GameView : Clutter.Group
 {
+    private TileActor highlighted = null;
+
+    private CursorActor cursor;
+    private bool cursor_active = false;
+    private int _cursor_x;
+    public int cursor_x
+    {
+        get { return this._cursor_x; }
+        set { this._cursor_x = value.clamp(0, game.columns - 1); }
+    }
+
+    private int _cursor_y;
+    public int cursor_y
+    {
+        get { return this._cursor_y; }
+        set { this._cursor_y = value.clamp(0, game.rows - 1); }
+    }
+
     /* A 2D array holding all tiles */
     private TileActor[,] tiles;
 
@@ -81,6 +100,8 @@ public class GameView : Clutter.Group
                 tile.destroy ();
             }
         }
+
+        cursor.destroy ();
     }
 
     private void place_tiles ()
@@ -122,6 +143,10 @@ public class GameView : Clutter.Group
                 game_actors.add_actor (tile);
             }
         }
+
+        cursor = new CursorActor (theme.cursor, tile_size);
+        game_actors.add_actor (cursor);
+        cursor.hide ();
     }
 
     public bool is_zealous;
@@ -137,6 +162,9 @@ public class GameView : Clutter.Group
             t.hide ();
             add_actor (t);
         }
+        theme.cursor.hide ();
+        add_actor (theme.cursor);
+
         theme = new Theme ("shapesandcolors");
         themes.insert ("shapesandcolors", theme);
         foreach (var t in theme.textures)
@@ -144,6 +172,8 @@ public class GameView : Clutter.Group
             t.hide ();
             add_actor (t);
         }
+        theme.cursor.hide ();
+        add_actor (theme.cursor);
     }
 
     /* When a tile in the model layer is closed, play an animation at the view layer */
@@ -163,14 +193,27 @@ public class GameView : Clutter.Group
         tile.animate_to (new_xx, new_yy, is_zealous);
     }
 
+    /* Sets the opacity for all tiles connected to the actor */
+    private void opacity_for_connected_tiles (TileActor? actor, int opacity)
+    {
+        if (actor == null)
+            return;
+
+        var connected_tiles = game.connected_tiles (actor.tile);
+        foreach (var l in connected_tiles)
+            tiles[l.grid_x, l.grid_y].opacity = opacity;
+    }
+
     /* When the mouse enters a tile, bright up the connected tiles */
     private bool tile_entered_cb (Clutter.Actor actor, Clutter.CrossingEvent event)
     {
+        if (cursor_active)
+            return false;
+
         var tile = (TileActor) actor;
 
-        var connected_tiles = game.connected_tiles (tile.tile);
-        foreach (var l in connected_tiles)
-            tiles[l.grid_x, l.grid_y].opacity = 255;
+        opacity_for_connected_tiles (tile, 255);
+        highlighted = tile;
 
         return false;
     }
@@ -178,11 +221,12 @@ public class GameView : Clutter.Group
     /* When the mouse leaves a tile, lower the brightness of the connected tiles */
     private bool tile_left_cb (Clutter.Actor actor, Clutter.CrossingEvent event)
     {
+        if (cursor_active)
+            return false;
+
         var tile = (TileActor) actor;
 
-        var connected_tiles = game.connected_tiles (tile.tile);
-        foreach (var l in connected_tiles)
-            tiles[l.grid_x, l.grid_y].opacity = 180;
+        opacity_for_connected_tiles (tile, 180);
 
         return false;
     }
@@ -192,6 +236,18 @@ public class GameView : Clutter.Group
     {
         var tile = (TileActor) actor;
 
+        opacity_for_connected_tiles (highlighted, 180);
+
+        if (cursor_active)
+        {
+            cursor_active = false;
+            cursor.hide ();
+        }
+
+        /* Move the cursor to where the mouse was clicked. Expected for mixed mouse/keyboard use */
+        cursor_x = tile.tile.grid_x;
+        cursor_y = tile.tile.grid_y;
+
         game.remove_connected_tiles (tile.tile);
 
         return false;
@@ -208,6 +264,30 @@ public class GameView : Clutter.Group
         return false;
     }
 
+    /* Move Keyboard cursor */
+    public void cursor_move (int x, int y)
+    {
+        cursor_active = true;
+
+        opacity_for_connected_tiles (highlighted, 180);
+        cursor_x += x;
+        cursor_y += y;
+        highlighted = tiles[cursor_x, cursor_y];
+        opacity_for_connected_tiles (highlighted, 255);
+
+        float xx, yy;
+        xx = cursor_x * tile_size + tile_size / 2;
+        yy = (game.rows - 1 - cursor_y) * tile_size + tile_size / 2;
+        cursor.set_position (xx, yy);
+        cursor.show ();
+    }
+
+    /* Keyboard Cursor Click */
+    public void cursor_click ()
+    {
+        game.remove_connected_tiles (tiles[cursor_x, cursor_y].tile);
+    }
+
     /* Show flying score animation after each tile-removing click */
     public void update_score_cb (int points_awarded)
     {
@@ -230,11 +310,12 @@ public class GameView : Clutter.Group
 
 /**
  *  This class holds the textures for a specific theme. These textures are used for creating light
- *  actors.
+ *  actors and cursor actor.
  */
 public class Theme
 {
     public Clutter.Texture[] textures;
+    public Clutter.Texture cursor;
 
     public Theme (string name)
     {
@@ -246,6 +327,8 @@ public class Theme
         {
             for (int i = 0; i < 4; i++)
                 textures[i] = new Clutter.Texture.from_file (Path.build_filename (DATADIR, "themes", name, colors[i] + ".svg"));
+
+            cursor = new Clutter.Texture.from_file (Path.build_filename (DATADIR, "themes", name, "highlight.svg"));
         }
         catch (Clutter.TextureError e)
         {
@@ -292,6 +375,17 @@ private class TileActor : Clutter.Clone
     }
 }
 
+public class CursorActor : Clutter.Clone
+{
+   public CursorActor (Clutter.Texture texture, int size)
+    {
+        source = texture;
+        opacity = 180;
+        set_size (size, size);
+        set_anchor_point (size / 2, size / 2);
+    }
+}
+
 /**
  *  This class defines the view of a score. All clutter related stuff goes here
  */
diff --git a/swell-foop/src/swell-foop.vala b/swell-foop/src/swell-foop.vala
index efb0207..bb8261f 100644
--- a/swell-foop/src/swell-foop.vala
+++ b/swell-foop/src/swell-foop.vala
@@ -93,7 +93,6 @@ public class SwellFoop : Gtk.Application
             var ui_description =
             "<ui>" +
             "    <toolbar name='Toolbar'>" +
-            "        <toolitem action='NewGame'/>" +
             "    </toolbar>" +
             "</ui>";
             ui_manager.add_ui_from_string (ui_description, -1);
@@ -157,14 +156,12 @@ public class SwellFoop : Gtk.Application
         view.is_zealous = settings.get_boolean ("zealous");
         view.game = game;
         stage.add_actor (view);
-
         /* Request an appropriate size for the game view */
         stage.set_size (view.width, view.height);
         clutter_embed.set_size_request ((int) stage.width, (int) stage.height);
 
         /* When the mouse leaves the window we need to update the view */
         clutter_embed.leave_notify_event.connect (view.board_left_cb);
-
         high_scores = new GnomeGamesSupport.Scores ("swell-foop",
                                                     new GnomeGamesSupport.ScoresCategory[0],
                                                     null, null, 0,
@@ -173,6 +170,38 @@ public class SwellFoop : Gtk.Application
         high_scores.add_category ("small", _("Small"));
         high_scores.add_category ("normal", _("Normal"));
         high_scores.add_category ("large", _("Large"));
+
+        stage.key_release_event.connect (key_release_event_cb);
+    }
+
+    private bool key_release_event_cb (Clutter.Actor actor, Clutter.KeyEvent event)
+    {
+        switch (event.keyval)
+        {
+            case Clutter.Key.F2:
+                new_game ();
+                break;
+            case Clutter.Key.Up:
+                view.cursor_move (0, 1);
+                break;
+            case Clutter.Key.Down:
+                view.cursor_move (0, -1);
+                break;
+            case Clutter.Key.Left:
+                view.cursor_move (-1, 0);
+                break;
+            case Clutter.Key.Right:
+                view.cursor_move (1, 0);
+                break;
+            case Clutter.Key.space:
+            case Clutter.Key.Return:
+                view.cursor_click ();
+                break;
+            default:
+                break;
+        }
+
+        return false;
     }
 
     private Size get_size ()



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]