[gnome-2048] Indent, move, comment.



commit 1f6aa3cbb5df50760341a677fc2698036245d704
Author: Arnaud Bonatti <arnaud bonatti gmail com>
Date:   Thu Mar 3 14:23:30 2016 +0100

    Indent, move, comment.

 data/org.gnome.gnome-2048.appdata.xml.in |    3 +-
 gnome-2048.doap                          |    7 +
 src/application.vala                     |  721 +++++++++---------
 src/config.vapi                          |    3 +-
 src/game.vala                            | 1213 +++++++++++++++---------------
 src/grid.vala                            |  995 +++++++++++++------------
 src/view.vala                            |  300 ++++----
 7 files changed, 1648 insertions(+), 1594 deletions(-)
---
diff --git a/data/org.gnome.gnome-2048.appdata.xml.in b/data/org.gnome.gnome-2048.appdata.xml.in
index e90c376..99723b6 100644
--- a/data/org.gnome.gnome-2048.appdata.xml.in
+++ b/data/org.gnome.gnome-2048.appdata.xml.in
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright 2015 Juan R. García Blanco -->
+<!-- Copyright 2015 Juan R. García Blanco <juanrgar gmail com>
+     Copyright 2016 Arnaud Bonatti <arnaud bonatti gmail com> -->
 <component type="desktop">
   <id>org.gnome.gnome-2048.desktop</id>
   <metadata_license>CC-BY-SA-3.0</metadata_license>
diff --git a/gnome-2048.doap b/gnome-2048.doap
index f987637..0135958 100644
--- a/gnome-2048.doap
+++ b/gnome-2048.doap
@@ -16,6 +16,13 @@
 
   <maintainer>
     <foaf:Person>
+      <foaf:name>Arnaud Bonatti</foaf:name>
+      <foaf:mbox rdf:resource="mailto:arnaud bonatti gmail com" />
+      <gnome:userid>arnaudb</gnome:userid>
+    </foaf:Person>
+  </maintainer>
+  <maintainer>
+    <foaf:Person>
       <foaf:name>Juan R. García Blanco</foaf:name>
       <foaf:mbox rdf:resource="mailto:juanrgar gmail com" />
       <gnome:userid>juanrgar</gnome:userid>
diff --git a/src/application.vala b/src/application.vala
index abe3d15..c10aa42 100644
--- a/src/application.vala
+++ b/src/application.vala
@@ -1,4 +1,5 @@
-/* Copyright (C) 2014-2015 Juan R. García Blanco
+/* Copyright (C) 2014-2015 Juan R. García Blanco <juanrgar gmail com>
+ * Copyright (C) 2016 Arnaud Bonatti <arnaud bonatti gmail com>
  *
  * This file is part of GNOME 2048.
  *
@@ -21,405 +22,407 @@ using Gtk;
 
 public class Application : Gtk.Application
 {
-  private GLib.Settings _settings;
+    /* settings */
+    private GLib.Settings _settings;
+
+    private int _window_width;
+    private int _window_height;
+    private bool _window_maximized;
+
+    private int WINDOW_MINIMUM_SIZE_HEIGHT = 600;
+    private int WINDOW_MINIMUM_SIZE_WIDTH = 600;
+
+    /* private widgets */
+    private Window _window;
+    private HeaderBar _header_bar;
+    private Button _undo_button;
+    private Button _new_game_button;
+    private Dialog _preferences_dialog;
+    private Dialog _congrats_dialog;
+    private Label _congrats_message;
+    private Label _score;
+    private ComboBoxText _grid_size_combo;
+
+    private Scores.Context _scores_ctx;
+    private Scores.Category _grid4_cat;
+    private Scores.Category _grid5_cat;
+
+    private bool _game_restored;
+
+    private Game _game;
+
+    /* actions */
+    private const GLib.ActionEntry[] action_entries =
+    {
+        { "undo",           undo_cb           },
+
+        // app-menu
+        { "new-game",       new_game_cb       },
+        { "scores",         scores_cb         },
+
+        { "preferences",    preferences_cb    },
+
+/*        { "help",           help_cb           }, */
+        { "about",          about_cb          },
+        { "quit",           quit_cb           }
+    };
+
+    public static int main (string[] args)
+    {
+        Intl.setlocale (LocaleCategory.ALL, "");
+        Intl.bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+        Intl.bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+        Intl.textdomain (GETTEXT_PACKAGE);
+
+        OptionContext context = new OptionContext ("");
+
+        context.add_group (get_option_group (true));
+        context.add_group (Clutter.get_option_group_without_init ());
+
+        try {
+            context.parse (ref args);
+        } catch (Error e) {
+            stderr.printf ("%s\n", e.message);
+            return Posix.EXIT_FAILURE;
+        }
+
+        Environment.set_application_name ("org.gnome.gnome-2048");
+        Window.set_default_icon_name ("gnome-2048");
+
+        try {
+            GtkClutter.init_with_args (ref args, "", new OptionEntry[0], null);
+        } catch (Error e) {
+            MessageDialog dialog = new MessageDialog (null,
+                                                      DialogFlags.MODAL,
+                                                      MessageType.ERROR,
+                                                      ButtonsType.NONE,
+                                                      "Unable to initialize Clutter:\n%s", e.message);
+            dialog.set_title (Environment.get_application_name ());
+            dialog.run ();
+            dialog.destroy ();
+            return Posix.EXIT_FAILURE;
+        }
+
+        Application app = new Application ();
+        return app.run (args);
+    }
+
+    public Application ()
+    {
+        Object (application_id: "org.gnome.gnome-2048", flags: ApplicationFlags.FLAGS_NONE);
+    }
 
-  private Window _window;
-  private HeaderBar _header_bar;
-  private Button _undo_button;
-  private Button _new_game_button;
-  private Dialog _preferences_dialog;
-  private Dialog _congrats_dialog;
-  private Label _congrats_message;
-  private Label _score;
-  private ComboBoxText _grid_size_combo;
+    protected override void startup ()
+    {
+        base.startup ();
 
-  private Scores.Context _scores_ctx;
-  private Scores.Category _grid4_cat;
-  private Scores.Category _grid5_cat;
+        add_action_entries (action_entries, this);
 
-  private bool _game_restored;
+        _settings = new GLib.Settings ("org.gnome.2048");
 
-  private int _window_width;
-  private int _window_height;
-  private bool _window_maximized;
+/*        CssProvider provider = new CssProvider ();
+        provider.load_from_resource ("/org/gnome/gnome-2048/data/style.css");
+        StyleContext.add_provider_for_screen (Gdk.Screen.get_default (), provider, 
STYLE_PROVIDER_PRIORITY_APPLICATION); */
 
-  private int WINDOW_MINIMUM_SIZE_HEIGHT = 600;
-  private int WINDOW_MINIMUM_SIZE_WIDTH = 600;
+        _init_game ();
+    }
+
+    protected override void activate ()
+    {
+        base.activate ();
 
-  private Game _game;
+        Builder builder = new Builder ();
+        _create_window (builder);
+        _create_preferences_dialog (builder);
+        _create_congrats_dialog (builder);
 
-  private const GLib.ActionEntry[] action_entries =
-  {
-    { "undo",           undo_cb           },
+        _create_scores ();
 
-    // app-menu
-    { "new-game",       new_game_cb       },
-    { "scores",         scores_cb         },
+        _window.show_all ();
 
-    { "preferences",    preferences_cb    },
+        _game_restored = _game.restore_game ();
+        if (!_game_restored)
+            new_game_cb ();
+    }
 
-/*    { "help",           help_cb           }, */
-    { "about",          about_cb          },
-    { "quit",           quit_cb           }
-  };
+    protected override void shutdown ()
+    {
+        base.shutdown ();
 
-  public Application ()
-  {
-    Object (application_id: "org.gnome.gnome-2048", flags: ApplicationFlags.FLAGS_NONE);
-  }
+        _game.save_game ();
 
-  protected override void startup ()
-  {
-    base.startup ();
+        _settings.set_int ("window-width", _window_width);
+        _settings.set_int ("window-height", _window_height);
+        _settings.set_boolean ("window-maximized", _window_maximized);
+    }
 
-    add_action_entries (action_entries, this);
+    private void _init_game ()
+    {
+        _game = new Game (_settings);
+        _game.notify["score"].connect ((s, p) => {
+                _score.label = _game.score.to_string ();
+            });
+        _game.finished.connect ((s) => {
+                _header_bar.subtitle = _("Game Over");
+
+                if (!_game_restored)
+                {
+                    Scores.Category cat = (_settings.get_int ("rows") == 4) ? _grid4_cat : _grid5_cat;
+                    _scores_ctx.add_score.begin (_game.score, cat, null, (object, result) => {
+                            try {
+                                _scores_ctx.add_score.end (result);
+                            } catch (GLib.Error e) {
+                                stderr.printf ("%s\n", e.message);
+                            }
+                            ((SimpleAction) lookup_action ("scores")).set_enabled (true);
+                            debug ("score added");
+                        });
+                }
+
+                debug ("finished");
+            });
+        _game.target_value_reached.connect ((s, v) => {
+                if (_settings.get_boolean ("do-congrat"))
+                {
+                    string message = _("You have obtained the %u tile".printf (v));
+                    _congrats_message.set_text (message);
+                    _congrats_dialog.present ();
+                    _settings.set_boolean ("do-congrat", false);
+                }
+                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);
+            });
+    }
 
-    _settings = new GLib.Settings ("org.gnome.2048");
+    private void _create_window (Builder builder)
+    {
+        try {
+            builder.add_from_resource ("/org/gnome/gnome-2048/data/mainwindow.ui");
+        } catch (GLib.Error e) {
+            stderr.printf ("%s\n", e.message);
+        }
 
-/*    CssProvider provider = new CssProvider ();
-    provider.load_from_resource ("/org/gnome/gnome-2048/data/style.css");
-    StyleContext.add_provider_for_screen (Gdk.Screen.get_default (), provider, 
STYLE_PROVIDER_PRIORITY_APPLICATION); */
+        _window = (ApplicationWindow) builder.get_object ("applicationwindow");
+        _window.set_default_size (_settings.get_int ("window-width"), _settings.get_int ("window-height"));
+        if (_settings.get_boolean ("window-maximized"))
+            _window.maximize ();
 
-    _init_game ();
-  }
+        add_window (_window);
 
-  protected override void activate ()
-  {
-    base.activate ();
+        _create_header_bar ();
+        _create_game_view (builder);
 
-    var builder = new Builder ();
-    _create_window (builder);
-    _create_preferences_dialog (builder);
-    _create_congrats_dialog (builder);
+        _window.set_events (_window.get_events () | Gdk.EventMask.STRUCTURE_MASK | 
Gdk.EventMask.KEY_PRESS_MASK | Gdk.EventMask.KEY_RELEASE_MASK);
+        _window.key_press_event.connect (key_press_event_cb);
+        _window.size_allocate.connect (window_size_allocate_cb);
+        _window.window_state_event.connect (window_state_event_cb);
 
-    _create_scores ();
+        Gdk.Geometry geom = Gdk.Geometry ();
+        geom.min_height = WINDOW_MINIMUM_SIZE_HEIGHT;
+        geom.min_width = WINDOW_MINIMUM_SIZE_WIDTH;
+        _window.set_geometry_hints (_window, geom, Gdk.WindowHints.MIN_SIZE);
+    }
 
-    _window.show_all ();
+    private void _create_header_bar ()
+    {
+        _header_bar = new HeaderBar ();
+        _header_bar.show_close_button = true;
+        _header_bar.title = "2048";
+        _window.set_titlebar (_header_bar);
 
-    _game_restored = _game.restore_game ();
-    if (!_game_restored)
-      new_game_cb ();
-  }
+        _score = new Label ("0");
+        _header_bar.pack_end (_score);
 
-  protected override void shutdown ()
-  {
-    base.shutdown ();
+        _undo_button = new 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);
 
-    _game.save_game ();
+        _new_game_button = new Button.with_label (_("New Game"));
+        _new_game_button.set_action_name ("app.new-game");
+        _header_bar.pack_start (_new_game_button);
+    }
 
-    _settings.set_int ("window-width", _window_width);
-    _settings.set_int ("window-height", _window_height);
-    _settings.set_boolean ("window-maximized", _window_maximized);
-  }
+    private void _create_game_view (Builder builder)
+    {
+        GtkClutter.Embed embed = new GtkClutter.Embed ();
+        AspectFrame frame = (AspectFrame) builder.get_object ("aspectframe");
+        frame.add (embed);
+        _game.view = embed.get_stage ();
+    }
 
