[gnome-2048] Add undo support
- From: Juan R. Garcia Blanco <juanrgar src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-2048] Add undo support
- Date: Sun, 1 Mar 2015 21:06:01 +0000 (UTC)
commit 8fc2ec808e3d54d9fa544c9f213df748f50a28f4
Author: Juan R. GarcĂa Blanco <juanrgar gmail com>
Date: Sun Mar 1 22:01:32 2015 +0100
Add undo support
* data/org.gnome.2048.gschema.xml: Add allow-undo and
allow-undo-max keys.
* data/preferences.ui: Add switch to control undo.
* src/application.vala: Connect to ::undo_* signals to
enable/disable undo action.
* src/game.vala: Add ::undo_enabled and ::undo_disabled signals;
create stack of undoable operations; push and pop operations
appropriately
* src/grid.vala: Add clone () method to effectively clone a Grid
instance.
* See https://bugzilla.gnome.org/show_bug.cgi?id=745332
data/org.gnome.2048.gschema.xml | 10 ++++++
data/preferences.ui | 44 ++++++++++++++++++++------
src/application.vala | 19 +++++++++++
src/game.vala | 65 ++++++++++++++++++++++++++++++++++----
src/grid.vala | 10 ++++++
5 files changed, 130 insertions(+), 18 deletions(-)
---
diff --git a/data/org.gnome.2048.gschema.xml b/data/org.gnome.2048.gschema.xml
index df0b3a6..4bf5241 100644
--- a/data/org.gnome.2048.gschema.xml
+++ b/data/org.gnome.2048.gschema.xml
@@ -40,5 +40,15 @@
<summary>Animations speed</summary>
<description>Duration of animations: show tile, move tile, and dim tile.</description>
</key>
+ <key name="allow-undo" type="b">
+ <default>false</default>
+ <summary>Allow undo</summary>
+ <description>Whether tile movements can be undone.</description>
+ </key>
+ <key name="allow-undo-max" type="i">
+ <default>10</default>
+ <summary>Number of undo movements</summary>
+ <description>Maximum number of tile movements that can be undone.</description>
+ </key>
</schema>
</schemalist>
diff --git a/data/preferences.ui b/data/preferences.ui
index faadf4c..3c93ca0 100644
--- a/data/preferences.ui
+++ b/data/preferences.ui
@@ -74,6 +74,31 @@
</packing>
</child>
<child>
+ <object class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Animations speed</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScale" id="animsscale">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="adjustment">animationsspeed</property>
+ <property name="inverted">True</property>
+ <property name="round_digits">1</property>
+ <property name="draw_value">False</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
<object class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="can_focus">False</property>
@@ -82,7 +107,7 @@
</object>
<packing>
<property name="left_attach">0</property>
- <property name="top_attach">2</property>
+ <property name="top_attach">3</property>
</packing>
</child>
<child>
@@ -93,32 +118,29 @@
</object>
<packing>
<property name="left_attach">1</property>
- <property name="top_attach">2</property>
+ <property name="top_attach">3</property>
</packing>
</child>
<child>
- <object class="GtkLabel" id="label3">
+ <object class="GtkLabel" id="label4">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="label" translatable="yes">Animations speed</property>
+ <property name="xalign">1</property>
+ <property name="label" translatable="yes">Allow undo</property>
</object>
<packing>
<property name="left_attach">0</property>
- <property name="top_attach">1</property>
+ <property name="top_attach">2</property>
</packing>
</child>
<child>
- <object class="GtkScale" id="animsscale">
+ <object class="GtkSwitch" id="undoswitch">
<property name="visible">True</property>
<property name="can_focus">True</property>
- <property name="adjustment">animationsspeed</property>
- <property name="inverted">True</property>
- <property name="round_digits">1</property>
- <property name="draw_value">False</property>
</object>
<packing>
<property name="left_attach">1</property>
- <property name="top_attach">1</property>
+ <property name="top_attach">2</property>
</packing>
</child>
</object>
diff --git a/src/application.vala b/src/application.vala
index 44ebcff..d4d0396 100644
--- a/src/application.vala
+++ b/src/application.vala
@@ -24,6 +24,7 @@ public class Application : Gtk.Application
private Gtk.Window _window;
private Gtk.HeaderBar _header_bar;
+ private Gtk.Button _undo_button;
private Gtk.Button _new_game_button;
private Gtk.AboutDialog _about_dialog;
private Gtk.Dialog _preferences_dialog;
@@ -50,6 +51,7 @@ public class Application : Gtk.Application
private const GLib.ActionEntry[] action_entries =
{
{ "new-game", new_game_cb },
+ { "undo", undo_cb },
{ "scores", scores_cb },
{ "about", about_cb },
{ "preferences", preferences_cb },
@@ -160,6 +162,12 @@ public class Application : Gtk.Application
}
debug ("target value reached");
});
+ _game.undo_enabled.connect ((s) => {
+ ((SimpleAction) lookup_action ("undo")).set_enabled (true);
+ });
+ _game.undo_disabled.connect ((s) => {
+ ((SimpleAction) lookup_action ("undo")).set_enabled (false);
+ });
}
private void _create_window (Gtk.Builder builder)
@@ -203,6 +211,11 @@ public class Application : Gtk.Application
_score = new Gtk.Label ("0");
_header_bar.pack_end (_score);
+ _undo_button = new Gtk.Button.from_icon_name ("edit-undo-symbolic");
+ _undo_button.set_action_name ("app.undo");
+ _header_bar.pack_start (_undo_button);
+ ((SimpleAction) lookup_action ("undo")).set_enabled (false);
+
_new_game_button = new Gtk.Button.with_label (_("New Game"));
_new_game_button.set_action_name ("app.new-game");
_header_bar.pack_start (_new_game_button);
@@ -281,6 +294,7 @@ public class Application : Gtk.Application
_settings.bind ("do-congrat", builder.get_object ("congratswitch"), "active",
GLib.SettingsBindFlags.DEFAULT);
_settings.bind ("animations-speed", builder.get_object ("animationsspeed"), "value",
GLib.SettingsBindFlags.DEFAULT);
+ _settings.bind ("allow-undo", builder.get_object ("undoswitch"), "active",
GLib.SettingsBindFlags.DEFAULT);
}
private void _create_congrats_dialog (Gtk.Builder builder)
@@ -324,6 +338,11 @@ public class Application : Gtk.Application
_game.new_game ();
}
+ private void undo_cb ()
+ {
+ _game.undo ();
+ }
+
private void scores_cb ()
{
_scores_ctx.run_dialog ();
diff --git a/src/game.vala b/src/game.vala
index dfd37af..b20ad67 100644
--- a/src/game.vala
+++ b/src/game.vala
@@ -49,6 +49,10 @@ public class Game : GLib.Object
private Clutter.TransitionGroup _move_trans;
private int _animations_duration;
+ private bool _allow_undo;
+ private uint _undo_stack_max_size;
+ private Gee.LinkedList<Grid> _undo_stack;
+
private GLib.Settings _settings;
private string _saved_path;
@@ -57,6 +61,8 @@ public class Game : GLib.Object
public signal void finished ();
public signal void target_value_reached (uint val);
+ public signal void undo_enabled ();
+ public signal void undo_disabled ();
public Game (GLib.Settings settings)
{
@@ -76,6 +82,10 @@ public class Game : GLib.Object
_to_hide = new Gee.LinkedList<TileMovement?> ();
_to_show = new Gee.LinkedList<Tile?> ();
+ _undo_stack = new Gee.LinkedList<Grid> ();
+ _allow_undo = _settings.get_boolean ("allow-undo");
+ _undo_stack_max_size = _settings.get_int ("allow-undo-max");
+
_saved_path = Path.build_filename (Environment.get_user_data_dir (), "gnome-2048", "saved");
_state = GameState.STOPPED;
@@ -96,12 +106,24 @@ public class Game : GLib.Object
public void new_game ()
{
_grid.clear ();
+ _undo_stack.clear ();
_clear_foreground ();
score = 0;
_state = GameState.SHOWING_FIRST_TILE;
_create_random_tile ();
}
+ public void undo ()
+ {
+ Grid grid = _undo_stack.poll_head ();
+ _clear_foreground ();
+ _grid = grid;
+ _restore_foreground (false);
+
+ if (_undo_stack.size == 0)
+ undo_disabled ();
+ }
+
public void save_game ()
{
string contents = "";
@@ -139,7 +161,7 @@ public class Game : GLib.Object
if (_background != null)
_clear_background ();
_init_background ();
- _restore_foreground ();
+ _restore_foreground (true);
debug ("game restored successfully");
return true;
@@ -169,9 +191,18 @@ public class Game : GLib.Object
public bool reload_settings ()
{
int rows, cols;
+ bool allow_undo;
_animations_duration = (int)_settings.get_double ("animations-speed");
+ allow_undo = _settings.get_boolean ("allow-undo");
+ if (_allow_undo && !allow_undo) {
+ _undo_stack.clear ();
+ undo_disabled ();
+ }
+ _allow_undo = allow_undo;
+ _undo_stack_max_size = _settings.get_int ("allow-undo-max");
+
rows = _settings.get_int ("rows");
cols = _settings.get_int ("cols");
@@ -299,7 +330,7 @@ public class Game : GLib.Object
Tile tile;
if (_grid.new_tile (out tile)) {
- _create_show_hide_transition ();
+ _create_show_hide_transition (true);
_create_tile (tile);
_to_show.add (tile);
@@ -336,6 +367,8 @@ public class Game : GLib.Object
bool has_moved;
+ _store_movement ();
+
_move_trans = new Clutter.TransitionGroup ();
_move_trans.stopped.connect (_on_move_trans_stopped);
_move_trans.set_duration (_animations_duration);
@@ -362,6 +395,8 @@ public class Game : GLib.Object
bool has_moved;
+ _store_movement ();
+
_move_trans = new Clutter.TransitionGroup ();
_move_trans.stopped.connect (_on_move_trans_stopped);
_move_trans.set_duration (_animations_duration);
@@ -388,6 +423,8 @@ public class Game : GLib.Object
bool has_moved;
+ _store_movement ();
+
_move_trans = new Clutter.TransitionGroup ();
_move_trans.stopped.connect (_on_move_trans_stopped);
_move_trans.set_duration (_animations_duration);
@@ -414,6 +451,8 @@ public class Game : GLib.Object
bool has_moved;
+ _store_movement ();
+
_move_trans = new Clutter.TransitionGroup ();
_move_trans.stopped.connect (_on_move_trans_stopped);
_move_trans.set_duration (_animations_duration);
@@ -553,7 +592,7 @@ public class Game : GLib.Object
}
}
- private void _restore_foreground ()
+ private void _restore_foreground (bool animate)
{
uint val;
GridPosition pos;
@@ -561,7 +600,7 @@ public class Game : GLib.Object
int rows = _grid.rows;
int cols = _grid.cols;
- _create_show_hide_transition ();
+ _create_show_hide_transition (animate);
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
@@ -591,7 +630,7 @@ public class Game : GLib.Object
_move_trans.remove_all ();
- _create_show_hide_transition ();
+ _create_show_hide_transition (true);
foreach (var e in _to_hide) {
_dim_tile (e.from);
@@ -636,11 +675,11 @@ public class Game : GLib.Object
GLib.Timeout.add (100, _finish_move);
}
- private void _create_show_hide_transition ()
+ private void _create_show_hide_transition (bool animate)
{
_show_hide_trans = new Clutter.TransitionGroup ();
_show_hide_trans.stopped.connect (_on_show_hide_trans_stopped);
- _show_hide_trans.set_duration (_animations_duration);
+ _show_hide_trans.set_duration (animate ? _animations_duration : 10);
}
private bool _finish_move ()
@@ -680,4 +719,16 @@ public class Game : GLib.Object
return false;
}
+
+ private void _store_movement ()
+ {
+ if (_allow_undo) {
+ if (_undo_stack.size == _undo_stack_max_size)
+ _undo_stack.poll_tail ();
+ _undo_stack.offer_head (_grid.clone ());
+ if (_undo_stack.size == 1) {
+ undo_enabled ();
+ }
+ }
+ }
}
diff --git a/src/grid.vala b/src/grid.vala
index d402b65..ef2a16d 100644
--- a/src/grid.vala
+++ b/src/grid.vala
@@ -45,6 +45,16 @@ public class Grid : GLib.Object
get; set;
}
+ public Grid clone ()
+ {
+ Grid grid = new Grid (_rows, _cols);
+ grid._grid = _grid;
+ grid._target_value = _target_value;
+ grid._target_value_reached = _target_value_reached;
+
+ return grid;
+ }
+
public void clear ()
{
for (uint i = 0; i < _grid.length[0]; i++) {
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]