-  private void _init_game ()
-  {
-    _game = new Game (_settings);
-    _game.notify["score"].connect ((s, p) => {
-      _score.label = _game.score.to_string ();
-    });
-    _game.finished.connect ((s) => {
-      _header_bar.subtitle = _("Game Over");
+    private void _create_preferences_dialog (Builder builder)
+    {
+        try {
+            builder.add_from_resource ("/org/gnome/gnome-2048/data/preferences.ui");
+        } catch (GLib.Error e) {
+            stderr.printf ("%s\n", e.message);
+        }
+
+        _preferences_dialog = (Dialog) builder.get_object ("preferencesdialog");
+        _preferences_dialog.set_transient_for (_window);
+
+        _grid_size_combo = (ComboBoxText) builder.get_object ("gridsizecombo");
+
+        _preferences_dialog.response.connect ((response_id) => {
+                _preferences_dialog.hide_on_delete ();
+            });
+        _preferences_dialog.delete_event.connect ((response_id) => {
+                int grid_size;
+                int rows, cols;
+                bool settings_changed;
+
+                grid_size = _grid_size_combo.get_active ();
+                if (grid_size == 0)
+                    rows = cols = 4;
+                else
+                    rows = cols = 5;
+
+                _settings.set_int ("rows", rows);
+                _settings.set_int ("cols", cols);
+
+                settings_changed = _game.reload_settings ();
+                if (settings_changed)
+                    new_game_cb ();
+                return _preferences_dialog.hide_on_delete ();
+            });
+
+        _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);
+    }
 
-      if (!_game_restored) {
-        Scores.Category cat = (_settings.get_int ("rows") == 4) ? _grid4_cat : _grid5_cat;
-        _scores_ctx.add_score.begin (_game.score, cat, null, (object, result) => {
-          try {
-            _scores_ctx.add_score.end (result);
-          } catch (GLib.Error e) {
+    private void _create_congrats_dialog (Builder builder)
+    {
+        try {
+            builder.add_from_resource ("/org/gnome/gnome-2048/data/congrats.ui");
+        } catch (GLib.Error e) {
             stderr.printf ("%s\n", e.message);
-          }
-          ((SimpleAction) lookup_action ("scores")).set_enabled (true);
-          debug ("score added");
-        });
-      }
-
-      debug ("finished");
-    });
-    _game.target_value_reached.connect ((s, v) => {
-      if (_settings.get_boolean ("do-congrat")) {
-        string message = _("You have obtained the %u tile".printf (v));
-        _congrats_message.set_text (message);
-        _congrats_dialog.present ();
-        _settings.set_boolean ("do-congrat", false);
-      }
-      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 (Builder builder)
-  {
-    try {
-      builder.add_from_resource ("/org/gnome/gnome-2048/data/mainwindow.ui");
-    } catch (GLib.Error e) {
-      stderr.printf ("%s\n", e.message);
+        }
+
+        _congrats_dialog = (Dialog) builder.get_object ("congratsdialog");
+        _congrats_dialog.set_transient_for (_window);
+
+        _congrats_dialog.response.connect ((response_id) => {
+                if (response_id == 0)
+                    new_game_cb ();
+                _congrats_dialog.hide ();
+            });
+        _congrats_dialog.delete_event.connect ((response_id) => {
+                return _congrats_dialog.hide_on_delete ();
+            });
+
+        _congrats_message = (Label) builder.get_object ("messagelabel");
+    }
+
+    private Games.Scores.Category category_request (string key)
+    {
+        if (key == "grid4") return _grid4_cat;
+        if (key == "grid5") return _grid5_cat;
+        assert_not_reached ();
     }
 
-    _window = (ApplicationWindow) builder.get_object ("applicationwindow");
-    _window.set_default_size (_settings.get_int ("window-width"), _settings.get_int ("window-height"));
-    if (_settings.get_boolean ("window-maximized"))
-      _window.maximize ();
-
-    add_window (_window);
-
-    _create_header_bar ();
-    _create_game_view (builder);
-
-    _window.set_events (_window.get_events () | Gdk.EventMask.STRUCTURE_MASK | Gdk.EventMask.KEY_PRESS_MASK 
| Gdk.EventMask.KEY_RELEASE_MASK);
-    _window.key_press_event.connect (key_press_event_cb);
-    _window.size_allocate.connect (window_size_allocate_cb);
-    _window.window_state_event.connect (window_state_event_cb);
-
-    Gdk.Geometry geom = Gdk.Geometry ();
-    geom.min_height = WINDOW_MINIMUM_SIZE_HEIGHT;
-    geom.min_width = WINDOW_MINIMUM_SIZE_WIDTH;
-    _window.set_geometry_hints (_window, geom, Gdk.WindowHints.MIN_SIZE);
-  }
-
-  private void _create_header_bar ()
-  {
-    _header_bar = new HeaderBar ();
-    _header_bar.show_close_button = true;
-    _header_bar.title = "2048";
-    _window.set_titlebar (_header_bar);
-
-    _score = new Label ("0");
-    _header_bar.pack_end (_score);
-
-    _undo_button = new 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 Button.with_label (_("New Game"));
-    _new_game_button.set_action_name ("app.new-game");
-    _header_bar.pack_start (_new_game_button);
-  }
-
-  private void _create_game_view (Builder builder)
-  {
-    var embed = new GtkClutter.Embed ();
-    var frame = (AspectFrame) builder.get_object ("aspectframe");
-    frame.add (embed);
-    _game.view = embed.get_stage ();
-  }
-
-  private void _create_preferences_dialog (Builder builder)
-  {
-    try {
-      builder.add_from_resource ("/org/gnome/gnome-2048/data/preferences.ui");
-    } catch (GLib.Error e) {
-      stderr.printf ("%s\n", e.message);
+    private void _create_scores ()
+    {
+        // FIXME: The category names should be marked for translation and use the × character.
+        _grid4_cat = new Scores.Category ("grid4", "Grid 4 x 4");
+        _grid5_cat = new Scores.Category ("grid5", "Grid 5 x 5");
+
+        // FIXME: The second parameter should be _("Grid Size:") but we're in string freeze.
+        _scores_ctx = new Scores.Context ("gnome-2048", "", _window, category_request, 
Scores.Style.POINTS_GREATER_IS_BETTER);
+    }
+
+    /*\
+    * * App-menu (and undo action) callbacks
+    \*/
+
+    private void undo_cb ()
+    {
+        _game.undo ();
     }
 
-    _preferences_dialog = (Dialog) builder.get_object ("preferencesdialog");
-    _preferences_dialog.set_transient_for (_window);
-
-    _grid_size_combo = (ComboBoxText) builder.get_object ("gridsizecombo");
-
-    _preferences_dialog.response.connect ((response_id) => {
-      _preferences_dialog.hide_on_delete ();
-    });
-    _preferences_dialog.delete_event.connect ((response_id) => {
-      int grid_size;
-      int rows, cols;
-      bool settings_changed;
-
-      grid_size = _grid_size_combo.get_active ();
-      if (grid_size == 0) {
-        rows = cols = 4;
-      } else {
-        rows = cols = 5;
-      }
-
-      _settings.set_int ("rows", rows);
-      _settings.set_int ("cols", cols);
-
-      settings_changed = _game.reload_settings ();
-      if (settings_changed)
-        new_game_cb ();
-      return _preferences_dialog.hide_on_delete ();
-    });
-
-    _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 (Builder builder)
-  {
-    try {
-      builder.add_from_resource ("/org/gnome/gnome-2048/data/congrats.ui");
-    } catch (GLib.Error e) {
-      stderr.printf ("%s\n", e.message);
+    private void new_game_cb ()
+    {
+        _header_bar.subtitle = null;
+        _game_restored = false;
+
+        _game.new_game ();
     }
 
-    _congrats_dialog = (Dialog) builder.get_object ("congratsdialog");
-    _congrats_dialog.set_transient_for (_window);
-
-    _congrats_dialog.response.connect ((response_id) => {
-      if (response_id == 0)
-        new_game_cb ();
-      _congrats_dialog.hide ();
-    });
-    _congrats_dialog.delete_event.connect ((response_id) => {
-      return _congrats_dialog.hide_on_delete ();
-    });
-
-    _congrats_message = (Label) builder.get_object ("messagelabel");
-  }
-
-  private Games.Scores.Category category_request (string key)
-  {
-    if (key == "grid4")
-      return _grid4_cat;
-    else if (key == "grid5")
-      return _grid5_cat;
-    assert_not_reached ();
-  }
-
-  private void _create_scores ()
-  {
-    // FIXME: The category names should be marked for translation and use the × character.
-    _grid4_cat = new Scores.Category ("grid4", "Grid 4 x 4");
-    _grid5_cat = new Scores.Category ("grid5", "Grid 5 x 5");
-
-    // FIXME: The second parameter should be _("Grid Size:") but we're in string freeze.
-    _scores_ctx = new Scores.Context ("gnome-2048", "", _window, category_request, 
Scores.Style.POINTS_GREATER_IS_BETTER);
-  }
-
-  private void new_game_cb ()
-  {
-    _header_bar.subtitle = null;
-    _game_restored = false;
-
-    _game.new_game ();
-  }
-
-  private void undo_cb ()
-  {
-    _game.undo ();
-  }
-
-  private void scores_cb ()
-  {
-    _scores_ctx.run_dialog ();
-  }
-
-  private void about_cb ()
-  {
-    string [] authors = { "Juan R. García Blanco", "Arnaud Bonatti" };
-    show_about_dialog (_window /* get_active_window () */,
-                       "program-name", "2048" /* TODO _("2048") */,
-                       "version", VERSION,
-                       "comments", _("A clone of 2048 for GNOME"),
-                       "copyright", _("Copyright \xc2\xa9 2014-2015 – Juan R. García Blanco\nCopyright 
\xc2\xa9 2016 – Arnaud Bonatti"),
-                       "license-type", License.GPL_3_0,
-                       "wrap-license", false /* TODO true? */,
-                       "authors", authors,
-                       "translator-credits", _("translator-credits"),
-                       "logo-icon-name", "gnome-2048",
-                       "website", "http://www.gnome.org";, /* TODO remove? better? */
-                       null);
-  }
-
-  private void preferences_cb ()
-  {
-    int grid_size;
-    int rows;
-
-    rows = _settings.get_int ("rows");
-
-    if (rows == 4) {
-      grid_size = 0;
-    } else {
-      grid_size = 1;
+    private void scores_cb ()
+    {
+        _scores_ctx.run_dialog ();
     }
 
-    _grid_size_combo.set_active (grid_size);
+    private void preferences_cb ()
+    {
+        if (_settings.get_int ("rows") == 4)
+            _grid_size_combo.set_active (0);
+        else
+            _grid_size_combo.set_active (1);
 
-    _preferences_dialog.present ();
-  }
+        _preferences_dialog.present ();
+    }
 
-  private void quit_cb ()
-  {
-    _window.destroy ();
-  }
+/*    private void help_cb ()
+    {
+        try {
+            show_uri (_window.get_screen (), "help:gnome-2048", get_current_event_time ());
+        } catch (GLib.Error e) {
+            warning ("Failed to show help: %s", e.message);
+        }
+    } */
+
+    private void about_cb ()
+    {
+        string [] authors = { "Juan R. García Blanco", "Arnaud Bonatti" };
+        show_about_dialog (_window /* get_active_window () */,
+                           "program-name", "2048" /* TODO _("2048") */,
+                           "version", VERSION,
+                           "comments", _("A clone of 2048 for GNOME"),
+                           "copyright", _("Copyright \xc2\xa9 2014-2015 – Juan R. García Blanco\nCopyright 
\xc2\xa9 2016 – Arnaud Bonatti"),
+                           "license-type", License.GPL_3_0,
+                           "wrap-license", false /* TODO true? */,
+                           "authors", authors,
+                           "translator-credits", _("translator-credits"),
+                           "logo-icon-name", "gnome-2048",
+                           "website", "http://www.gnome.org";, /* TODO remove? better? */
+                           null);
+    }
 
-/*  private void help_cb ()
-  {
-    try {
-      show_uri (_window.get_screen (), "help:gnome-2048", get_current_event_time ());
-    } catch (GLib.Error e) {
-      warning ("Failed to show help: %s", e.message);
+    private void quit_cb ()
+    {
+        _window.destroy ();
     }
-  } */
-
-  private bool key_press_event_cb (Widget widget, Gdk.EventKey event)
-  {
-    _game_restored = false;
-
-    return _game.key_pressed (event);
-  }
-
-  private void window_size_allocate_cb ()
-  {
-    if (_window_maximized)
-      return;
-    _window.get_size (out _window_width, out _window_height);
-  }
-
-  private bool window_state_event_cb (Gdk.EventWindowState event)
-  {
-    if ((event.changed_mask & Gdk.WindowState.MAXIMIZED) != 0)
-      _window_maximized = (event.new_window_state & Gdk.WindowState.MAXIMIZED) != 0;
-
-    return false;
-  }
-
-  public static int main (string[] args)
-  {
-    Intl.setlocale (LocaleCategory.ALL, "");
-    Intl.bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
-    Intl.bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
-    Intl.textdomain (GETTEXT_PACKAGE);
-
-    var context = new OptionContext ("");
-
-    context.add_group (get_option_group (true));
-    context.add_group (Clutter.get_option_group_without_init ());
-
-    try {
-      context.parse (ref args);
-    } catch (Error e) {
-      stderr.printf ("%s\n", e.message);
-      return Posix.EXIT_FAILURE;
+
+    /*\
+    * * Window management callbacks
+    \*/
+
+    private bool key_press_event_cb (Widget widget, Gdk.EventKey event)
+    {
+        _game_restored = false;
+
+        return _game.key_pressed (event);
     }
 
-    Environment.set_application_name ("org.gnome.gnome-2048");
-    Window.set_default_icon_name ("gnome-2048");
-
-    try {
-      GtkClutter.init_with_args (ref args, "", new OptionEntry[0], null);
-    } catch (Error e) {
-      MessageDialog dialog = new MessageDialog (null,
-                                                DialogFlags.MODAL,
-                                                MessageType.ERROR,
-                                                ButtonsType.NONE,
-                                                "Unable to initialize Clutter:\n%s", e.message);
-      dialog.set_title (Environment.get_application_name ());
-      dialog.run ();
-      dialog.destroy ();
-      return Posix.EXIT_FAILURE;
+    private void window_size_allocate_cb ()
+    {
+        if (_window_maximized)
+            return;
+        _window.get_size (out _window_width, out _window_height);
     }
 
-    var app = new Application ();
-    return app.run (args);
-  }
+    private bool window_state_event_cb (Gdk.EventWindowState event)
+    {
+        if ((event.changed_mask & Gdk.WindowState.MAXIMIZED) != 0)
+            _window_maximized = (event.new_window_state & Gdk.WindowState.MAXIMIZED) != 0;
+
+        return false;
+    }
 }
diff --git a/src/config.vapi b/src/config.vapi
index 8e68938..9c5d7dc 100644
--- a/src/config.vapi
+++ b/src/config.vapi
@@ -1,4 +1,5 @@
-/* Copyright (C) 2014-2015 Juan R. García Blanco
+/* Copyright (C) 2014-2015 Juan R. García Blanco <juanrgar gmail com>
+ * Copyright (C) 2016 Arnaud Bonatti <arnaud bonatti gmail com>
  *
  * This file is part of GNOME 2048.
  *
diff --git a/src/game.vala b/src/game.vala
index cc2aeac..d27a339 100644
--- a/src/game.vala
+++ b/src/game.vala
@@ -1,4 +1,5 @@
-/* Copyright (C) 2014-2015 Juan R. García Blanco
+/* Copyright (C) 2014-2015 Juan R. García Blanco <juanrgar gmail com>
+ * Copyright (C) 2016 Arnaud Bonatti <arnaud bonatti gmail com>
  *
  * This file is part of GNOME 2048.
  *
@@ -16,743 +17,767 @@
  * along with GNOME 2048; if not, see <http://www.gnu.org/licenses/>.
  */
 
-public class Game : GLib.Object
+public class Game : Object
 {
-  enum GameState {
-    STOPPED,
-    IDLE,
-    MOVING_DOWN,
-    MOVING_UP,
-    MOVING_RIGHT,
-    MOVING_LEFT,
-    SHOWING_FIRST_TILE,
-    SHOWING_SECOND_TILE,
-    RESTORING_TILES
-  }
-
-  private int BLANK_ROW_HEIGHT = 10;
-  private int BLANK_COL_WIDTH = 10;
-
-  private Grid _grid;
-
-  private uint _finish_move_id = 0;
-  private Clutter.Actor _view;
-  private Clutter.Actor _view_background;
-  private Clutter.Actor _view_foreground;
-  private RoundedRectangle[,] _background;
-  private TileView[,] _foreground_cur;
-  private TileView[,] _foreground_nxt;
-
-  private Gee.LinkedList<TileMovement?> _to_move;
-  private Gee.LinkedList<TileMovement?> _to_hide;
-  private Gee.LinkedList<Tile?> _to_show;
-
-  private GameState _state;
-  private Clutter.TransitionGroup _show_hide_trans;
-  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 Gee.LinkedList<uint> _undo_score_stack;
-
-  private GLib.Settings _settings;
-
-  private string _saved_path;
-
-  private uint _resize_view_id;
-
-  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)
-  {
-    Object ();
-
-    _settings = settings;
-
-    int rows = _settings.get_int ("rows");
-    int cols = _settings.get_int ("cols");
-    _grid = new Grid (rows, cols);
-
-    _animations_duration = (int)_settings.get_double ("animations-speed");
-
-    _settings.bind ("target-value", _grid, "target_value", GLib.SettingsBindFlags.DEFAULT);
-
-    _to_move = new Gee.LinkedList<TileMovement?> ();
-    _to_hide = new Gee.LinkedList<TileMovement?> ();
-    _to_show = new Gee.LinkedList<Tile?> ();
-
-    _view_background = new Clutter.Actor ();
-    _view_foreground = new Clutter.Actor ();
-    _view_background.show ();
-    _view_foreground.show ();
-
-    _undo_stack = new Gee.LinkedList<Grid> ();
-    _undo_score_stack = new Gee.LinkedList<uint> ();
-    _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;
-  }
-
-  public Clutter.Actor view {
-    get { return _view; }
-    set {
-      _view = value;
-      _view.allocation_changed.connect (_on_allocation_changed);
-      _view.add_child (_view_background);
-      _view.add_child (_view_foreground);
-    }
-  }
-
-  public uint score {
-    get; set;
-  }
-
-  public void new_game ()
-  {
-    if (_finish_move_id > 0)
-      Source.remove (_finish_move_id);
-    _grid.clear ();
-    _undo_stack.clear ();
-    _undo_score_stack.clear ();
-    // new_game could be called without an existing game
-    if (_background == null)
-      _init_background ();
-    else
-      _clear_foreground ();
-    score = 0;
-    _state = GameState.SHOWING_FIRST_TILE;
-    _create_random_tile ();
-    undo_disabled ();
-  }
+    enum GameState {
+        STOPPED,
+        IDLE,
+        MOVING_DOWN,
+        MOVING_UP,
+        MOVING_RIGHT,
+        MOVING_LEFT,
+        SHOWING_FIRST_TILE,
+        SHOWING_SECOND_TILE,
+        RESTORING_TILES
+    }
 
-  public void undo ()
-  {
-    Grid grid = _undo_stack.poll_head ();
-    uint delta_score = _undo_score_stack.poll_head ();
+    private int BLANK_ROW_HEIGHT = 10;
+    private int BLANK_COL_WIDTH = 10;
 
-    _clear_foreground ();
-    _grid = grid;
-    _restore_foreground (false);
-    score -= delta_score;
+    private Grid _grid;
 
-    if (_undo_stack.size == 0)
-      undo_disabled ();
-  }
+    private uint _finish_move_id = 0;
+    private Clutter.Actor _view;
+    private Clutter.Actor _view_background;
+    private Clutter.Actor _view_foreground;
+    private RoundedRectangle[,] _background;
+    private TileView[,] _foreground_cur;
+    private TileView[,] _foreground_nxt;
 
-  public void save_game ()
-  {
-    string contents = "";
+    private Gee.LinkedList<TileMovement?> _to_move;
+    private Gee.LinkedList<TileMovement?> _to_hide;
+    private Gee.LinkedList<Tile?> _to_show;
 
-    contents += _grid.save ();
-    contents += _score.to_string() + "\n";
+    private GameState _state;
+    private Clutter.TransitionGroup _show_hide_trans;
+    private Clutter.TransitionGroup _move_trans;
+    private int _animations_duration;
 
-    try {
-      DirUtils.create_with_parents (Path.get_dirname (_saved_path), 0775);
-      FileUtils.set_contents (_saved_path, contents);
-      debug ("game saved successfully");
-    } catch (FileError e) {
-      warning ("Failed to save game: %s", e.message);
-    }
-  }
+    private bool _allow_undo;
+    private uint _undo_stack_max_size;
+    private Gee.LinkedList<Grid> _undo_stack;
+    private Gee.LinkedList<uint> _undo_score_stack;
 
-  public bool restore_game ()
-  {
-    string contents;
-    string[] lines;
+    private GLib.Settings _settings;
 
-    try {
-      FileUtils.get_contents (_saved_path, out contents);
-    } catch (FileError e) {
-      return false;
-    }
+    private string _saved_path;
 
-    if (!_grid.load (contents)) {
-      warning ("Failed to restore game from saved file");
-      return false;
-    }
+    private uint _resize_view_id;
 
-    lines = contents.split ("\n");
-    score = (uint)int.parse (lines[lines.length-2]);
+    public signal void finished ();
+    public signal void target_value_reached (uint val);
+    public signal void undo_enabled ();
+    public signal void undo_disabled ();
 
-    if (_background != null)
-      _clear_background ();
-    _init_background ();
-    _restore_foreground (true);
+    public Game (GLib.Settings settings)
+    {
+        Object ();
 
-    debug ("game restored successfully");
-    return true;
-  }
+        _settings = settings;
 
-  public bool key_pressed (Gdk.EventKey event)
-  {
-    if (_state != GameState.IDLE) {
-      return true;
-    }
+        int rows = _settings.get_int ("rows");
+        int cols = _settings.get_int ("cols");
+        _grid = new Grid (rows, cols);
 
-    uint keyval = _upper_key (event.keyval);
+        _animations_duration = (int)_settings.get_double ("animations-speed");
 
-    if (keyval == Gdk.Key.Down) {
-      _move_down ();
-    } else if (keyval == Gdk.Key.Up) {
-      _move_up ();
-    } else if (keyval == Gdk.Key.Left) {
-      _move_left ();
-    } else if (keyval == Gdk.Key.Right) {
-      _move_right ();
-    }
+        _settings.bind ("target-value", _grid, "target_value", GLib.SettingsBindFlags.DEFAULT);
+
+        _to_move = new Gee.LinkedList<TileMovement?> ();
+        _to_hide = new Gee.LinkedList<TileMovement?> ();
+        _to_show = new Gee.LinkedList<Tile?> ();
 
-    return false;
-  }
+        _view_background = new Clutter.Actor ();
+        _view_foreground = new Clutter.Actor ();
+        _view_background.show ();
+        _view_foreground.show ();
 
-  public bool reload_settings ()
-  {
-    int rows, cols;
-    bool allow_undo;
+        _undo_stack = new Gee.LinkedList<Grid> ();
+        _undo_score_stack = new Gee.LinkedList<uint> ();
+        _allow_undo = _settings.get_boolean ("allow-undo");
+        _undo_stack_max_size = _settings.get_int ("allow-undo-max");
 
-    _animations_duration = (int)_settings.get_double ("animations-speed");
+        _saved_path = Path.build_filename (Environment.get_user_data_dir (), "gnome-2048", "saved");
 
-    allow_undo = _settings.get_boolean ("allow-undo");
-    if (_allow_undo && !allow_undo) {
-      _undo_stack.clear ();
-      _undo_score_stack.clear ();
-      undo_disabled ();
+        _state = GameState.STOPPED;
     }
-    _allow_undo = allow_undo;
-    _undo_stack_max_size = _settings.get_int ("allow-undo-max");
 
-    rows = _settings.get_int ("rows");
-    cols = _settings.get_int ("cols");
+    public Clutter.Actor view {
+        get { return _view; }
+        set {
+            _view = value;
+            _view.allocation_changed.connect (_on_allocation_changed);
+            _view.add_child (_view_background);
+            _view.add_child (_view_foreground);
+        }
+    }
 
-    if ((rows != _grid.rows) || (cols != _grid.cols)) {
-      _clear_foreground ();
+    public uint score {
+        get; set;
+    }
 
-      _clear_background ();
+    public void new_game ()
+    {
+        if (_finish_move_id > 0)
+            Source.remove (_finish_move_id);
+        _grid.clear ();
+        _undo_stack.clear ();
+        _undo_score_stack.clear ();
+        // new_game could be called without an existing game
+        if (_background == null)
+            _init_background ();
+        else
+            _clear_foreground ();
+        score = 0;
+        _state = GameState.SHOWING_FIRST_TILE;
+        _create_random_tile ();
+        undo_disabled ();
+    }
 
-      _grid = new Grid (rows, cols);
+    public void undo ()
+    {
+        Grid grid = _undo_stack.poll_head ();
+        uint delta_score = _undo_score_stack.poll_head ();
 
-      _init_background ();
+        _clear_foreground ();
+        _grid = grid;
+        _restore_foreground (false);
+        score -= delta_score;
 
-      return true;
+        if (_undo_stack.size == 0)
+            undo_disabled ();
     }
 
-    return false;
-  }
+    public void save_game ()
+    {
+        string contents = "";
 
-  private uint _upper_key (uint keyval)
-  {
-    return (keyval > 255) ? keyval : ((char) keyval).toupper ();
-  }
+        contents += _grid.save ();
+        contents += _score.to_string () + "\n";
 
-  private void _on_allocation_changed (Clutter.ActorBox box, Clutter.AllocationFlags flags)
-  {
-    if (_background == null) {
-      _init_background ();
-    } else {
-      _resize_view ();
+        try {
+            DirUtils.create_with_parents (Path.get_dirname (_saved_path), 0775);
+            FileUtils.set_contents (_saved_path, contents);
+            debug ("game saved successfully");
+        } catch (FileError e) {
+            warning ("Failed to save game: %s", e.message);
+        }
     }
-  }
 
-  private void _init_background ()
-  {
-    int rows = _grid.rows;
-    int cols = _grid.cols;
-    Clutter.Color background_color = Clutter.Color.from_string ("#babdb6");
-    _view.set_background_color (background_color);
+    public bool restore_game ()
+    {
+        string contents;
+        string[] lines;
 
-    _background = new RoundedRectangle[rows, cols];
-    _foreground_cur = new TileView[rows, cols];
-    _foreground_nxt = new TileView[rows, cols];
+        try {
+            FileUtils.get_contents (_saved_path, out contents);
+        } catch (FileError e) {
+            return false;
+        }
 
-    float canvas_width = _view.width;
-    float canvas_height = _view.height;
+        if (!_grid.load (contents))
+        {
+            warning ("Failed to restore game from saved file");
+            return false;
+        }
 
-    canvas_width -= (cols + 1) * BLANK_COL_WIDTH;
-    canvas_height -= (rows + 1) * BLANK_ROW_HEIGHT;
+        lines = contents.split ("\n");
+        score = (uint)int.parse (lines[lines.length-2]);
 
-    float tile_width = canvas_width / cols;
-    float tile_height = canvas_height / rows;
+        if (_background != null)
+            _clear_background ();
+        _init_background ();
+        _restore_foreground (true);
 
-    Clutter.Color color = Clutter.Color.from_string ("#ffffff");
+        debug ("game restored successfully");
+        return true;
+    }
 
-    for (int i = 0; i < rows; i++) {
-      for (int j = 0; j < cols; j++) {
-        float x = j * tile_width + (j+1) * BLANK_COL_WIDTH;
-        float y = i * tile_height + (i+1) * BLANK_ROW_HEIGHT;
+    public bool key_pressed (Gdk.EventKey event)
+    {
+        if (_state != GameState.IDLE)
+            return true;
 
-        RoundedRectangle rect = new RoundedRectangle (x, y, tile_width, tile_height, color);
+        uint keyval = _upper_key (event.keyval);
 
-        _view_background.add_child (rect.actor);
-        rect.canvas.invalidate ();
-        rect.actor.show ();
+        if (keyval == Gdk.Key.Down)       _move_down ();
+        else if (keyval == Gdk.Key.Up)    _move_up ();
+        else if (keyval == Gdk.Key.Left)  _move_left ();
+        else if (keyval == Gdk.Key.Right) _move_right ();
 
-        _background[i,j] = rect;
-        _foreground_cur[i,j] = null;
-        _foreground_nxt[i,j] = null;
-      }
+        return false;
     }
-  }
 
-  private void _resize_view ()
-  {
-    int rows = _grid.rows;
-    int cols = _grid.cols;
-    float canvas_width = _view.width;
-    float canvas_height = _view.height;
+    public bool reload_settings ()
+    {
+        int rows, cols;
+        bool allow_undo;
 
-    canvas_width -= (cols + 1) * BLANK_COL_WIDTH;
-    canvas_height -= (rows + 1) * BLANK_ROW_HEIGHT;
+        _animations_duration = (int)_settings.get_double ("animations-speed");
 
-    float tile_width = canvas_width / cols;
-    float tile_height = canvas_height / rows;
+        allow_undo = _settings.get_boolean ("allow-undo");
+        if (_allow_undo && !allow_undo)
+        {
+            _undo_stack.clear ();
+            _undo_score_stack.clear ();
+            undo_disabled ();
+        }
+        _allow_undo = allow_undo;
+        _undo_stack_max_size = _settings.get_int ("allow-undo-max");
 
-    for (int i = 0; i < rows; i++) {
-      for (int j = 0; j < cols; j++) {
-        float x = j * tile_width + (j+1) * BLANK_COL_WIDTH;
-        float y = i * tile_height + (i+1) * BLANK_ROW_HEIGHT;
+        rows = _settings.get_int ("rows");
+        cols = _settings.get_int ("cols");
 
-        _background[i,j].resize (x, y, tile_width, tile_height);
+        if ((rows != _grid.rows) || (cols != _grid.cols))
+        {
+            _clear_foreground ();
+            _clear_background ();
 
-        if (_foreground_cur[i,j] != null)
-          _foreground_cur[i,j].resize (x, y, tile_width, tile_height);
+            _grid = new Grid (rows, cols);
 
-        if (_foreground_nxt[i,j] != null)
-          _foreground_nxt[i,j].resize (x, y, tile_width, tile_height);
-      }
-    }
+            _init_background ();
 
-    if (_resize_view_id == 0)
-      _resize_view_id = Clutter.Threads.Timeout.add (1000, _idle_resize_view);
-  }
+            return true;
+        }
 
-  private bool _idle_resize_view ()
-  {
-    int rows = _grid.rows;
-    int cols = _grid.cols;
-    for (int i = 0; i < rows; i++) {
-      for (int j = 0; j < cols; j++) {
-        _background[i,j].idle_resize ();
+        return false;
+    }
 
-        if (_foreground_cur[i,j] != null) {
-          _foreground_cur[i,j].idle_resize ();
-        }
-      }
+    private uint _upper_key (uint keyval)
+    {
+        return (keyval > 255) ? keyval : ((char) keyval).toupper ();
     }
 
-    _resize_view_id = 0;
-    return false;
-  }
+    private void _on_allocation_changed (Clutter.ActorBox box, Clutter.AllocationFlags flags)
+    {
+        if (_background == null)
+            _init_background ();
+        else
+            _resize_view ();
+    }
+
+    private void _init_background ()
+    {
+        int rows = _grid.rows;
+        int cols = _grid.cols;
+        Clutter.Color background_color = Clutter.Color.from_string ("#babdb6");
+        _view.set_background_color (background_color);
+
+        _background = new RoundedRectangle[rows, cols];
+        _foreground_cur = new TileView[rows, cols];
+        _foreground_nxt = new TileView[rows, cols];
+
+        float canvas_width = _view.width;
+        float canvas_height = _view.height;
+
+        canvas_width -= (cols + 1) * BLANK_COL_WIDTH;
+        canvas_height -= (rows + 1) * BLANK_ROW_HEIGHT;
 
-  private void _create_random_tile ()
-  {
-    Tile tile;
+        float tile_width = canvas_width / cols;
+        float tile_height = canvas_height / rows;
 
-    if (_grid.new_tile (out tile)) {
-      _create_show_hide_transition (true);
+        Clutter.Color color = Clutter.Color.from_string ("#ffffff");
 
-      _create_tile (tile);
-      _to_show.add (tile);
-      _show_tile (tile.pos);
-      _show_hide_trans.start ();
+        for (int i = 0; i < rows; i++)
+        {
+            for (int j = 0; j < cols; j++)
+            {
+                float x = j * tile_width + (j+1) * BLANK_COL_WIDTH;
+                float y = i * tile_height + (i+1) * BLANK_ROW_HEIGHT;
+
+                RoundedRectangle rect = new RoundedRectangle (x, y, tile_width, tile_height, color);
+
+                _view_background.add_child (rect.actor);
+                rect.canvas.invalidate ();
+                rect.actor.show ();
+
+                _background[i,j] = rect;
+                _foreground_cur[i,j] = null;
+                _foreground_nxt[i,j] = null;
+            }
+        }
     }
-  }
 
-  private void _create_tile (Tile tile)
-  {
-    GridPosition pos;
-    RoundedRectangle rect;
-    TileView view;
-    float x;
-    float y;
-    float width;
-    float height;
+    private void _resize_view ()
+    {
+        int rows = _grid.rows;
+        int cols = _grid.cols;
+        float canvas_width = _view.width;
+        float canvas_height = _view.height;
+
+        canvas_width -= (cols + 1) * BLANK_COL_WIDTH;
+        canvas_height -= (rows + 1) * BLANK_ROW_HEIGHT;
 
-    pos = tile.pos;
-    rect = _background[pos.row,pos.col];
-    x = rect.actor.x;
-    y = rect.actor.y;
-    width = rect.actor.width;
-    height = rect.actor.height;
+        float tile_width = canvas_width / cols;
+        float tile_height = canvas_height / rows;
 
-    assert (_foreground_nxt[pos.row,pos.col] == null);
-    view = new TileView (x, y, width, height, tile.val);
-    _foreground_nxt[pos.row,pos.col] = view;
-  }
+        for (int i = 0; i < rows; i++)
+        {
+            for (int j = 0; j < cols; j++)
+            {
+                float x = j * tile_width + (j+1) * BLANK_COL_WIDTH;
+                float y = i * tile_height + (i+1) * BLANK_ROW_HEIGHT;
 
-  private void _move_down ()
-  {
-    debug ("move down");
+                _background[i,j].resize (x, y, tile_width, tile_height);
 
-    bool has_moved;
+                if (_foreground_cur[i,j] != null)
+                    _foreground_cur[i,j].resize (x, y, tile_width, tile_height);
 
-    _store_movement ();
+                if (_foreground_nxt[i,j] != null)
+                    _foreground_nxt[i,j].resize (x, y, tile_width, tile_height);
+            }
+        }
 
-    _move_trans = new Clutter.TransitionGroup ();
-    _move_trans.stopped.connect (_on_move_trans_stopped);
-    _move_trans.set_duration (_animations_duration);
+        if (_resize_view_id == 0)
+            _resize_view_id = Clutter.Threads.Timeout.add (1000, _idle_resize_view);
+    }
 
-    _grid.move_down (_to_move, _to_hide, _to_show);
+    private bool _idle_resize_view ()
+    {
+        int rows = _grid.rows;
+        int cols = _grid.cols;
+        for (int i = 0; i < rows; i++)
+        {
+            for (int j = 0; j < cols; j++)
+            {
+                _background[i,j].idle_resize ();
+
+                if (_foreground_cur[i,j] != null)
+                    _foreground_cur[i,j].idle_resize ();
+            }
+        }
+
+        _resize_view_id = 0;
+        return false;
+    }
 
-    foreach (var e in _to_move)
-      _move_tile (e.from, e.to);
+    private void _create_random_tile ()
+    {
+        Tile tile;
 
-    foreach (var e in _to_hide)
-      _prepare_move_tile (e.from, e.to);
+        if (_grid.new_tile (out tile))
+        {
+            _create_show_hide_transition (true);
 
-    has_moved = (_to_move.size > 0) || (_to_hide.size > 0) || (_to_show.size > 0);
+            _create_tile (tile);
+            _to_show.add (tile);
+            _show_tile (tile.pos);
+            _show_hide_trans.start ();
+        }
+    }
 
-    if (has_moved) {
-      _state = GameState.MOVING_DOWN;
-      _move_trans.start ();
+    private void _create_tile (Tile tile)
+    {
+        GridPosition pos;
+        RoundedRectangle rect;
+        TileView view;
+        float x;
+        float y;
+        float width;
+        float height;
+
+        pos = tile.pos;
+        rect = _background[pos.row,pos.col];
+        x = rect.actor.x;
+        y = rect.actor.y;
+        width = rect.actor.width;
+        height = rect.actor.height;
+
+        assert (_foreground_nxt[pos.row,pos.col] == null);
+        view = new TileView (x, y, width, height, tile.val);
+        _foreground_nxt[pos.row,pos.col] = view;
     }
-  }
 
-  private void _move_up ()
-  {
-    debug ("move up");
+    private void _move_down ()
+    {
+        debug ("move down");
 
-    bool has_moved;
+        bool has_moved;
 
-    _store_movement ();
+        _store_movement ();
 
-    _move_trans = new Clutter.TransitionGroup ();
-    _move_trans.stopped.connect (_on_move_trans_stopped);
-    _move_trans.set_duration (_animations_duration);
+        _move_trans = new Clutter.TransitionGroup ();
+        _move_trans.stopped.connect (_on_move_trans_stopped);
+        _move_trans.set_duration (_animations_duration);
 
-    _grid.move_up (_to_move, _to_hide, _to_show);
+        _grid.move_down (_to_move, _to_hide, _to_show);
 
-    foreach (var e in _to_move)
-      _move_tile (e.from, e.to);
+        foreach (var e in _to_move)
+            _move_tile (e.from, e.to);
 
-    foreach (var e in _to_hide)
-      _prepare_move_tile (e.from, e.to);
+        foreach (var e in _to_hide)
+            _prepare_move_tile (e.from, e.to);
 
-    has_moved = (_to_move.size > 0) || (_to_hide.size > 0) || (_to_show.size > 0);
+        has_moved = (_to_move.size > 0) || (_to_hide.size > 0) || (_to_show.size > 0);
 
-    if (has_moved) {
-      _state = GameState.MOVING_UP;
-      _move_trans.start ();
+        if (has_moved)
+        {
+            _state = GameState.MOVING_DOWN;
+            _move_trans.start ();
+        }
     }
-  }
 
-  private void _move_left ()
-  {
-    debug ("move left");
+    private void _move_up ()
+    {
+        debug ("move up");
 
-    bool has_moved;
+        bool has_moved;
 
-    _store_movement ();
+        _store_movement ();
 
-    _move_trans = new Clutter.TransitionGroup ();
-    _move_trans.stopped.connect (_on_move_trans_stopped);
-    _move_trans.set_duration (_animations_duration);
+        _move_trans = new Clutter.TransitionGroup ();
+        _move_trans.stopped.connect (_on_move_trans_stopped);
+        _move_trans.set_duration (_animations_duration);
 
-    _grid.move_left (_to_move, _to_hide, _to_show);
+        _grid.move_up (_to_move, _to_hide, _to_show);
 
-    foreach (var e in _to_move)
-      _move_tile (e.from, e.to);
+        foreach (var e in _to_move)
+            _move_tile (e.from, e.to);
 
-    foreach (var e in _to_hide)
-      _prepare_move_tile (e.from, e.to);
+        foreach (var e in _to_hide)
+            _prepare_move_tile (e.from, e.to);
 
-    has_moved = (_to_move.size > 0) || (_to_hide.size > 0) || (_to_show.size > 0);
+        has_moved = (_to_move.size > 0) || (_to_hide.size > 0) || (_to_show.size > 0);
 
-    if (has_moved) {
-      _state = GameState.MOVING_LEFT;
-      _move_trans.start ();
+        if (has_moved)
+        {
+            _state = GameState.MOVING_UP;
+            _move_trans.start ();
+        }
     }
-  }
 
-  private void _move_right ()
-  {
-    debug ("move right");
+    private void _move_left ()
+    {
+        debug ("move left");
 
-    bool has_moved;
+        bool has_moved;
 
-    _store_movement ();
+        _store_movement ();
 
-    _move_trans = new Clutter.TransitionGroup ();
-    _move_trans.stopped.connect (_on_move_trans_stopped);
-    _move_trans.set_duration (_animations_duration);
+        _move_trans = new Clutter.TransitionGroup ();
+        _move_trans.stopped.connect (_on_move_trans_stopped);
+        _move_trans.set_duration (_animations_duration);
 
-    _grid.move_right (_to_move, _to_hide, _to_show);
+        _grid.move_left (_to_move, _to_hide, _to_show);
 
-    foreach (var e in _to_move)
-      _move_tile (e.from, e.to);
+        foreach (var e in _to_move)
+            _move_tile (e.from, e.to);
 
-    foreach (var e in _to_hide)
-      _prepare_move_tile (e.from, e.to);
+        foreach (var e in _to_hide)
+            _prepare_move_tile (e.from, e.to);
 
-    has_moved = (_to_move.size > 0) || (_to_hide.size > 0) || (_to_show.size > 0);
+        has_moved = (_to_move.size > 0) || (_to_hide.size > 0) || (_to_show.size > 0);
 
-    if (has_moved) {
-      _state = GameState.MOVING_LEFT;
-      _move_trans.start ();
+        if (has_moved)
+        {
+            _state = GameState.MOVING_LEFT;
+            _move_trans.start ();
+        }
     }
-  }
 
-  private void _show_tile (GridPosition pos)
-  {
-    debug (@"show tile pos $pos");
+    private void _move_right ()
+    {
+        debug ("move right");
 
-    Clutter.PropertyTransition trans;
-    TileView view;
+        bool has_moved;
 
-    view = _foreground_nxt[pos.row,pos.col];
-    view.canvas.invalidate ();
-    view.actor.set_opacity (0);
-    view.actor.show ();
-    _view_foreground.add_child (view.actor);
+        _store_movement ();
 
-    trans = new Clutter.PropertyTransition ("scale-x");
-    trans.set_from_value (1.0);
-    trans.set_to_value (1.1);
-    trans.set_duration (_animations_duration);
-    trans.set_animatable (view.actor);
-    _show_hide_trans.add_transition (trans);
+        _move_trans = new Clutter.TransitionGroup ();
+        _move_trans.stopped.connect (_on_move_trans_stopped);
+        _move_trans.set_duration (_animations_duration);
 
-    trans = new Clutter.PropertyTransition ("scale-y");
-    trans.set_from_value (1.0);
-    trans.set_to_value (1.1);
-    trans.set_duration (_animations_duration);
-    trans.set_animatable (view.actor);
-    _show_hide_trans.add_transition (trans);
+        _grid.move_right (_to_move, _to_hide, _to_show);
 
-    trans = new Clutter.PropertyTransition ("opacity");
-    trans.set_from_value (0);
-    trans.set_to_value (255);
-    trans.set_remove_on_complete (true);
-    trans.set_duration (_animations_duration / 2);
-    view.actor.add_transition ("show", trans);
-  }
+        foreach (var e in _to_move)
+            _move_tile (e.from, e.to);
 
-  private void _move_tile (GridPosition from, GridPosition to)
-  {
-    debug (@"move tile from $from to $to");
-
-    _prepare_move_tile (from, to);
+        foreach (var e in _to_hide)
+            _prepare_move_tile (e.from, e.to);
 
-    _foreground_nxt[to.row,to.col] = _foreground_cur[from.row,from.col];
-    _foreground_cur[from.row,from.col] = null;
-  }
-
-  private void _prepare_move_tile (GridPosition from, GridPosition to)
-  {
-    debug (@"prepare move tile from $from to $to");
-
-    bool row_move;
-    string trans_name;
-    Clutter.PropertyTransition trans;
-    RoundedRectangle rect_from;
-    RoundedRectangle rect_to;
-
-    row_move = (from.col == to.col);
-    trans_name = row_move ? "y" : "x";
-
-    rect_from = _background[from.row,from.col];
-    rect_to = _background[to.row,to.col];
-
-    trans = new Clutter.PropertyTransition (trans_name);
-    trans.set_from_value (row_move ? rect_from.actor.y : rect_from.actor.x);
-    trans.set_to_value (row_move ? rect_to.actor.y : rect_to.actor.x);
-    trans.set_duration (_animations_duration);
-    trans.set_animatable (_foreground_cur[from.row,from.col].actor);
-    _move_trans.add_transition (trans);
-  }
-
-  private void _dim_tile (GridPosition pos)
-  {
-    debug (@"diming tile at $pos " + _foreground_cur[pos.row,pos.col].value.to_string ());
-
-    Clutter.Actor actor;
-    Clutter.PropertyTransition trans;
-
-    actor = _foreground_cur[pos.row,pos.col].actor;
-
-    trans = new Clutter.PropertyTransition ("opacity");
-    trans.set_from_value (actor.opacity);
-    trans.set_to_value (0);
-    trans.set_duration (_animations_duration);
-    trans.set_animatable (actor);
-
-    _show_hide_trans.add_transition (trans);
-  }
-
-  private void _clear_background ()
-  {
-    _view_background.remove_all_children ();
-  }
-
-  private void _clear_foreground ()
-  {
-    int rows = _grid.rows;
-    int cols = _grid.cols;
-    _view_foreground.remove_all_children ();
-    for (int i = 0; i < rows; i++) {
-      for (int j = 0; j < cols; j++) {
-        if (_foreground_cur[i,j] != null)
-          _foreground_cur[i,j] = null;
-        if (_foreground_nxt[i,j] != null)
-          _foreground_nxt[i,j] = null;
-      }
-    }
-  }
-
-  private void _restore_foreground (bool animate)
-  {
-    uint val;
-    GridPosition pos;
-    Tile tile;
-    int rows = _grid.rows;
-    int cols = _grid.cols;
-
-    _create_show_hide_transition (animate);
-
-    for (int i = 0; i < rows; i++) {
-      for (int j = 0; j < cols; j++) {
-        val = _grid[i,j];
-        if (val != 0) {
-          pos = { i, j };
-          tile = { pos, val };
-          _create_tile (tile);
-          _to_show.add (tile);
-          _show_tile (pos);
+        has_moved = (_to_move.size > 0) || (_to_hide.size > 0) || (_to_show.size > 0);
+
+        if (has_moved)
+        {
+            _state = GameState.MOVING_LEFT;
+            _move_trans.start ();
         }
-      }
     }
 
-    if (_to_show.size > 0) {
-      _state = GameState.RESTORING_TILES;
-      _show_hide_trans.start ();
+    private void _show_tile (GridPosition pos)
+    {
+        debug (@"show tile pos $pos");
+
+        Clutter.PropertyTransition trans;
+        TileView view;
+
+        view = _foreground_nxt[pos.row,pos.col];
+        view.canvas.invalidate ();
+        view.actor.set_opacity (0);
+        view.actor.show ();
+        _view_foreground.add_child (view.actor);
+
+        trans = new Clutter.PropertyTransition ("scale-x");
+        trans.set_from_value (1.0);
+        trans.set_to_value (1.1);
+        trans.set_duration (_animations_duration);
+        trans.set_animatable (view.actor);
+        _show_hide_trans.add_transition (trans);
+
+        trans = new Clutter.PropertyTransition ("scale-y");
+        trans.set_from_value (1.0);
+        trans.set_to_value (1.1);
+        trans.set_duration (_animations_duration);
+        trans.set_animatable (view.actor);
+        _show_hide_trans.add_transition (trans);
+
+        trans = new Clutter.PropertyTransition ("opacity");
+        trans.set_from_value (0);
+        trans.set_to_value (255);
+        trans.set_remove_on_complete (true);
+        trans.set_duration (_animations_duration / 2);
+        view.actor.add_transition ("show", trans);
     }
-  }
 
-  private void _on_move_trans_stopped (bool is_finished)
-  {
-    debug (@"move animation stopped; finished $is_finished");
-    debug (@"$_grid");
+    private void _move_tile (GridPosition from, GridPosition to)
+    {
+        debug (@"move tile from $from to $to");
 
-    uint delta_score;
+        _prepare_move_tile (from, to);
 
-    _move_trans.remove_all ();
+        _foreground_nxt[to.row,to.col] = _foreground_cur[from.row,from.col];
+        _foreground_cur[from.row,from.col] = null;
+    }
 
-    _create_show_hide_transition (true);
+    private void _prepare_move_tile (GridPosition from, GridPosition to)
+    {
+        debug (@"prepare move tile from $from to $to");
 
-    foreach (var e in _to_hide) {
-      _dim_tile (e.from);
-    }
+        bool row_move;
+        string trans_name;
+        Clutter.PropertyTransition trans;
+        RoundedRectangle rect_from;
+        RoundedRectangle rect_to;
+
+        row_move = (from.col == to.col);
+        trans_name = row_move ? "y" : "x";
+
+        rect_from = _background[from.row,from.col];
+        rect_to = _background[to.row,to.col];
 
-    delta_score = 0;
-    foreach (var e in _to_show) {
-      _create_tile (e);
-      _show_tile (e.pos);
-      delta_score += e.val;
+        trans = new Clutter.PropertyTransition (trans_name);
+        trans.set_from_value (row_move ? rect_from.actor.y : rect_from.actor.x);
+        trans.set_to_value (row_move ? rect_to.actor.y : rect_to.actor.x);
+        trans.set_duration (_animations_duration);
+        trans.set_animatable (_foreground_cur[from.row,from.col].actor);
+        _move_trans.add_transition (trans);
     }
-    score += delta_score;
-    _store_score_update (delta_score);
 
-    _create_random_tile ();
+    private void _dim_tile (GridPosition pos)
+    {
+        debug (@"diming tile at $pos " + _foreground_cur[pos.row,pos.col].value.to_string ());
 
-    _show_hide_trans.start ();
-  }
+        Clutter.Actor actor;
+        Clutter.PropertyTransition trans;
 
-  private void _on_show_hide_trans_stopped (bool is_finished)
-  {
-    debug (@"show/hide animation stopped; finished $is_finished");
+        actor = _foreground_cur[pos.row,pos.col].actor;
 
-    if (_show_hide_trans.direction == Clutter.TimelineDirection.FORWARD) {
-      _show_hide_trans.direction = Clutter.TimelineDirection.BACKWARD;
-      _show_hide_trans.start ();
-      return;
+        trans = new Clutter.PropertyTransition ("opacity");
+        trans.set_from_value (actor.opacity);
+        trans.set_to_value (0);
+        trans.set_duration (_animations_duration);
+        trans.set_animatable (actor);
+
+        _show_hide_trans.add_transition (trans);
     }
 
-    debug (@"$_grid");
+    private void _clear_background ()
+    {
+        _view_background.remove_all_children ();
+    }
 
-    _show_hide_trans.remove_all ();
+    private void _clear_foreground ()
+    {
+        int rows = _grid.rows;
+        int cols = _grid.cols;
+        _view_foreground.remove_all_children ();
+        for (int i = 0; i < rows; i++)
+        {
+            for (int j = 0; j < cols; j++)
+            {
+                if (_foreground_cur[i,j] != null)
+                    _foreground_cur[i,j] = null;
+                if (_foreground_nxt[i,j] != null)
+                    _foreground_nxt[i,j] = null;
+            }
+        }
+    }
 
-    foreach (var e in _to_hide) {
-      TileView view = _foreground_cur[e.from.row,e.from.col];
-      view.actor.hide ();
-      debug (@"remove child " + _foreground_cur[e.from.row,e.from.col].value.to_string ());
-      _view_foreground.remove_child (view.actor);
+    private void _restore_foreground (bool animate)
+    {
+        uint val;
+        GridPosition pos;
+        Tile tile;
+        int rows = _grid.rows;
+        int cols = _grid.cols;
+
+        _create_show_hide_transition (animate);
+
+        for (int i = 0; i < rows; i++)
+        {
+            for (int j = 0; j < cols; j++)
+            {
+                val = _grid[i,j];
+                if (val != 0)
+                {
+                    pos = { i, j };
+                    tile = { pos, val };
+                    _create_tile (tile);
+                    _to_show.add (tile);
+                    _show_tile (pos);
+                }
+            }
+        }
 
-      _foreground_cur[e.from.row,e.from.col] = null;
+        if (_to_show.size > 0)
+        {
+            _state = GameState.RESTORING_TILES;
+            _show_hide_trans.start ();
+        }
     }
 
-    _finish_move_id = GLib.Timeout.add (100, _finish_move);
-  }
+    private void _on_move_trans_stopped (bool is_finished)
+    {
+        debug (@"move animation stopped; finished $is_finished");
+        debug (@"$_grid");
+
+        uint delta_score;
+
+        _move_trans.remove_all ();
+
+        _create_show_hide_transition (true);
+
+        foreach (var e in _to_hide)
+        {
+            _dim_tile (e.from);
+        }
+
+        delta_score = 0;
+        foreach (var e in _to_show)
+        {
+            _create_tile (e);
+            _show_tile (e.pos);
+            delta_score += e.val;
+        }
+        score += delta_score;
+        _store_score_update (delta_score);
 
-  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 (animate ? _animations_duration : 10);
-  }
+        _create_random_tile ();
 
-  private bool _finish_move ()
-  {
-    if (_state == GameState.SHOWING_FIRST_TILE) {
-      _state = GameState.SHOWING_SECOND_TILE;
-      debug ("state show second tile");
-      _create_random_tile ();
-    } else if (_state == GameState.SHOWING_SECOND_TILE) {
-      _state = GameState.IDLE;
-      debug ("state idle");
-    } else if (_state != GameState.IDLE) {
-      _state = GameState.IDLE;
-      debug ("state idle");
+        _show_hide_trans.start ();
     }
 
-    foreach (var e in _to_move) {
-      _foreground_cur[e.to.row,e.to.col] = _foreground_nxt[e.to.row,e.to.col];
-      _foreground_nxt[e.to.row,e.to.col] = null;
+    private void _on_show_hide_trans_stopped (bool is_finished)
+    {
+        debug (@"show/hide animation stopped; finished $is_finished");
+
+        if (_show_hide_trans.direction == Clutter.TimelineDirection.FORWARD)
+        {
+            _show_hide_trans.direction = Clutter.TimelineDirection.BACKWARD;
+            _show_hide_trans.start ();
+            return;
+        }
+
+        debug (@"$_grid");
+
+        _show_hide_trans.remove_all ();
+
+        foreach (var e in _to_hide)
+        {
+            TileView view = _foreground_cur[e.from.row,e.from.col];
+            view.actor.hide ();
+            debug (@"remove child " + _foreground_cur[e.from.row,e.from.col].value.to_string ());
+            _view_foreground.remove_child (view.actor);
+
+            _foreground_cur[e.from.row,e.from.col] = null;
+        }
+
+        _finish_move_id = GLib.Timeout.add (100, _finish_move);
     }
-    foreach (var e in _to_show) {
-      _foreground_cur[e.pos.row,e.pos.col] = _foreground_nxt[e.pos.row,e.pos.col];
-      _foreground_nxt[e.pos.row,e.pos.col] = null;
+
+    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 (animate ? _animations_duration : 10);
     }
 
-    _to_hide.clear ();
-    _to_move.clear ();
-    _to_show.clear ();
+    private bool _finish_move ()
+    {
+        if (_state == GameState.SHOWING_FIRST_TILE)
+        {
+            _state = GameState.SHOWING_SECOND_TILE;
+            debug ("state show second tile");
+            _create_random_tile ();
+        }
+        else if (_state == GameState.SHOWING_SECOND_TILE)
+        {
+            _state = GameState.IDLE;
+            debug ("state idle");
+        }
+        else if (_state != GameState.IDLE)
+        {
+            _state = GameState.IDLE;
+            debug ("state idle");
+        }
 
-    if (_grid.target_value_reached) {
-      target_value_reached (_grid.target_value);
-      _grid.target_value_reached = false;
-    }
+        foreach (var e in _to_move)
+        {
+            _foreground_cur[e.to.row,e.to.col] = _foreground_nxt[e.to.row,e.to.col];
+            _foreground_nxt[e.to.row,e.to.col] = null;
+        }
+        foreach (var e in _to_show)
+        {
+            _foreground_cur[e.pos.row,e.pos.col] = _foreground_nxt[e.pos.row,e.pos.col];
+            _foreground_nxt[e.pos.row,e.pos.col] = null;
+        }
 
-    if (_grid.is_finished ())
-      finished ();
+        _to_hide.clear ();
+        _to_move.clear ();
+        _to_show.clear ();
+
+        if (_grid.target_value_reached)
+        {
+            target_value_reached (_grid.target_value);
+            _grid.target_value_reached = false;
+        }
 
-    _finish_move_id = 0;
-    return false;
-  }
+        if (_grid.is_finished ())
+            finished ();
 
-  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 ();
-      }
+        _finish_move_id = 0;
+        return false;
     }
-  }
 
-  private void _store_score_update (uint delta_score)
-  {
-    if (_allow_undo) {
-      if (_undo_score_stack.size == _undo_stack_max_size)
-        _undo_score_stack.poll_tail ();
-      _undo_score_stack.offer_head (delta_score);
+    private void _store_movement ()
+    {
+        if (!_allow_undo)
+            return;
+
+        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 ();
+    }
+
+    private void _store_score_update (uint delta_score)
+    {
+        if (!_allow_undo)
+            return;
+
+        if (_undo_score_stack.size == _undo_stack_max_size)
+            _undo_score_stack.poll_tail ();
+        _undo_score_stack.offer_head (delta_score);
     }
-  }
 }
diff --git a/src/grid.vala b/src/grid.vala
index ef2a16d..0787ede 100644
--- a/src/grid.vala
+++ b/src/grid.vala
@@ -1,4 +1,5 @@
-/* Copyright (C) 2014-2015 Juan R. García Blanco
+/* Copyright (C) 2014-2015 Juan R. García Blanco <juanrgar gmail com>
+ * Copyright (C) 2016 Arnaud Bonatti <arnaud bonatti gmail com>
  *
  * This file is part of GNOME 2048.
  *
@@ -16,571 +17,593 @@
  * along with GNOME 2048; if not, see <http://www.gnu.org/licenses/>.
  */
 
-public class Grid : GLib.Object
+public class Grid : Object
 {
-  private uint[,] _grid;
-
-  public Grid (int rows, int cols)
-  {
-    Object (rows: rows, cols: cols);
-
-    _grid = new uint[rows, cols];
-    clear ();
-    _target_value = 0;
-  }
-
-  public int rows {
-    get; set;
-  }
-
-  public int cols {
-    get; set;
-  }
-
-  public uint target_value {
-    get; set;
-  }
-
-  public bool target_value_reached {
-    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++) {
-      for (uint j = 0; j < _grid.length[1]; j++) {
-        _grid[i,j] = 0;
-      }
-    }
-  }
+    private uint[,] _grid;
 
-  public bool new_tile (out Tile tile)
-  {
-    GridPosition pos = { 0, 0 };
-    uint val;
-    tile = { pos, 0 };
+    public Grid (int rows, int cols)
+    {
+        Object (rows: rows, cols: cols);
 
-    if (_grid_is_full ()) {
-      return false;
+        _grid = new uint[rows, cols];
+        clear ();
+        _target_value = 0;
     }
 
-    val = 2;
-
-    while (true) {
-      pos = _random_position ();
-
-      if (_grid[pos.row,pos.col] == 0) {
-        _grid[pos.row,pos.col] = val;
-        _check_target_value_reached (val);
-        tile = { pos, val };
-        return true;
-      }
+    public int rows {
+        get; set;
     }
-  }
 
-  public void move_down (Gee.LinkedList<TileMovement?> to_move,
-                         Gee.LinkedList<TileMovement?> to_hide,
-                         Gee.LinkedList<Tile?> to_show)
-  {
-    GridPosition free;
-    GridPosition cur;
-    GridPosition match;
-    bool has_match;
-    int row;
-    uint val;
-    TileMovement mov;
-    Tile tile;
-
-    to_move.clear ();
-    to_hide.clear ();
-    to_show.clear ();
-
-    for (int i = 0; i < _cols; i++) {
-      free = { _rows, i };
-
-      for (int j = 0; j < _rows; j++) {
-        row = _rows - j - 1;
-        cur = { row, i };
-        val = _grid[cur.row,cur.col];
-
-        if (val == 0) {
-          if (free.row == _rows) {
-            free.row = row;
-          }
-          continue;
-        }
+    public int cols {
+        get; set;
+    }
 
-        // search for matches
-        match = { 0, 0 };
-        has_match = false;
-        for (int k = row - 1; k >= 0; k--) {
-          uint k_val = _grid[k,cur.col];
+    public uint target_value {
+        get; set;
+    }
 
-          if (k_val != 0) {
-            if (k_val == val) {
-              has_match = true;
-              match = { k, cur.col };
-            }
-            break;
-          }
-        }
+    public bool target_value_reached {
+        get; set;
+    }
 
-        if (has_match) {
-          debug (@"matching tile found at $match");
+    public Grid clone ()
+    {
+        Grid grid = new Grid (_rows, _cols);
+        grid._grid = _grid;
+        grid._target_value = _target_value;
+        grid._target_value_reached = _target_value_reached;
 
-          if (free.row == _rows) {
-            free.row = row; // temporarily
-          }
-          mov = { cur, free };
-          to_hide.add (mov);
-          mov = { match, free };
-          to_hide.add (mov);
+        return grid;
+    }
 
-          tile = { free, val*2 };
-          to_show.add (tile);
+    public void clear ()
+    {
+        for (uint i = 0; i < _grid.length[0]; i++)
+            for (uint j = 0; j < _grid.length[1]; j++)
+                _grid[i,j] = 0;
+    }
 
-          _grid[cur.row,cur.col] = 0;
-          _grid[match.row,match.col] = 0;
-          _grid[free.row,free.col] = val*2;
-          _check_target_value_reached (val*2);
+    public bool new_tile (out Tile tile)
+    {
+        GridPosition pos = { 0, 0 };
+        uint val;
+        tile = { pos, 0 };
 
-          free.row--;
-        } else if (free.row != _rows) {
-          debug (@"moving $cur to $free");
+        if (_grid_is_full ())
+            return false;
 
-          mov = { cur, free };
-          to_move.add (mov);
+        val = 2;
 
-          _grid[cur.row,cur.col] = 0;
-          _grid[free.row,free.col] = val;
+        while (true)
+        {
+            pos = _random_position ();
 
-          free.row--;
+            if (_grid[pos.row,pos.col] == 0)
+            {
+                _grid[pos.row,pos.col] = val;
+                _check_target_value_reached (val);
+                tile = { pos, val };
+                return true;
+            }
         }
-      }
     }
-  }
-
-  public void move_up (Gee.LinkedList<TileMovement?> to_move,
-                       Gee.LinkedList<TileMovement?> to_hide,
-                       Gee.LinkedList<Tile?> to_show)
-  {
-    GridPosition free;
-    GridPosition cur;
-    GridPosition match;
-    bool has_match;
-    int row;
-    uint val;
-    TileMovement mov;
-    Tile tile;
-
-    to_move.clear ();
-    to_hide.clear ();
-    to_show.clear ();
-
-    for (int i = 0; i < _cols; i++) {
-      free = { -1, i };
-
-      for (int j = 0; j < _rows; j++) {
-        row = j;
-        cur = { row, i };
-        val = _grid[cur.row,cur.col];
-
-        if (val == 0) {
-          if (free.row == -1) {
-            free.row = row;
-          }
-          continue;
-        }
 
-        // search for matches
-        match = { 0, 0 };
-        has_match = false;
-        for (int k = row + 1; k < _rows; k++) {
-          uint k_val = _grid[k,cur.col];
-
-          if (k_val != 0) {
-            if (k_val == val) {
-              has_match = true;
-              match = { k, cur.col };
+    public void move_down (Gee.LinkedList<TileMovement?> to_move,
+                           Gee.LinkedList<TileMovement?> to_hide,
+                           Gee.LinkedList<Tile?> to_show)
+    {
+        GridPosition free;
+        GridPosition cur;
+        GridPosition match;
+        bool has_match;
+        int row;
+        uint val;
+        TileMovement mov;
+        Tile tile;
+
+        to_move.clear ();
+        to_hide.clear ();
+        to_show.clear ();
+
+        for (int i = 0; i < _cols; i++)
+        {
+            free = { _rows, i };
+
+            for (int j = 0; j < _rows; j++)
+            {
+                row = _rows - j - 1;
+                cur = { row, i };
+                val = _grid[cur.row,cur.col];
+
+                if (val == 0)
+                {
+                    if (free.row == _rows)
+                        free.row = row;
+                    continue;
+                }
+
+                // search for matches
+                match = { 0, 0 };
+                has_match = false;
+                for (int k = row - 1; k >= 0; k--)
+                {
+                    uint k_val = _grid[k,cur.col];
+
+                    if (k_val != 0)
+                    {
+                        if (k_val == val)
+                        {
+                            has_match = true;
+                            match = { k, cur.col };
+                        }
+                        break;
+                    }
+                }
+
+                if (has_match)
+                {
+                    debug (@"matching tile found at $match");
+
+                    if (free.row == _rows)
+                        free.row = row; // temporarily
+
+                    mov = { cur, free };
+                    to_hide.add (mov);
+                    mov = { match, free };
+                    to_hide.add (mov);
+
+                    tile = { free, val*2 };
+                    to_show.add (tile);
+
+                    _grid[cur.row,cur.col] = 0;
+                    _grid[match.row,match.col] = 0;
+                    _grid[free.row,free.col] = val*2;
+                    _check_target_value_reached (val*2);
+
+                    free.row--;
+                }
+                else if (free.row != _rows)
+                {
+                    debug (@"moving $cur to $free");
+
+                    mov = { cur, free };
+                    to_move.add (mov);
+
+                    _grid[cur.row,cur.col] = 0;
+                    _grid[free.row,free.col] = val;
+
+                    free.row--;
+                }
             }
-            break;
-          }
-        }
-
-        if (has_match) {
-          debug (@"matching tile found at $match");
-
-          if (free.row == -1) {
-            free.row = row; // temporarily
-          }
-          mov = { cur, free };
-          to_hide.add (mov);
-          mov = { match, free };
-          to_hide.add (mov);
-
-          tile = { free, val*2 };
-          to_show.add (tile);
-
-          _grid[cur.row,cur.col] = 0;
-          _grid[match.row,match.col] = 0;
-          _grid[free.row,free.col] = val*2;
-          _check_target_value_reached (val*2);
-
-          free.row++;
-        } else if (free.row != -1) {
-          debug (@"moving $cur to $free");
-
-          mov = { cur, free };
-          to_move.add (mov);
-
-          _grid[cur.row,cur.col] = 0;
-          _grid[free.row,free.col] = val;
-
-          free.row++;
         }
-      }
     }
-  }
 
-  public void move_left (Gee.LinkedList<TileMovement?> to_move,
+    public void move_up (Gee.LinkedList<TileMovement?> to_move,
                          Gee.LinkedList<TileMovement?> to_hide,
                          Gee.LinkedList<Tile?> to_show)
-  {
-    GridPosition free;
-    GridPosition cur;
-    GridPosition match;
-    bool has_match;
-    int col;
-    uint val;
-    TileMovement mov;
-    Tile tile;
-
-    to_move.clear ();
-    to_hide.clear ();
-    to_show.clear ();
-
-    for (int i = 0; i < _rows; i++) {
-      free = { i, -1 };
-
-      for (int j = 0; j < _cols; j++) {
-        col = j;
-        cur = { i, col };
-        val = _grid[cur.row,cur.col];
-
-        if (val == 0) {
-          if (free.col == -1) {
-            free.col = col;
-          }
-          continue;
-        }
-
-        // search for matches
-        match = { 0, 0 };
-        has_match = false;
-        for (int k = col + 1; k < _rows; k++) {
-          uint k_val = _grid[cur.row,k];
-
-          if (k_val != 0) {
-            if (k_val == val) {
-              has_match = true;
-              match = { cur.row, k };
+    {
+        GridPosition free;
+        GridPosition cur;
+        GridPosition match;
+        bool has_match;
+        int row;
+        uint val;
+        TileMovement mov;
+        Tile tile;
+
+        to_move.clear ();
+        to_hide.clear ();
+        to_show.clear ();
+
+        for (int i = 0; i < _cols; i++)
+        {
+            free = { -1, i };
+
+            for (int j = 0; j < _rows; j++)
+            {
+                row = j;
+                cur = { row, i };
+                val = _grid[cur.row,cur.col];
+
+                if (val == 0)
+                {
+                    if (free.row == -1)
+                        free.row = row;
+                    continue;
+                }
+
+                // search for matches
+                match = { 0, 0 };
+                has_match = false;
+                for (int k = row + 1; k < _rows; k++)
+                {
+                    uint k_val = _grid[k,cur.col];
+
+                    if (k_val != 0)
+                    {
+                        if (k_val == val)
+                        {
+                            has_match = true;
+                            match = { k, cur.col };
+                        }
+                        break;
+                    }
+                }
+
+                if (has_match)
+                {
+                    debug (@"matching tile found at $match");
+
+                    if (free.row == -1)
+                        free.row = row; // temporarily
+
+                    mov = { cur, free };
+                    to_hide.add (mov);
+                    mov = { match, free };
+                    to_hide.add (mov);
+
+                    tile = { free, val*2 };
+                    to_show.add (tile);
+
+                    _grid[cur.row,cur.col] = 0;
+                    _grid[match.row,match.col] = 0;
+                    _grid[free.row,free.col] = val*2;
+                    _check_target_value_reached (val*2);
+
+                    free.row++;
+                }
+                else if (free.row != -1)
+                {
+                    debug (@"moving $cur to $free");
+
+                    mov = { cur, free };
+                    to_move.add (mov);
+
+                    _grid[cur.row,cur.col] = 0;
+                    _grid[free.row,free.col] = val;
+
+                    free.row++;
+                }
             }
-            break;
-          }
         }
+    }
 
-        if (has_match) {
-          debug (@"matching tile found at $match");
-
-          if (free.col == -1) {
-            free.col = col; // temporarily
-          }
-          mov = { cur, free };
-          to_hide.add (mov);
-          mov = { match, free };
-          to_hide.add (mov);
-
-          tile = { free, val*2 };
-          to_show.add (tile);
-
-          _grid[cur.row,cur.col] = 0;
-          _grid[match.row,match.col] = 0;
-          _grid[free.row,free.col] = val*2;
-          _check_target_value_reached (val*2);
-
-          free.col++;
-        } else if (free.col != -1) {
-          debug (@"moving $cur to $free");
-
-          mov = { cur, free };
-          to_move.add (mov);
-
-          _grid[cur.row,cur.col] = 0;
-          _grid[free.row,free.col] = val;
-
-          free.col++;
+    public void move_left (Gee.LinkedList<TileMovement?> to_move,
+                           Gee.LinkedList<TileMovement?> to_hide,
+                           Gee.LinkedList<Tile?> to_show)
+    {
+        GridPosition free;
+        GridPosition cur;
+        GridPosition match;
+        bool has_match;
+        int col;
+        uint val;
+        TileMovement mov;
+        Tile tile;
+
+        to_move.clear ();
+        to_hide.clear ();
+        to_show.clear ();
+
+        for (int i = 0; i < _rows; i++)
+        {
+            free = { i, -1 };
+
+            for (int j = 0; j < _cols; j++)
+            {
+                col = j;
+                cur = { i, col };
+                val = _grid[cur.row,cur.col];
+
+                if (val == 0)
+                {
+                    if (free.col == -1)
+                        free.col = col;
+                    continue;
+                }
+
+                // search for matches
+                match = { 0, 0 };
+                has_match = false;
+                for (int k = col + 1; k < _rows; k++)
+                {
+                    uint k_val = _grid[cur.row,k];
+
+                    if (k_val != 0)
+                    {
+                        if (k_val == val)
+                        {
+                            has_match = true;
+                            match = { cur.row, k };
+                        }
+                        break;
+                    }
+                }
+
+                if (has_match)
+                {
+                    debug (@"matching tile found at $match");
+
+                    if (free.col == -1)
+                        free.col = col; // temporarily
+
+                    mov = { cur, free };
+                    to_hide.add (mov);
+                    mov = { match, free };
+                    to_hide.add (mov);
+
+                    tile = { free, val*2 };
+                    to_show.add (tile);
+
+                    _grid[cur.row,cur.col] = 0;
+                    _grid[match.row,match.col] = 0;
+                    _grid[free.row,free.col] = val*2;
+                    _check_target_value_reached (val*2);
+
+                    free.col++;
+                }
+                else if (free.col != -1)
+                {
+                    debug (@"moving $cur to $free");
+
+                    mov = { cur, free };
+                    to_move.add (mov);
+
+                    _grid[cur.row,cur.col] = 0;
+                    _grid[free.row,free.col] = val;
+
+                    free.col++;
+                }
+            }
         }
-      }
     }
-  }
-
-  public void move_right (Gee.LinkedList<TileMovement?> to_move,
-                          Gee.LinkedList<TileMovement?> to_hide,
-                          Gee.LinkedList<Tile?> to_show)
-  {
-    GridPosition free;
-    GridPosition cur;
-    GridPosition match;
-    bool has_match;
-    int col;
-    uint val;
-    TileMovement mov;
-    Tile tile;
-
-    to_move.clear ();
-    to_hide.clear ();
-    to_show.clear ();
-
-    for (int i = 0; i < _rows; i++) {
-      free = { i, _cols };
-
-      for (int j = 0; j < _cols; j++) {
-        col = _cols - j - 1;
-        cur = { i, col };
-        val = _grid[cur.row,cur.col];
-
-        if (val == 0) {
-          if (free.col == _cols) {
-            free.col = col;
-          }
-          continue;
-        }
-
-        // search for matches
-        match = { 0, 0 };
-        has_match = false;
-        for (int k = col - 1; k >= 0; k--) {
-          uint k_val = _grid[cur.row,k];
 
-          if (k_val != 0) {
-            if (k_val == val) {
-              has_match = true;
-              match = { cur.row, k };
+    public void move_right (Gee.LinkedList<TileMovement?> to_move,
+                            Gee.LinkedList<TileMovement?> to_hide,
+                            Gee.LinkedList<Tile?> to_show)
+    {
+        GridPosition free;
+        GridPosition cur;
+        GridPosition match;
+        bool has_match;
+        int col;
+        uint val;
+        TileMovement mov;
+        Tile tile;
+
+        to_move.clear ();
+        to_hide.clear ();
+        to_show.clear ();
+
+        for (int i = 0; i < _rows; i++)
+        {
+            free = { i, _cols };
+
+            for (int j = 0; j < _cols; j++)
+            {
+                col = _cols - j - 1;
+                cur = { i, col };
+                val = _grid[cur.row,cur.col];
+
+                if (val == 0)
+                {
+                    if (free.col == _cols)
+                        free.col = col;
+                    continue;
+                }
+
+                // search for matches
+                match = { 0, 0 };
+                has_match = false;
+                for (int k = col - 1; k >= 0; k--)
+                {
+                    uint k_val = _grid[cur.row,k];
+
+                    if (k_val != 0)
+                    {
+                        if (k_val == val)
+                        {
+                            has_match = true;
+                            match = { cur.row, k };
+                        }
+                        break;
+                    }
+                }
+
+                if (has_match)
+                {
+                    debug (@"matching tile found at $match");
+
+                    if (free.col == _cols)
+                        free.col = col; // temporarily
+
+                    mov = { cur, free };
+                    to_hide.add (mov);
+                    mov = { match, free };
+                    to_hide.add (mov);
+
+                    tile = { free, val*2 };
+                    to_show.add (tile);
+
+                    _grid[cur.row,cur.col] = 0;
+                    _grid[match.row,match.col] = 0;
+                    _grid[free.row,free.col] = val*2;
+                    _check_target_value_reached (val*2);
+
+                    free.col--;
+                }
+                else if (free.col != _cols)
+                {
+                    debug (@"moving $cur to $free");
+
+                    mov = { cur, free };
+                    to_move.add (mov);
+
+                    _grid[cur.row,cur.col] = 0;
+                    _grid[free.row,free.col] = val;
+
+                    free.col--;
+                }
             }
-            break;
-          }
         }
+    }
 
-        if (has_match) {
-          debug (@"matching tile found at $match");
-
-          if (free.col == _cols) {
-            free.col = col; // temporarily
-          }
-          mov = { cur, free };
-          to_hide.add (mov);
-          mov = { match, free };
-          to_hide.add (mov);
-
-          tile = { free, val*2 };
-          to_show.add (tile);
-
-          _grid[cur.row,cur.col] = 0;
-          _grid[match.row,match.col] = 0;
-          _grid[free.row,free.col] = val*2;
-          _check_target_value_reached (val*2);
-
-          free.col--;
-        } else if (free.col != _cols) {
-          debug (@"moving $cur to $free");
+    public bool is_finished ()
+    {
+        if (!_grid_is_full ())
+            return false;
 
-          mov = { cur, free };
-          to_move.add (mov);
+        for (int i = 0; i < _rows; i++)
+        {
+            for (int j = 0; j < _cols; j++)
+            {
+                uint val = _grid[i,j];
 
-          _grid[cur.row,cur.col] = 0;
-          _grid[free.row,free.col] = val;
+                if (i < (_rows - 1) && val == _grid[i+1,j])
+                    return false;
 
-          free.col--;
-        }
-      }
-    }
-  }
-
-  public bool is_finished ()
-  {
-    uint val;
-
-    if (!_grid_is_full ())
-      return false;
-    else {
-      for (int i = 0; i < _rows; i++) {
-        for (int j = 0; j < _cols; j++) {
-          val = _grid[i,j];
-
-          if (i < (_rows - 1))
-            if (val == _grid[i+1,j])
-              return false;
-
-          if (j < (_cols - 1))
-            if (val == _grid[i,j+1])
-              return false;
+                if (j < (_cols - 1) && val == _grid[i,j+1])
+                    return false;
+            }
         }
-      }
+
+        return true;
     }
 
-    return true;
-  }
+    public new uint get (int row, int col)
+    {
+        if ((row >= _rows) || (col >= _cols))
+            return 0;
 
-  public new uint get (int row, int col)
-  {
-    if ((row >= _rows) || (col >= _cols))
-      return 0;
+        return _grid[row,col];
+    }
 
-    return _grid[row,col];
-  }
+    public string save ()
+    {
+        string ret = "";
 
-  public string save ()
-  {
-    string ret = "";
+        ret += _rows.to_string () + " ";
+        ret += _cols.to_string () + "\n";
 
-    ret += _rows.to_string () + " ";
-    ret += _cols.to_string () + "\n";
+        ret += _convert_to_string ();
 
-    ret += _convert_to_string ();
+        return ret;
+    }
 
-    return ret;
-  }
+    public bool load (string content)
+    {
+        return _load_from_string (content);
+    }
 
-  public bool load (string content)
-  {
-    return _load_from_string (content);
-  }
+    public string to_string ()
+    {
+        string ret = "\n";
+        ret += _convert_to_string ();
+        return ret;
+    }
 
-  public string to_string ()
-  {
-    string ret = "\n";
-    ret += _convert_to_string ();
-    return ret;
-  }
+    private string _convert_to_string ()
+    {
+        string ret = "";
 
-  private string _convert_to_string ()
-  {
-    string ret = "";
+        for (uint i = 0; i < _rows; i++)
+            for (uint j = 0; j < _cols; j++)
+                ret += "%u%s".printf (_grid[i,j], (j == (_cols-1)) ? "\n" : " ");
 
-    for (uint i = 0; i < _rows; i++) {
-      for (uint j = 0; j < _cols; j++) {
-        ret += "%u%s".printf (_grid[i,j], (j == (_cols-1)) ? "\n" : " ");
-      }
+        return ret;
     }
 
-    return ret;
-  }
+    private bool _load_from_string (string contents)
+    {
+        int rows = 0;
+        int cols = 0;
+        string[] lines;
+        string[] tokens;
+        uint[,] grid;
 
-  private bool _load_from_string (string contents)
-  {
-    int rows = 0;
-    int cols = 0;
-    string[] lines;
-    string[] tokens;
-    uint[,] grid;
+        lines = contents.split ("\n");
 
-    lines = contents.split ("\n");
+        // check that at least it contains 2 rows
+        if (lines.length < 3)
+            return false;
 
-    // check that at least it contains 2 rows
-    if (lines.length < 3)
-      return false;
+        tokens = lines[0].split (" ");
+        if (tokens.length != 2)
+            return false;
 
-    tokens = lines[0].split (" ");
-    if (tokens.length != 2)
-      return false;
+        rows = int.parse (tokens[0]);
+        cols = int.parse (tokens[1]);
 
-    rows = int.parse (tokens[0]);
-    cols = int.parse (tokens[1]);
+        if ((rows < 2) || (cols < 2))
+            return false;
+        // we don't need to be strict here
+        if (lines.length < (rows+1))
+            return false;
 
-    if ((rows < 2) || (cols < 2))
-      return false;
-    // we don't need to be strict here
-    if (lines.length < (rows+1))
-      return false;
+        grid = new uint[rows, cols];
 
-    grid = new uint[rows, cols];
+        for (int i = 0; i < rows; i++)
+        {
+            tokens = lines[i+1].split (" ");
+            // we do need to be strict here
+            if (tokens.length != cols)
+                return false;
 
-    for (int i = 0; i < rows; i++) {
-      tokens = lines[i+1].split (" ");
-      // we do need to be strict here
-      if (tokens.length != cols)
-        return false;
+            for (int j = 0; j < cols; j++)
+                grid[i,j] = int.parse (tokens[j]);
+        }
 
-      for (int j = 0; j < cols; j++) {
-        grid[i,j] = int.parse (tokens[j]);
-      }
-    }
+        _rows = rows;
+        _cols = cols;
+        _grid = grid;
 
-    _rows = rows;
-    _cols = cols;
-    _grid = grid;
+        return true;
+    }
 
-    return true;
-  }
+    private bool _grid_is_full ()
+    {
+        for (uint i = 0; i < _rows; i++)
+            for (uint j = 0; j < _cols; j++)
+                if (_grid[i,j] == 0)
+                    return false;
 
-  private bool _grid_is_full ()
-  {
-    for (uint i = 0; i < _rows; i++) {
-      for (uint j = 0; j < _cols; j++) {
-        if (_grid[i,j] == 0) {
-          return false;
-        }
-      }
+        return true;
     }
 
-    return true;
-  }
+    private GridPosition _random_position ()
+    {
+        GridPosition ret = { Random.int_range (0, (int)_rows),
+                             Random.int_range (0, (int)_cols) };
 
-  private GridPosition _random_position ()
-  {
-    GridPosition ret = { Random.int_range (0, (int)_rows),
-                         Random.int_range (0, (int)_cols) };
-
-    return ret;
-  }
+        return ret;
+    }
 
-  private void _check_target_value_reached (uint val)
-  {
-    if (target_value != 0)
-      if (val == target_value)
-        target_value_reached = true;
-  }
+    private void _check_target_value_reached (uint val)
+    {
+        if (target_value != 0 && val == target_value)
+            target_value_reached = true;
+    }
 }
 
 public struct GridPosition
 {
-  public uint row;
-  public uint col;
+    public uint row;
+    public uint col;
 
-  public string to_string ()
-  {
-    return @"($row,$col)";
-  }
+    public string to_string ()
+    {
+        return @"($row,$col)";
+    }
 }
 
 public struct TileMovement
 {
-  public GridPosition from;
-  public GridPosition to;
+    public GridPosition from;
+    public GridPosition to;
 }
 
 public struct Tile
 {
-  public GridPosition pos;
-  public uint val;
+    public GridPosition pos;
+    public uint val;
 }
diff --git a/src/view.vala b/src/view.vala
index 5f4cf39..6ef8756 100644
--- a/src/view.vala
+++ b/src/view.vala
@@ -1,4 +1,5 @@
-/* Copyright (C) 2014-2015 Juan R. García Blanco
+/* Copyright (C) 2014-2015 Juan R. García Blanco <juanrgar gmail com>
+ * Copyright (C) 2016 Arnaud Bonatti <arnaud bonatti gmail com>
  *
  * This file is part of GNOME 2048.
  *
@@ -16,184 +17,177 @@
  * along with GNOME 2048; if not, see <http://www.gnu.org/licenses/>.
  */
 
-public class RoundedRectangle : GLib.Object
+public class RoundedRectangle : Object
 {
-  protected Clutter.Actor _actor;
-  protected Clutter.Canvas _canvas;
-  protected Clutter.Color? _color;
-
-  public RoundedRectangle (float x, float y, float width, float height, Clutter.Color? color)
-  {
-    Object ();
-
-    _color = color;
-
-    _canvas = new Clutter.Canvas ();
-    _canvas.set_size ((int)Math.ceilf (width), (int)Math.ceilf (height));
-
-    _actor = new Clutter.Actor ();
-    _actor.set_size (width, height);
-    _actor.set_content (_canvas);
-    _actor.x = x;
-    _actor.y = y;
-    _actor.set_pivot_point (0.5f, 0.5f);
-
-    _canvas.draw.connect (_draw);
-  }
-
-  public Clutter.Actor actor {
-    get { return _actor; }
-  }
-
-  public Clutter.Color color {
-    get { return _color; }
-    set {
-      _color = value;
-      _canvas.invalidate ();
+    protected Clutter.Actor _actor;
+    protected Clutter.Canvas _canvas;
+    protected Clutter.Color? _color;
+
+    public RoundedRectangle (float x, float y, float width, float height, Clutter.Color? color)
+    {
+        Object ();
+
+        _color = color;
+
+        _canvas = new Clutter.Canvas ();
+        _canvas.set_size ((int)Math.ceilf (width), (int)Math.ceilf (height));
+
+        _actor = new Clutter.Actor ();
+        _actor.set_size (width, height);
+        _actor.set_content (_canvas);
+        _actor.x = x;
+        _actor.y = y;
+        _actor.set_pivot_point (0.5f, 0.5f);
+
+        _canvas.draw.connect (_draw);
+    }
+
+    public Clutter.Actor actor {
+        get { return _actor; }
+    }
+
+    public Clutter.Color color {
+        get { return _color; }
+        set {
+            _color = value;
+            _canvas.invalidate ();
+        }
     }
-  }
-
-  public Clutter.Canvas canvas {
-    get { return _canvas; }
-  }
-
-  public void resize (float x, float y, float width, float height)
-  {
-    _actor.x = x;
-    _actor.y = y;
-    _actor.width = width;
-    _actor.height = height;
-  }
-
-  public void idle_resize ()
-  {
-    if (!_canvas.set_size ((int)Math.ceilf (_actor.width), (int)Math.ceilf (_actor.height)))
-      _canvas.invalidate ();
-  }
-
-  protected virtual bool _draw (Cairo.Context ctx, int width, int height)
-  {
-    double radius = height / 20.0;
-    double degrees = Math.PI / 180.0;
-
-    ctx.save ();
-    ctx.set_operator (Cairo.Operator.CLEAR);
-    ctx.paint ();
-    ctx.restore ();
-
-    ctx.new_sub_path ();
-    ctx.arc (width - radius, radius, radius, -90 * degrees, 0 * degrees);
-    ctx.arc (width - radius, height - radius, radius, 0 * degrees, 90 * degrees);
-    ctx.arc (radius, height - radius, radius, 90 * degrees, 180 * degrees);
-    ctx.arc (radius, radius, radius, 180 * degrees, 270 * degrees);
-    ctx.close_path ();
-
-    if (_color != null) {
-      Clutter.cairo_set_source_color (ctx, _color);
-      ctx.fill ();
+
+    public Clutter.Canvas canvas {
+        get { return _canvas; }
+    }
+
+    public void resize (float x, float y, float width, float height)
+    {
+        _actor.x = x;
+        _actor.y = y;
+        _actor.width = width;
+        _actor.height = height;
     }
 
-    return false;
-  }
+    public void idle_resize ()
+    {
+        if (!_canvas.set_size ((int)Math.ceilf (_actor.width), (int)Math.ceilf (_actor.height)))
+            _canvas.invalidate ();
+    }
+
+    protected virtual bool _draw (Cairo.Context ctx, int width, int height)
+    {
+        double radius = height / 20.0;
+        double degrees = Math.PI / 180.0;
+
+        ctx.save ();
+        ctx.set_operator (Cairo.Operator.CLEAR);
+        ctx.paint ();
+        ctx.restore ();
+
+        ctx.new_sub_path ();
+        ctx.arc (width - radius, radius, radius, -90 * degrees, 0 * degrees);
+        ctx.arc (width - radius, height - radius, radius, 0 * degrees, 90 * degrees);
+        ctx.arc (radius, height - radius, radius, 90 * degrees, 180 * degrees);
+        ctx.arc (radius, radius, radius, 180 * degrees, 270 * degrees);
+        ctx.close_path ();
+
+        if (_color != null)
+        {
+            Clutter.cairo_set_source_color (ctx, _color);
+            ctx.fill ();
+        }
+
+        return false;
+    }
 }
 
 public class TileView : RoundedRectangle
 {
-  public TileView (float x, float y, float width, float height, uint val)
-  {
-    base (x, y, width, height, null);
+    public TileView (float x, float y, float width, float height, uint val)
+    {
+        base (x, y, width, height, null);
 
-    _value = val;
-    _color = _pick_color ();
-  }
-
-  public uint value {
-    get; set; default = 2;
-  }
+        _value = val;
+        _color = _pick_color ();
+    }
 
+    public uint value {
+        get; set; default = 2;
+    }
 
-  protected override bool _draw (Cairo.Context ctx, int width, int height)
-  {
-    Pango.Rectangle logical_rect;
-    Pango.Layout layout;
-    Pango.FontDescription font_desc;
+    protected override bool _draw (Cairo.Context ctx, int width, int height)
+    {
+        Pango.Rectangle logical_rect;
+        Pango.Layout layout;
+        Pango.FontDescription font_desc;
 
-    base._draw (ctx, width, height);
+        base._draw (ctx, width, height);
 
-    ctx.set_source_rgb (255, 255, 255);
+        ctx.set_source_rgb (255, 255, 255);
 
-    layout = Pango.cairo_create_layout (ctx);
-    font_desc = Pango.FontDescription.from_string ("Sans Bold %dpx".printf (height / 4));
-    layout.set_font_description (font_desc);
+        layout = Pango.cairo_create_layout (ctx);
+        font_desc = Pango.FontDescription.from_string ("Sans Bold %dpx".printf (height / 4));
+        layout.set_font_description (font_desc);
 
-    layout.set_text (value.to_string(), -1);
+        layout.set_text (value.to_string (), -1);
 
-    layout.get_extents (null, out logical_rect);
-    ctx.move_to ((width / 2) - (logical_rect.width / 2 / Pango.SCALE),
-                 (height / 2) - (logical_rect.height / 2 / Pango.SCALE));
-    Pango.cairo_show_layout (ctx, layout);
+        layout.get_extents (null, out logical_rect);
+        ctx.move_to ((width / 2) - (logical_rect.width / 2 / Pango.SCALE),
+                     (height / 2) - (logical_rect.height / 2 / Pango.SCALE));
+        Pango.cairo_show_layout (ctx, layout);
 
-    return false;
-  }
+        return false;
+    }
 
-  private Clutter.Color _pick_color ()
-  {
-    return ColorPalette.get_instance ().pick_color (_value);
-  }
+    private Clutter.Color _pick_color ()
+    {
+        return ColorPalette.get_instance ().pick_color (_value);
+    }
 }
 
-public class ColorPalette : GLib.Object
+public class ColorPalette : Object
 {
-  private Gee.HashMap<uint,Clutter.Color?> _palette;
-  private static ColorPalette? _singleton = null;
-
-  public ColorPalette ()
-  {
-    Object ();
-
-    _palette = new Gee.HashMap<uint,Clutter.Color?> ();
-
-    _palette.set (2,    Clutter.Color.from_string ("#fce94f")); // Butter 1
-    _palette.set (4,    Clutter.Color.from_string ("#8ae234")); // Chameleon 1
-    _palette.set (8,    Clutter.Color.from_string ("#fcaf3e")); // Orange 1
-    _palette.set (16,   Clutter.Color.from_string ("#729fcf")); // Sky blue 1
-    _palette.set (32,   Clutter.Color.from_string ("#ad7fa8")); // Plum 1
-    _palette.set (64,   Clutter.Color.from_string ("#c17d11")); // Chocolate 2
-    _palette.set (128,  Clutter.Color.from_string ("#ef2929")); // Scarlet red 1
-    _palette.set (256,  Clutter.Color.from_string ("#c4a000")); // Butter 3
-    _palette.set (512,  Clutter.Color.from_string ("#4e9a06")); // Chameleon 3
-    _palette.set (1024, Clutter.Color.from_string ("#ce5c00")); // Orange 3
-    _palette.set (2048, Clutter.Color.from_string ("#204a87")); // Sky blue 3
-  }
-
-  public static ColorPalette get_instance ()
-  {
-    if (_singleton == null) {
-      ColorPalette._singleton = new ColorPalette ();
+    private Gee.HashMap<uint,Clutter.Color?> _palette;
+    private static ColorPalette? _singleton = null;
+
+    public ColorPalette ()
+    {
+        Object ();
+
+        _palette = new Gee.HashMap<uint,Clutter.Color?> ();
+
+        _palette.set (2,    Clutter.Color.from_string ("#fce94f")); // Butter 1
+        _palette.set (4,    Clutter.Color.from_string ("#8ae234")); // Chameleon 1
+        _palette.set (8,    Clutter.Color.from_string ("#fcaf3e")); // Orange 1
+        _palette.set (16,   Clutter.Color.from_string ("#729fcf")); // Sky blue 1
+        _palette.set (32,   Clutter.Color.from_string ("#ad7fa8")); // Plum 1
+        _palette.set (64,   Clutter.Color.from_string ("#c17d11")); // Chocolate 2
+        _palette.set (128,  Clutter.Color.from_string ("#ef2929")); // Scarlet red 1
+        _palette.set (256,  Clutter.Color.from_string ("#c4a000")); // Butter 3
+        _palette.set (512,  Clutter.Color.from_string ("#4e9a06")); // Chameleon 3
+        _palette.set (1024, Clutter.Color.from_string ("#ce5c00")); // Orange 3
+        _palette.set (2048, Clutter.Color.from_string ("#204a87")); // Sky blue 3
     }
 
-    return _singleton;
-  }
+    public static ColorPalette get_instance ()
+    {
+        if (_singleton == null)
+            ColorPalette._singleton = new ColorPalette ();
 
-  public Clutter.Color pick_color (uint val)
-  {
-    Clutter.Color color;
+        return _singleton;
+    }
 
-    if (_palette.has_key (val)) {
-      color = _palette.get (val);
-    } else {
-      uint norm_val;
-      uint8 sbits;
+    public Clutter.Color pick_color (uint val)
+    {
+        if (_palette.has_key (val))
+            return _palette.get (val);
 
-      norm_val = val / 2048;
-      color = _palette.get (norm_val);
+        uint norm_val = val / 2048;
+        Clutter.Color color = _palette.get (norm_val);
 
-      sbits = (uint8)(val % 7);
-      color.red <<= sbits;
-      color.green <<= sbits;
-      color.blue <<= sbits;
-    }
+        uint8 sbits = (uint8) (val % 7);
+        color.red <<= sbits;
+        color.green <<= sbits;
+        color.blue <<= sbits;
 
-    return color;
-  }
+        return color;
+    }
 }


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