[four-in-a-row/KaKnife/four-in-a-row-vala: 5/65] finished translation (still need to fix game)



commit 5c8e719edc5e0ad1697881a331162271398e764f
Author: Jacob Humphrey <jacob ryan humphrey gmail com>
Date:   Fri Nov 16 04:35:03 2018 -0600

    finished translation (still need to fix game)

 build/config.h           |   51 --
 build/src/ai.c           | 1918 ----------------------------------------------
 build/src/ai.h           |   64 --
 src/Makefile.am          |   49 +-
 src/ai.vala              |    2 +-
 src/games-controls.c     |  374 ---------
 src/games-controls.h     |   45 --
 src/games-controls2.vala |  186 +++++
 src/gfx.c                |  153 ----
 src/gfx.h                |   13 -
 src/gfx.vala             |  260 +++++++
 src/gfx2.vala            |  174 -----
 src/main.c               |  725 ------------------
 src/main.h               |   75 --
 src/main2.vala           |  890 ++++++++++++++++++---
 src/prefs.c              |  640 ----------------
 src/prefs.h              |   17 -
 src/prefs.vala           |   10 +-
 src/rules.h              |   24 -
 src/temp.vapi            |  105 +--
 src/theme.c              |   13 -
 src/theme.h              |   27 -
 src/theme.vala           |   27 +-
 23 files changed, 1271 insertions(+), 4571 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 480e4d8..d255254 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -2,22 +2,13 @@ bin_PROGRAMS = four-in-a-row
 
 check_PROGRAMS = ai-test
 
-four_in_a_row_SOURCES = main.h     \
-                main.c     \
-                gfx.h      \
-                gfx.c      \
-                prefs.h    \
-                theme.h    \
-                games-controls.c \
-                games-controls.h \
-                games-controls2.vala \
-                rules.h \
-                $(ai_C) \
-                main2.vala \
-                $(ai_HEADER)\
-               prefs.vala \
-               gfx2.vala \
-               theme.vala
+four_in_a_row_SOURCES = \
+               games-controls2.vala \
+               ai.vala \
+               main2.vala \
+               prefs.vala \
+               gfx.vala \
+               theme.vala
 
 four_in_a_row_CPPFLAGS = \
        -I$(top_srcdir)
@@ -27,26 +18,18 @@ four_in_a_row_CFLAGS = \
        -DSOUND_DIRECTORY=\"$(datadir)/four-in-a-row/sounds\" \
        -DLOCALEDIR=\"$(datadir)/locale\" \
        -DICON_THEME_DIRECTORY="\"$(datadir)/icons\"" \
+       -DGETTEXT_PACKAGE=$GETTEXT_PACKAGE \
        $(FOUR_IN_A_ROW_CFLAGS)
 
 four_in_a_row_LDADD = \
        $(FOUR_IN_A_ROW_LIBS)
 
-four_in_a_row_VALAFLAGS = --pkg gtk+-3.0 \
-                         --vapidir . \
-                         --pkg temp
-
-ai_VALA = ai.vala
-
-ai_HEADER = ai.h
-
-ai_C = $(ai_VALA:.vala=.c)
-
-$(ai_HEADER): $(ai_VALA)
-       $(V_VALAC) $(VALAC) -C --basedir=$(srcdir) --directory=$(builddir) --header=ai.h \
-               --pkg glib-2.0 --pkg gio-2.0 --pkg posix --use-header $(VALAFLAGS) $^
-
-$(ai_C) : $(ai_HEADER)
+four_in_a_row_VALAFLAGS = \
+               --pkg gtk+-3.0 \
+               --pkg libcanberra-gtk \
+               --pkg libcanberra \
+               --vapidir . \
+               --pkg temp
 
 ai_test_SOURCES = \
        ai.vala \
@@ -61,10 +44,6 @@ ai_test_LDADD = \
 check-local: $(check_PROGRAMS)
        $(GTESTER) --keep-going --verbose $(check_PROGRAMS)
 
-BUILT_SOURCES = \
-       $(ai_C) \
-       $(ai_HEADER)
-
 EXTRA_DIST = $(BUILT_SOURCES)
 
 MAINTAINERCLEANFILES = \
diff --git a/src/ai.vala b/src/ai.vala
index d1ec09e..cbe9a72 100644
--- a/src/ai.vala
+++ b/src/ai.vala
@@ -29,7 +29,7 @@ const int BOARD_COLUMNS = 7;
 enum Player { NONE, HUMAN, AI; }
 enum Difficulty { EASY, MEDIUM, HARD; }
 
-int playgame (string moves_until_now)
+public int playgame (string moves_until_now)
 {
     var t = new DecisionTree ();
     return t.playgame (moves_until_now);
diff --git a/src/games-controls2.vala b/src/games-controls2.vala
index e69de29..2371fd5 100644
--- a/src/games-controls2.vala
+++ b/src/games-controls2.vala
@@ -0,0 +1,186 @@
+using Gtk;
+
+const string jjjj = Config.GETTEXT_PACKAGE;
+
+enum Columns {
+  CONFKEY_COLUMN = 0,
+  LABEL_COLUMN,
+  KEYCODE_COLUMN,
+  KEYMODS_COLUMN,
+  DEFAULT_KEYCODE_COLUMN,
+  DEFAULT_KEYMODS_COLUMN,
+  N_COLUMNS
+}
+
+public class GamesControlsList: Gtk.ScrolledWindow {
+       Gtk.TreeModel model;
+       Gtk.ListStore store;
+       Gtk.TreeView view;
+
+       GLib.Settings settings;
+       ulong notify_handler_id;
+
+       public GamesControlsList(GLib.Settings settings) {
+               Gtk.CellRenderer label_renderer;
+               CellRendererAccel key_renderer;
+               Gtk.TreeViewColumn column;
+
+               this.hscrollbar_policy = Gtk.PolicyType.NEVER;
+               this.vscrollbar_policy = Gtk.PolicyType.AUTOMATIC;
+               this.shadow_type = Gtk.ShadowType.IN;
+               this.settings = settings;
+               notify_handler_id = settings.changed
+                       .connect(settings_changed_cb);
+
+               store = new Gtk.ListStore(Columns.N_COLUMNS,
+                       Type.STRING,
+                       Type.STRING,
+                       Type.UINT,
+                       Type.UINT,
+                       Type.UINT,
+                       Type.UINT);
+
+               model = store;
+               view = new Gtk.TreeView.with_model(model);
+
+               view.headers_visible = false;
+               view.enable_search = false;
+
+               label_renderer = new Gtk.CellRendererText();
+               column = new Gtk.TreeViewColumn.with_attributes("Control", label_renderer,
+                       "text", Columns.LABEL_COLUMN);
+
+               view.append_column(column);
+
+               key_renderer = new Gtk.CellRendererAccel();
+
+               key_renderer.editable = true;
+               key_renderer.accel_mode = Gtk.CellRendererAccelMode.OTHER;
+
+               key_renderer.accel_edited.connect(this.accel_edited_cb);
+               key_renderer.accel_cleared.connect(this.accel_cleared_cb);
+
+               column = new TreeViewColumn.with_attributes("Key", key_renderer,
+                       "accel-key", Columns.KEYCODE_COLUMN,
+                       "accel-mods", Columns.KEYMODS_COLUMN);
+
+               view.append_column(column);
+               this.add(view);
+       }
+
+       void accel_cleared_cb (string path_string)
+       {
+               TreePath path;
+               TreeIter iter;
+               string conf_key = null;
+               int default_keyval = 0; //set to 0 to make valac happy
+
+               path = new TreePath.from_string (path_string);
+               if (path == null)
+                       return;
+
+               if (!model.get_iter (out iter, path)) {
+                       return;
+               }
+
+               model.get(iter,
+                       Columns.CONFKEY_COLUMN, conf_key,
+                       Columns.DEFAULT_KEYCODE_COLUMN, default_keyval);
+
+               if(conf_key == null)
+                       return;
+
+               /* Note: the model is updated in the conf notification callback */
+               /* FIXME: what to do with the modifiers? */
+               settings.set_int(conf_key, default_keyval);
+       }
+
+       void accel_edited_cb (string path_string, uint keyval,
+               Gdk.ModifierType mask, uint hardware_keycode)
+       {
+               TreePath path;
+               TreeIter iter;
+               string conf_key = null;
+               bool valid;
+               bool unused_key = true;
+
+
+               path = new TreePath.from_string (path_string);
+               if (path == null)
+                       return;
+
+               if (!model.get_iter (out iter, path)) {
+                       return;
+               }
+
+               model.get (iter, Columns.CONFKEY_COLUMN, conf_key);
+               if (conf_key == null)
+                       return;
+
+               valid = model.get_iter_first (out iter);
+               while (valid) {
+                       string actual_conf_key = null;
+
+                       model.get (iter, Columns.CONFKEY_COLUMN, actual_conf_key);
+
+                       if (settings.get_int (actual_conf_key) == keyval){
+                               unused_key = false;
+
+                               if (conf_key == actual_conf_key) {
+                                       var dialog = new MessageDialog.with_markup (window,
+                                               DialogFlags.DESTROY_WITH_PARENT,
+                                               MessageType.WARNING,
+                                               ButtonsType.OK,
+                                               "<span weight=\"bold\" size=\"larger\">%s</span>",
+                                               _("This key is already in use."));
+
+                                       dialog.run();
+                               }
+                               break;
+                       }
+
+                       valid = store.iter_next (ref iter);
+               }
+
+               /* Note: the model is updated in the conf notification callback */
+               /* FIXME: what to do with the modifiers? */
+               if (unused_key)
+                       settings.set_int (conf_key, (int)keyval);
+       }
+
+       void add_control (string conf_key, string? label,
+                               uint default_keyval) {
+               Gtk.TreeIter iter;
+               uint keyval;
+
+               if (label == null)
+                       label = _("Unknown Command");
+
+               keyval = settings.get_int(conf_key);
+
+               store.insert_with_values(out iter, -1,
+                       Columns.CONFKEY_COLUMN, conf_key,
+                       Columns.LABEL_COLUMN, label,
+                       Columns.KEYCODE_COLUMN, keyval,
+                       Columns.KEYMODS_COLUMN, 0,
+                       Columns.DEFAULT_KEYCODE_COLUMN, default_keyval,
+                       Columns.DEFAULT_KEYMODS_COLUMN, 0
+                       );
+
+       }
+
+       void add_controls (string first_gconf_key, ...) {
+               var args = va_list();
+               string? key;
+               string label;
+               uint keyval;
+
+               key = first_gconf_key;
+               while (key != null) {
+                       label = args.arg();
+                       keyval = args.arg();
+                       this.add_control (key, label, keyval);
+                       key = args.arg();
+               }
+       }
+}
diff --git a/src/gfx.vala b/src/gfx.vala
new file mode 100644
index 0000000..5296774
--- /dev/null
+++ b/src/gfx.vala
@@ -0,0 +1,260 @@
+//using GETTTEXT_PACKAGE_CONTENT;
+const string GETTEXT_PACKAGE2 = Config.GETTEXT_PACKAGE;
+Gtk.Widget drawarea;
+//extern Theme theme[];
+int[,] gboard;
+int boardsize = 0;
+int tilesize = 0;
+int offset[6];
+
+namespace Gfx{
+       /* unscaled pixbufs */
+       Gdk.Pixbuf pb_tileset_raw;
+       Gdk.Pixbuf pb_bground_raw;
+
+       /* scaled pixbufs */
+       Gdk.Pixbuf pb_tileset;
+       Gdk.Pixbuf pb_bground;
+
+       public int get_column (int xpos) {
+               /* Derive column from pixel position */
+               int c = xpos / tilesize;
+               if (c > 6)
+                       c = 6;
+               if (c < 0)
+                       c = 0;
+
+               return c;
+       }
+
+       public void draw_tile (int r, int c) {
+               drawarea.queue_draw_area(c*tilesize, r*tilesize, tilesize, tilesize);
+       }
+
+       public void draw_all () {
+               drawarea.queue_draw_area(0, 0, boardsize, boardsize);
+       }
+
+       bool change_theme () {
+               if (!Gfx.load_pixmaps ())
+                       return false;
+
+               Gfx.refresh_pixmaps ();
+               draw_all ();
+               return true;
+       }
+
+       void resize (Gtk.Widget w) {
+               int width, height;
+
+               width = w.get_allocated_width ();
+               height = w.get_allocated_height ();
+
+               boardsize = int.min (width, height);
+               tilesize = boardsize / 7;
+
+               offset[Tile.PLAYER1] = 0;
+               offset[Tile.PLAYER2] = tilesize;
+               offset[Tile.CLEAR] = tilesize * 2;
+               offset[Tile.CLEAR_CURSOR] = tilesize * 3;
+               offset[Tile.PLAYER1_CURSOR] = tilesize * 4;
+               offset[Tile.PLAYER2_CURSOR] = tilesize * 5;
+
+               Gfx.refresh_pixmaps ();
+               draw_all ();
+       }
+
+       void expose (Cairo.Context cr) {
+               int r, c;
+
+               /* draw the background */
+               cr.save();
+               Gdk.cairo_set_source_pixbuf(cr, pb_bground, 0, 0);
+               cr.rectangle(0, 0, boardsize, boardsize);
+               cr.paint();
+               cr.restore();
+
+               for (r = 0; r < 7; r++) {
+                       for (c = 0; c < 7; c++) {
+                               Gfx.paint_tile (cr, r, c);
+                       }
+               }
+
+               draw_grid (cr);
+       }
+
+       void draw_grid (Cairo.Context cr) {
+               const double dashes[] = { 4.0, 4.0 };
+               int i;
+               Gdk.RGBA color = Gdk.RGBA();
+
+               color.parse(theme[p.theme_id].grid_color);
+               Gdk.cairo_set_source_rgba (cr, color);
+               cr.set_operator (Cairo.Operator.SOURCE);
+               cr.set_line_width (1);
+               cr.set_line_cap (Cairo.LineCap.BUTT);
+               cr.set_line_join (Cairo.LineJoin.MITER);
+               cr.set_dash (dashes, 0);
+
+               /* draw the grid on the background pixmap */
+               for (i = 1; i < 7; i++) {
+                       cr.move_to (i * tilesize + 0.5, 0);
+                       cr.line_to (i * tilesize + 0.5, boardsize);
+                       cr.move_to (0, i * tilesize + 0.5);
+                       cr.line_to (boardsize, i * tilesize + 0.5);
+               }
+               cr.stroke();
+
+               /* Draw separator line at the top */
+               cr.set_dash(null, 0);
+               cr.move_to(0, tilesize+0.5);
+               cr.line_to(boardsize, tilesize +0.5);
+
+               cr.stroke();
+       }
+
+    void load_error (string fname) {
+       Gtk.MessageDialog dialog;
+
+       dialog = new Gtk.MessageDialog(window, Gtk.DialogFlags.MODAL,
+           Gtk.MessageType.WARNING, Gtk.ButtonsType.CLOSE,
+       dgettext(Config.GETTEXT_PACKAGE, "Unable to load image:\n%s"), fname);
+
+       dialog.run();
+       dialog.destroy();
+    }
+
+    void paint_tile (Cairo.Context cr, int r, int c) {
+       int x = c * tilesize;
+       int y = r * tilesize;
+       int tile = gboard[r,c];
+       int os = 0;
+
+       if (tile == Tile.CLEAR && r != 0)
+           return;
+
+       switch (tile) {
+       case Tile.PLAYER1:
+           if (r == 0)
+               os = offset[Tile.PLAYER1_CURSOR];
+           else
+               os = offset[Tile.PLAYER1];
+           break;
+       case Tile.PLAYER2:
+           if (r == 0)
+               os = offset[Tile.PLAYER2_CURSOR];
+           else
+               os = offset[Tile.PLAYER2];
+           break;
+       case Tile.CLEAR:
+           if (r == 0)
+               os = offset[Tile.CLEAR_CURSOR];
+           else
+               os = offset[Tile.CLEAR];
+           break;
+       }
+
+
+       cr.save();
+       //gdk_cairo_set_source_pixbuf (cr, pb_tileset, x - os, y);
+       cr.rectangle (x, y, tilesize, tilesize);
+
+       cr.clip();
+       cr.paint();
+       cr.restore();
+    }
+
+       void refresh_pixmaps () {
+               /* scale the pixbufs */
+               pb_tileset = pb_tileset_raw.scale_simple (tilesize * 6, tilesize, Gdk.InterpType.BILINEAR);
+               pb_bground = pb_bground_raw.scale_simple (boardsize, boardsize, Gdk.InterpType.BILINEAR);
+       }
+
+
+
+bool load_pixmaps ()
+{
+       string fname;
+       Gdk.Pixbuf pb_tileset_tmp;
+       Gdk.Pixbuf pb_bground_tmp = null;
+
+       /* Try the theme pixmaps, fallback to the default and then give up */
+       while (true) {
+               fname = Path.build_filename (Config.DATA_DIRECTORY, theme[p.theme_id].fname_tileset, null);
+               try {
+                       pb_tileset_tmp = new Gdk.Pixbuf.from_file (fname);
+               } catch (Error e) {
+                       if (p.theme_id != 0) {
+                               p.theme_id = 0;
+                               continue;
+                       } else {
+                               Gfx.load_error (fname);
+                               return false;
+                       }
+               }
+               break;
+       }
+
+       pb_tileset_raw = pb_tileset_tmp;
+
+       if (theme[p.theme_id].fname_bground != null) {
+               fname = Path.build_filename (Config.DATA_DIRECTORY, theme[p.theme_id].fname_bground, null);
+               try {
+                       pb_bground_tmp = new Gdk.Pixbuf.from_file (fname);
+               } catch (Error e) {
+                       Gfx.load_error (fname);
+                       return false;
+               }
+       }
+
+       /* If a separate background image wasn't supplied,
+       * derive the background image from the tile set
+       */
+       if (pb_bground_tmp != null) {
+               pb_bground_raw = pb_bground_tmp;
+       } else {
+               int tilesize_raw;
+               int i, j;
+
+               tilesize_raw = pb_tileset_raw.get_height();
+
+               pb_bground_raw = new Gdk.Pixbuf (Gdk.Colorspace.RGB, true, 8,
+                       tilesize_raw * 7, tilesize_raw * 7);
+               for (i = 0; i < 7; i++) {
+                       pb_tileset_raw.copy_area (tilesize_raw * 3, 0,
+                               tilesize_raw, tilesize_raw,
+                               pb_bground_raw, i * tilesize_raw, 0);
+                       for (j = 1; j < 7; j++) {
+                               pb_tileset_raw.copy_area (
+                                       tilesize_raw * 2, 0,
+                                       tilesize_raw, tilesize_raw,
+                                       pb_bground_raw,
+                                       i * tilesize_raw, j * tilesize_raw);
+                       }
+               }
+       }
+
+       return true;
+}
+
+       void free ()
+       {
+               if (pb_tileset_raw != null) {
+                       pb_tileset_raw.unref();
+                       pb_tileset_raw = null;
+               }
+               if (pb_bground_raw != null) {
+                       pb_bground_raw.unref();
+                       pb_bground_raw = null;
+               }
+               if (pb_tileset != null) {
+                       pb_tileset.unref();
+                       pb_tileset = null;
+               }
+               if (pb_bground != null) {
+                       pb_bground.unref();
+                       pb_bground = null;
+               }
+       }
+
+}
diff --git a/src/main2.vala b/src/main2.vala
index 154dff5..a82e123 100644
--- a/src/main2.vala
+++ b/src/main2.vala
@@ -1,9 +1,61 @@
+using Config;
 using Intl;
 using Gtk;
 //using temp;
 
-const string jfasolfdas = Config.GETTEXT_PACKAGE;
-extern int main2(int argc, char** argv);
+public enum AnimID {
+       NONE,
+       MOVE,
+       DROP,
+       BLINK,
+       HINT
+}
+
+public enum PlayerID {
+       PLAYER1,
+       PLAYER2,
+       NOBODY
+}
+
+public enum Level {
+       HUMAN,
+       WEAK,
+       MEDIUM,
+       STRONG
+}
+
+public enum Tile {
+       PLAYER1,
+       PLAYER2,
+       CLEAR,
+       CLEAR_CURSOR,
+       PLAYER1_CURSOR,
+       PLAYER2_CURSOR,
+}
+
+public enum Move {
+       LEFT,
+       RIGHT,
+       DROP
+}
+
+public enum SoundID{
+       DROP,
+       I_WIN,
+       YOU_WIN,
+       PLAYER_WIN,
+       DRAWN_GAME,
+       COLUMN_FULL
+}
+
+SimpleAction hint_action;
+SimpleAction undo_action;
+SimpleAction new_game_action;
+
+//const string jfasolfdas = Config.GETTEXT_PACKAGE;
+const string APPNAME_LONG = N_("Four-in-a-row");
+const int SIZE_VSTR = 53;
+
 Gtk.Application? application;
 Window window;
 Gtk.Dialog? scorebox = null;
@@ -16,10 +68,9 @@ PlayerID winner;
 PlayerID who_starts;
 int score[3];
 AnimID anim;
-char vstr[SIZE_VSTR];
-extern char vlevel[];
+char vstr[53];
+const char vlevel[] = {'0','a','b','c','\0'};
 int moves;
-extern const int SIZE_VSTR;
 const int SPEED_BLINK = 150;
 const int SPEED_MOVE = 35;
 const int SPEED_DROP = 20;
@@ -27,7 +78,10 @@ int column;
 int column_moveto;
 int row;
 int row_dropto;
-extern Gtk.HeaderBar headerbar;
+Gtk.HeaderBar headerbar;
+
+const int DEFAULT_WIDTH = 495;
+const int DEFAULT_HEIGHT = 435;
 
 int blink_r1 = 0;
 int blink_c1 = 0;
@@ -38,151 +92,194 @@ int blink_n = 0;
 bool blink_on = false;
 uint timeout = 0;
 
-void on_game_new(SimpleAction a, Variant v) {
-    stop_anim ();
-    game_reset ();
+void on_game_new(SimpleAction a, Variant? v) {
+       stop_anim ();
+       game_reset ();
 }
 
 void draw_line (int r1, int c1, int r2, int c2, int tile)
 {
-  /* draw a line of 'tile' from r1,c1 to r2,c2 */
+       /* draw a line of 'tile' from r1,c1 to r2,c2 */
+
+       bool done = false;
+       int d_row = 0;
+       int d_col = 0;
+
+       if (r1 < r2)
+               d_row = 1;
+       else if (r1 > r2)
+               d_row = -1;
+
+       if (c1 < c2)
+               d_col = 1;
+       else if (c1 > c2)
+               d_col = -1;
+
+       do {
+               done = (r1 == r2 && c1 == c2);
+               gboard[r1, c1] = tile;
+               Gfx.draw_tile (r1, c1);
+               if (r1 != r2)
+                       r1 += d_row;
+               if (c1 != c2)
+                       c1 += d_col;
+       } while (!done);
+}
 
-  bool done = false;
-  int d_row = 0;
-  int d_col = 0;
+public int main(string[] argv) {
+       gboard = new int[7,7];
+       setlocale();
 
-  if (r1 < r2)
-    d_row = 1;
-  else if (r1 > r2)
-    d_row = -1;
+       application = new Gtk.Application("org.gnome.four-in-a-row", 0);
 
-  if (c1 < c2)
-    d_col = 1;
-  else if (c1 > c2)
-    d_col = -1;
+       bindtextdomain(Config.GETTEXT_PACKAGE, Config.LOCALEDIR);
+       bind_textdomain_codeset(Config.GETTEXT_PACKAGE, "UTF-8");
+       textdomain(Config.GETTEXT_PACKAGE);
 
-  do {
-    done = (r1 == r2 && c1 == c2);
-    gboard[r1, c1] = tile;
-    Gfx.draw_tile (r1, c1);
-    if (r1 != r2)
-      r1 += d_row;
-    if (c1 != c2)
-      c1 += d_col;
-  } while (!done);
-}
+       application.startup.connect(create_app);
+       application.activate.connect(activate);
 
-public int main(string[] argv) {
-    setlocale();
+       var context = new OptionContext();
+       context.add_group(get_option_group(true));
+       try {
+               context.parse(ref argv);
+       } catch (Error error) {
+               print("%s", error.message);
+               return 1;
+       }
+
+       settings = new GLib.Settings("org.gnome.four-in-a-row");
 
-    var application = new Gtk.Application("org.gnome.four-in-a-row", 0);
+       Environment.set_application_name(_(Config.APPNAME_LONG));
 
-    return main2(argv.length, argv);
+       prefs_init();
+       game_init();
+
+       if (!Gfx.load_pixmaps())
+               return 1;
+
+       var app_retval = application.run(argv);
+
+       //game_free();
+
+       return app_retval;
 }
 
 public void activate() {
-    if (!window.is_visible()) {
-        window.show_all();
-        gfx_refresh_pixmaps();
-        Gfx.draw_all ();
-        scorebox_update ();       /* update visible player descriptions */
-        prompt_player ();
-        game_reset ();
-    }
+       if (!window.is_visible()) {
+               window.show_all();
+               Gfx.refresh_pixmaps();
+               Gfx.draw_all ();
+               scorebox_update ();       /* update visible player descriptions */
+               prompt_player ();
+               game_reset ();
+       }
+}
+
+class NextMove {
+       int c;
+
+       public NextMove(int c) {
+               this.c = c;
+       }
+
+       public bool exec() {
+               return next_move(c);
+       }
 }
 
-public int next_move(int c) {
-    process_move(c);
-    return 0;
+public bool next_move(int c) {
+       process_move(c);
+       return false;
 }
 
 public void game_process_move(int c) {
-    process_move(c);
+       process_move(c);
 }
 
 public void game_free() {
-    gfx_free();
+       Gfx.free();
 }
 
 public void game_init ()
 {
-    //Random.set_seed ((uint) Linux.timegm(null));
+       //Random.set_seed ((uint) Linux.timegm(null));
 
-    anim = AnimID.NONE;
-    gameover = true;
-    player_active = false;
-    player = PlayerID.PLAYER1;
-    winner = PlayerID.NOBODY;
-    score[PlayerID.PLAYER1] = 0;
-    score[PlayerID.PLAYER2] = 0;
-    score[PlayerID.NOBODY] = 0;
+       anim = AnimID.NONE;
+       gameover = true;
+       player_active = false;
+       player = PlayerID.PLAYER1;
+       winner = PlayerID.NOBODY;
+       score[PlayerID.PLAYER1] = 0;
+       score[PlayerID.PLAYER2] = 0;
+       score[PlayerID.NOBODY] = 0;
 
-    who_starts = PlayerID.PLAYER2;     /* This gets reversed immediately. */
+       who_starts = PlayerID.PLAYER2;     /* This gets reversed immediately. */
 
-    clear_board ();
+       clear_board ();
 }
 
 void clear_board () {
-  int r, c, i;
+       int r, c, i;
 
-  for (r = 0; r < 7; r++) {
-    for (c = 0; c < 7; c++) {
-      gboard[r, c] = Tile.CLEAR;
-    }
-  }
+       for (r = 0; r < 7; r++) {
+               for (c = 0; c < 7; c++) {
+                       gboard[r, c] = Tile.CLEAR;
+               }
+       }
 
-  for (i = 0; i < SIZE_VSTR; i++)
-    vstr[i] = '\0';
+       for (i = 0; i < SIZE_VSTR; i++)
+               vstr[i] = '\0';
 
-  vstr[0] = vlevel[Level.WEAK];
-  vstr[1] = '0';
-  moves = 0;
+       vstr[0] = vlevel[Level.WEAK];
+       vstr[1] = '0';
+       moves = 0;
 }
 
 static int first_empty_row (int c) {
-  int r = 1;
+       int r = 1;
 
-  while (r < 7 && gboard[r, c] == Tile.CLEAR)
-    r++;
-  return r - 1;
+       while (r < 7 && gboard[r, c] == Tile.CLEAR)
+               r++;
+       return r - 1;
 }
 
 static int get_n_human_players () {
-  if (p.level[PlayerID.PLAYER1] != Level.HUMAN && p.level[PlayerID.PLAYER2] != Level.HUMAN)
-    return 0;
-  if (p.level[PlayerID.PLAYER1] != Level.HUMAN || p.level[PlayerID.PLAYER2] != Level.HUMAN)
-    return 1;
-  return 2;
+       if (p.level[PlayerID.PLAYER1] != Level.HUMAN && p.level[PlayerID.PLAYER2] != Level.HUMAN)
+               return 0;
+       if (p.level[PlayerID.PLAYER1] != Level.HUMAN || p.level[PlayerID.PLAYER2] != Level.HUMAN)
+               return 1;
+       return 2;
 }
 
 static bool is_player_human ()
 {
-  return player == PLAYER1 ? p.level[PlayerID.PLAYER1] == Level.HUMAN
-                           : p.level[PlayerID.PLAYER2] == Level.HUMAN;
+       return player == PLAYER1 ? p.level[PlayerID.PLAYER1] == Level.HUMAN
+               : p.level[PlayerID.PLAYER2] == Level.HUMAN;
 }
 
 static void drop_marble (int r, int c)
 {
-  int tile;
-  tile = player == PlayerID.PLAYER1 ? Tile.PLAYER1 : Tile.PLAYER2;
+       int tile;
+       tile = player == PlayerID.PLAYER1 ? Tile.PLAYER1 : Tile.PLAYER2;
 
-  gboard[r, c] = tile;
-  Gfx.draw_tile (r, c);
+       gboard[r, c] = tile;
+       Gfx.draw_tile (r, c);
 
-  column = column_moveto = c;
-  row = row_dropto = r;
+       column = column_moveto = c;
+       row = row_dropto = r;
 }
 
 void drop () {
-  int tile;
-  tile = player == PLAYER1 ? Tile.PLAYER1 : Tile.PLAYER2;
+       int tile;
+       tile = player == PLAYER1 ? Tile.PLAYER1 : Tile.PLAYER2;
 
-  gboard[row, column] = Tile.CLEAR;
-  Gfx.draw_tile (row, column);
+       gboard[row, column] = Tile.CLEAR;
+       Gfx.draw_tile (row, column);
 
-  row++;
-  gboard[row, column] = tile;
-  Gfx.draw_tile (row, column);
+       row++;
+       gboard[row, column] = tile;
+       Gfx.draw_tile (row, column);
 }
 
 void move (int c) {
@@ -210,7 +307,7 @@ void swap_player ()
 }
 
 
-void set_status_message (string message)
+void set_status_message (string? message)
 {
     headerbar.set_title(message);
 }
@@ -226,7 +323,8 @@ static void blink_tile (int r, int c, int t, int n) {
   blink_n = n;
   blink_on = false;
   anim = AnimID.BLINK;
-  timeout = Timeout.add (SPEED_BLINK, on_animate);
+  var anim = new Animate(0);
+  timeout = Timeout.add (SPEED_BLINK, anim.exec);
 }
 
 void stop_anim ()
@@ -249,7 +347,7 @@ bool on_drawarea_draw (Gtk.Widget w, Cairo.Context cr) {
 }
 
 void
-on_game_undo (SimpleAction action, Variant parameter)
+on_game_undo (SimpleAction action, Variant? parameter)
 {
   int r, c;
 
@@ -288,18 +386,18 @@ on_game_undo (SimpleAction action, Variant parameter)
     }
   }
 }
-void on_game_scores (SimpleAction action, Variant parameter)
+void on_game_scores (SimpleAction action, Variant? parameter)
 {
     Gtk.Grid grid, grid2;
     Gtk.Widget icon;
 
     if (scorebox != null) {
-        scorebox.present();
-        return;
+       scorebox.present();
+       return;
     }
 
     scorebox = new Gtk.Dialog.with_buttons(_("Scores"), window,
-        Gtk.DialogFlags.DESTROY_WITH_PARENT | Gtk.DialogFlags.USE_HEADER_BAR);
+       Gtk.DialogFlags.DESTROY_WITH_PARENT | Gtk.DialogFlags.USE_HEADER_BAR);
 
     scorebox.set_resizable(false);
     scorebox.set_border_width(5);
@@ -352,13 +450,13 @@ void on_game_scores (SimpleAction action, Variant parameter)
 
     //scorebox.response.connect(on_dialog_close);
 
-    scorebox.show_all();
+       scorebox.show_all();
 
-    scorebox_update ();
+       scorebox_update ();
 }
 
 void
-on_game_exit (SimpleAction action, Variant parameter)
+on_game_exit (SimpleAction action, Variant? parameter)
 {
   stop_anim ();
   application.quit();
@@ -374,7 +472,8 @@ process_move2 (int c)
     row = 0;
     row_dropto = r;
     anim = AnimID.DROP;
-    timeout = Timeout.add(SPEED_DROP, on_animate, c);
+    var temp = new Animate(c);
+    timeout = Timeout.add(SPEED_DROP, temp.exec);
     //timeout = g_timeout_add (SPEED_DROP, (GSourceFunc) on_animate, GINT_TO_POINTER (c));
   } else {
     play_sound (SoundID.COLUMN_FULL);
@@ -413,12 +512,12 @@ bool is_dline1_at (PlayerID p, int r, int c, int * r1, int * c1, int * r2, int *
 
 bool is_line_at (PlayerID p, int r, int c)
 {
-  int r1, r2, c1, c2;
+       int r1, r2, c1, c2;
 
-  return is_hline_at (p, r, c, &r1, &c1, &r2, &c2) ||
-    is_vline_at (p, r, c, &r1, &c1, &r2, &c2) ||
-    is_dline1_at (p, r, c, &r1, &c1, &r2, &c2) ||
-    is_dline2_at (p, r, c, &r1, &c1, &r2, &c2);
+       return is_hline_at (p, r, c, &r1, &c1, &r2, &c2) ||
+               is_vline_at (p, r, c, &r1, &c1, &r2, &c2) ||
+               is_dline1_at (p, r, c, &r1, &c1, &r2, &c2) ||
+               is_dline2_at (p, r, c, &r1, &c1, &r2, &c2);
 }
 
 bool is_dline2_at (PlayerID p, int r, int c, int * r1, int * c1, int * r2, int * c2) {
@@ -453,22 +552,567 @@ bool is_hline_at (PlayerID p, int r, int c, int * r1, int * c1, int * r2, int *
 
 void scorebox_reset ()
 {
-  score[PlayerID.PLAYER1] = 0;
-  score[PlayerID.PLAYER2] = 0;
-  score[PlayerID.NOBODY] = 0;
-  scorebox_update ();
+       score[PlayerID.PLAYER1] = 0;
+       score[PlayerID.PLAYER2] = 0;
+       score[PlayerID.NOBODY] = 0;
+       scorebox_update ();
 }
 
 void process_move (int c)
 {
-    if (timeout != 0) {
-        //Timeout.add(SPEED_DROP, next_move, c.to_pointer());
-        //g_timeout_add (SPEED_DROP, (GSourceFunc) next_move, GINT_TO_POINTER (c));
-        return;
-    }
+       if (timeout != 0) {
+               //Timeout.add(SPEED_DROP, next_move, c.to_pointer());
+               //g_timeout_add (SPEED_DROP, (GSourceFunc) next_move, GINT_TO_POINTER (c));
+               return;
+       }
+
+       column_moveto = c;
+       anim = AnimID.MOVE;
+       //Timeout.add(SPEED_DROP, on_animate, c.to_pointer());
+       //timeout = g_timeout_add (SPEED_MOVE, (GSourceFunc) on_animate, GINT_TO_POINTER (c));
+}
+
+void on_help_about (SimpleAction action, Variant? parameter)
+{
+       const string authors[] = {"Tim Musson <trmusson ihug co nz>",
+               "David Neary <bolsh gimp org>",
+               "Nikhar Agrawal <nikharagrawal2006 gmail com>"
+       };
+
+       const string artists[] = { "Alan Horkan",
+               "Anatol Drlicek",
+               "Based on the Faenza icon theme by Matthieu James"
+       };
+
+       const string documenters[] = {"Timothy Musson"};
+
+       Gtk.show_about_dialog(window,
+               name: _(Config.APPNAME_LONG),
+               version: Config.VERSION,
+               copyright: "Copyright © 1999–2008 Tim Musson and David Neary\nCopyright © 2014 Michael 
Catanzaro",
+               license_type: Gtk.License.GPL_2_0,
+               comments: _("Connect four in a row to win"),
+               authors: authors,
+               documenters: documenters,
+               artists: artists,
+               translator_credits: _("translator-credits"),
+               logo_icon_name: "four-in-a-row",
+               website: "https://wiki.gnome.org/Apps/Four-in-a-row";
+               );
+}
+
+void check_game_state ()
+{
+       if (is_line_at (player, row, column)) {
+               gameover = true;
+               winner = player;
+               switch (get_n_human_players ()) {
+               case 1:
+                       play_sound (is_player_human () ? SoundID.YOU_WIN : SoundID.I_WIN);
+                       break;
+               case 0:
+               case 2:
+                       play_sound (SoundID.PLAYER_WIN);
+                       break;
+               }
+               blink_winner (6);
+       } else if (moves == 42) {
+               gameover = true;
+               winner = NOBODY;
+               play_sound (SoundID.DRAWN_GAME);
+       }
+}
+
+void
+on_help_contents (SimpleAction action, Variant? parameter)
+{
+       try {
+               Gtk.show_uri (window.get_screen(),
+                       "help:four-in-a-row",
+                       Gtk.get_current_event_time ());
+       } catch(Error error) {
+               warning ("Failed to show help: %s", error.message);
+       }
+}
+
+void process_move3 (int c)
+{
+       play_sound (SoundID.DROP);
+
+       vstr[++moves] = '1' + (char)c;
+       vstr[moves + 1] = '0';
+
+       check_game_state ();
+
+       if (gameover) {
+               score[winner]++;
+               scorebox_update ();
+               prompt_player ();
+       } else {
+               swap_player ();
+               if (!is_player_human ()) {
+                       vstr[0] = player == PlayerID.PLAYER1 ? vlevel[p.level[PlayerID.PLAYER1]]
+                               : vlevel[p.level[PlayerID.PLAYER2]];
+                       c = playgame ((string)vstr) - 1;
+                       if (c < 0)
+                               gameover = true;
+                       var nm = new NextMove(c);
+                       Timeout.add(SPEED_DROP, nm.exec);
+               }
+       }
+}
+
+void game_reset ()
+{
+       stop_anim ();
+
+       undo_action.set_enabled(false);
+       hint_action.set_enabled(false);
+
+       who_starts = (who_starts == PlayerID.PLAYER1)
+               ? PlayerID.PLAYER2 : PlayerID.PLAYER1;
+       player = who_starts;
+
+       gameover = true;
+       player_active = false;
+       winner = NOBODY;
+       column = 3;
+       column_moveto = 3;
+       row = 0;
+       row_dropto = 0;
+
+       clear_board ();
+       set_status_message (null);
+       Gfx.draw_all ();
+
+       move_cursor (column);
+       gameover = false;
+       prompt_player ();
+       if (!is_player_human ()) {
+               vstr[0] = player == PLAYER1 ? vlevel[p.level[PlayerID.PLAYER1]]
+                       : vlevel[p.level[PlayerID.PLAYER2]];
+               game_process_move (playgame ((string)vstr) - 1);
+       }
+}
+
+void
+play_sound (SoundID id)
+{
+       string name;
+
+       if (!p.do_sound)
+               return;
+
+       switch (id) {
+       case SoundID.DROP:
+               name = "slide";
+               break;
+       case SoundID.I_WIN:
+               name = "reverse";
+               break;
+       case SoundID.YOU_WIN:
+               name = "bonus";
+               break;
+       case SoundID.PLAYER_WIN:
+               name = "bonus";
+               break;
+       case SoundID.DRAWN_GAME:
+               name = "reverse";
+               break;
+       case SoundID.COLUMN_FULL:
+               name = "bad";
+               break;
+       default:
+               return;
+       }
+
+
+       string filename, path;
+
+       filename = name + ".ogg";
+       path = Path.build_filename (Config.SOUND_DIRECTORY, filename);
+
+       CanberraGtk.context_get().play(
+                       id,
+                       Canberra.PROP_MEDIA_NAME, name,
+                       Canberra.PROP_MEDIA_FILENAME, path);
+
+}
+
+class Animate {
+       int c;
+       public Animate(int c) {
+               this.c = c;
+       }
+
+       public bool exec() {
+               return on_animate(c);
+       }
+}
+
+bool on_animate (int c = 0)
+{
+       if (anim == AnimID.NONE)
+               return false;
+
+       switch (anim) {
+       case AnimID.NONE:
+               break;
+       case AnimID.HINT:
+       case AnimID.MOVE:
+               if (column < column_moveto) {
+                       move (column + 1);
+               } else if (column > column_moveto) {
+                       move (column - 1);
+               } else {
+                       timeout = 0;
+                       if (anim == AnimID.MOVE) {
+                               anim = AnimID.NONE;
+                               process_move2 (c);
+                       } else {
+                               anim = AnimID.NONE;
+                       }
+                       return false;
+               }
+               break;
+       case AnimID.DROP:
+               if (row < row_dropto) {
+                       drop ();
+               } else {
+                       anim = AnimID.NONE;
+                       timeout = 0;
+                       process_move3 (c);
+                       return false;
+               }
+               break;
+       case AnimID.BLINK:
+               draw_line (blink_r1, blink_c1, blink_r2, blink_c2, blink_on ? blink_t
+                       : Tile.CLEAR);
+               blink_n--;
+               if (blink_n <= 0 && blink_on) {
+                       anim = AnimID.NONE;
+                       timeout = 0;
+                       return false;
+               }
+               blink_on = !blink_on;
+               break;
+       }
+       return true;
+}
+
+bool on_key_press (Widget  w, Gdk.EventKey  e)
+{
+       if ((player_active) || timeout != 0 ||
+                       (e.keyval != p.keypress[Move.LEFT] &&
+                       e.keyval != p.keypress[Move.RIGHT] &&
+                       e.keyval != p.keypress[Move.DROP])) {
+               return false;
+       }
+
+       if (gameover) {
+               blink_winner (2);
+               return true;
+       }
+
+       if (e.keyval == p.keypress[Move.LEFT] && column != 0) {
+               column_moveto--;
+               move_cursor (column_moveto);
+       } else if (e.keyval == p.keypress[Move.RIGHT] && column < 6) {
+               column_moveto++;
+               move_cursor (column_moveto);
+       } else if (e.keyval == p.keypress[Move.DROP]) {
+               game_process_move (column);
+       }
+       return true;
+}
+
+void
+blink_winner (int n)
+{
+       /* blink the winner's line(s) n times */
+
+       if (winner == NOBODY)
+               return;
+
+       blink_t = winner;
+       if (is_hline_at (winner, row, column, &blink_r1, &blink_c1, &blink_r2, &blink_c2)) {
+               anim = AnimID.BLINK;
+               blink_on = false;
+               blink_n = n;
+               var temp = new Animate(0);
+               timeout = Timeout.add (SPEED_BLINK,  temp.exec);
+               while (timeout!=0)
+                       Gtk.main_iteration();
+       }
+
+       if (is_vline_at (winner, row, column, &blink_r1, &blink_c1, &blink_r2, &blink_c2)) {
+               anim = AnimID.BLINK;
+               blink_on = false;
+               blink_n = n;
+               var temp = new Animate(0);
+               timeout = Timeout.add (SPEED_BLINK,  temp.exec);
+               while (timeout!=0)
+                       Gtk.main_iteration();
+       }
+
+       if (is_dline1_at (winner, row, column, &blink_r1, &blink_c1, &blink_r2, &blink_c2)) {
+               anim = AnimID.BLINK;
+               blink_on = false;
+               blink_n = n;
+               var temp = new Animate(0);
+               timeout = Timeout.add (SPEED_BLINK,  temp.exec);
+               while (timeout!=0)
+                       Gtk.main_iteration();
+       }
+
+       if (is_dline2_at (winner, row, column, &blink_r1, &blink_c1, &blink_r2, &blink_c2)) {
+               anim = AnimID.BLINK;
+               blink_on = false;
+               blink_n = n;
+               var temp = new Animate(0);
+               timeout = Timeout.add (SPEED_BLINK,  temp.exec);
+               while (timeout!=0)
+                       Gtk.main_iteration();
+       }
+}
+
+bool on_button_press (Gtk.Widget w, Gdk.EventButton e)
+{
+       int x, y;
+       if (player_active) {
+               return false;
+       }
+
+       if (gameover && timeout == 0) {
+               blink_winner (2);
+       } else if (is_player_human () && timeout == 0) {
+               w.get_window().get_device_position (e.device, out x, out y, null);
+               game_process_move (Gfx.get_column (x));
+       }
+
+       return true;
+}
+
+void
+scorebox_update ()
+{
+       string s;
+
+       if (scorebox == null)
+               return;
+
+       if (get_n_human_players () == 1) {
+               if (p.level[PlayerID.PLAYER1] == Level.HUMAN) {
+                       label_score[PlayerID.PLAYER1].set_text(_("You:"));
+                       label_score[PlayerID.PLAYER2].set_text(_("Me:"));
+               } else {
+                       label_score[PlayerID.PLAYER2].set_text(_("You:"));
+                       label_score[PlayerID.PLAYER1].set_text(_("Me:"));
+               }
+       } else {
+               label_name[PlayerID.PLAYER1].set_text(theme_get_player(PlayerID.PLAYER1));
+               label_name[PlayerID.PLAYER2].set_text(theme_get_player(PlayerID.PLAYER2));
+       }
+
+       label_score[PlayerID.PLAYER1].set_text((string)score[PlayerID.PLAYER1]);
+       label_score[PlayerID.PLAYER2].set_text((string)score[PlayerID.PLAYER2]);
+       label_score[PlayerID.NOBODY].set_text((string)score[PlayerID.NOBODY]);
+
+}
+
+void on_settings_preferences (SimpleAction action, Variant? parameter)
+{
+       prefsbox_open ();
+}
+
+void
+on_game_hint (SimpleAction action, Variant? parameter)
+{
+       string s;
+       int c;
+
+       if (timeout != 0)
+               return;
+       if (gameover)
+               return;
+
+       hint_action.set_enabled(false);
+       undo_action.set_enabled(false);
+
+       set_status_message (_("I’m Thinking…"));
+
+       vstr[0] = vlevel[Level.STRONG];
+       c = playgame ((string)vstr) - 1;
+
+       column_moveto = c;
+       while (timeout != 0)
+               Gtk.main_iteration ();
+       anim = AnimID.HINT;
+       var temp = new Animate(0);
+       timeout = Timeout.add (SPEED_MOVE, temp.exec);
+
+       blink_tile (0, c, gboard[0, c], 6);
 
-    column_moveto = c;
-    anim = AnimID.MOVE;
-    //Timeout.add(SPEED_DROP, on_animate, c.to_pointer());
-    //timeout = g_timeout_add (SPEED_MOVE, (GSourceFunc) on_animate, GINT_TO_POINTER (c));
+       s = _("Hint: Column ")+ (c + 1).to_string();
+       set_status_message (s);
+       g_free (s);
+
+       if (moves <= 0 || (moves == 1 && is_player_human ()))
+               undo_action.set_enabled(false);
+       else
+               undo_action.set_enabled(true);
+}
+
+const GLib.ActionEntry app_entries[] = {
+       {"new-game", on_game_new, null, null, null},
+       {"undo-move", on_game_undo, null, null, null},
+       {"hint", on_game_hint, null, null, null},
+       {"scores", on_game_scores, null, null, null},
+       {"quit", on_game_exit, null, null, null},
+       {"preferences", on_settings_preferences, null, null, null},
+       {"help", on_help_contents, null, null, null},
+       {"about", on_help_about, null, null, null}
+};
+
+void
+create_app (GLib.Application app)
+{
+       Gtk.AspectFrame frame;
+       GLib.Menu app_menu, section;
+
+       Gtk.Builder builder;
+       Gtk.CssProvider css_provider;
+       //Error *error = NULL;
+
+       Gtk.Window.set_default_icon_name("four-in-a-row");
+
+       css_provider = new Gtk.CssProvider ();
+       try {
+               css_provider.load_from_data("GtkButtonBox{-GtkButtonBox-child-internal-pad-x:0;}\0");
+       } catch (Error error){
+               stderr.printf("Could not load UI: %s\n", error.message);
+               return;
+       }
+       StyleContext.add_provider_for_screen(Gdk.Screen.get_default(), css_provider, 
STYLE_PROVIDER_PRIORITY_APPLICATION);
+
+
+       builder = new Builder.from_file (Config.DATA_DIRECTORY + "/four-in-a-row.ui");
+
+       window = (Window) builder.get_object ("fiar-window");
+       window.application = application;
+       window.set_default_size(DEFAULT_WIDTH, DEFAULT_HEIGHT); // TODO save size & state
+
+       headerbar = (HeaderBar) builder.get_object ("headerbar");
+
+       application.add_action_entries(app_entries, application);
+       application.add_accelerator("<Primary>n", "app.new-game", null);
+       application.add_accelerator("<Primary>h", "app.hint", null);
+       application.add_accelerator("<Primary>z", "app.undo-move", null);
+       application.add_accelerator("<Primary>q", "app.quit", null);
+       application.add_accelerator("F1", "app.contents", null);
+
+       app_menu = new GLib.Menu();
+       section = new GLib.Menu();
+       app_menu.append_section(null, section);
+       section.append(_("_Scores"), "app.scores");
+       section.append(_("_Preferences"), "app.preferences");
+       section = new GLib.Menu();
+       app_menu.append_section(null, section);
+       section.append(_("_Help"), "app.help");
+       section.append(_("_About"), "app.about");
+       section.append(_("_Quit"), "app.quit");
+
+       new_game_action = (GLib.SimpleAction) application.lookup_action("new-game");
+       undo_action = (GLib.SimpleAction) application.lookup_action("undo-move");
+       hint_action = (GLib.SimpleAction) application.lookup_action("hint");
+
+       application.app_menu = app_menu;
+
+       frame = (Gtk.AspectFrame) builder.get_object("frame");
+
+       drawarea = new DrawingArea();
+       /* set a min size to avoid pathological behavior of gtk when scaling down */
+       drawarea.set_size_request (350, 350);
+       drawarea.halign = Align.FILL;
+       drawarea.valign = Align.FILL;
+       frame.add(drawarea);
+
+       drawarea.events = Gdk.EventMask.EXPOSURE_MASK | Gdk.EventMask.BUTTON_PRESS_MASK | 
Gdk.EventMask.BUTTON_RELEASE_MASK;
+       drawarea.configure_event.connect(on_drawarea_resize);
+       drawarea.draw.connect(on_drawarea_draw);
+       drawarea.button_press_event.connect(on_button_press);
+       drawarea.key_press_event.connect(on_key_press);
+
+       hint_action.set_enabled(false);
+       undo_action.set_enabled(false);
+}
+
+void on_dialog_close (Gtk.Widget w, int response_id)
+{
+       w.hide();
+}
+
+void
+prompt_player ()
+{
+       int players = get_n_human_players ();
+       bool human = is_player_human ();
+       string who;
+       string str;
+
+       hint_action.set_enabled(human && !gameover);
+
+       switch (players) {
+       case 0:
+               undo_action.set_enabled(false);
+               break;
+       case 1:
+               undo_action.set_enabled((human && moves >1) || (!human && gameover));
+               break;
+       case 2:
+               undo_action.set_enabled(moves > 0);
+               break;
+       }
+
+       if (gameover && winner == PlayerID.NOBODY) {
+               if (score[PlayerID.NOBODY] == 0)
+                       set_status_message (null);
+               else
+                       set_status_message (_("It’s a draw!"));
+               return;
+       }
+
+       switch (players) {
+       case 1:
+               if (human) {
+                       if (gameover)
+                               set_status_message (_("You win!"));
+                       else
+                               set_status_message (_("Your Turn"));
+               } else {
+                       if (gameover)
+                               set_status_message (_("I win!"));
+                       else
+                               set_status_message (_("I’m Thinking…"));
+               }
+               break;
+       case 2:
+       case 0:
+
+               if (gameover) {
+                       who = player == PLAYER1 ? theme_get_player_win (PlayerID.PLAYER1)
+                               : theme_get_player_win (PlayerID.PLAYER2);
+                       str =  _(who);
+               } else if (player_active) {
+                       set_status_message (_("Your Turn"));
+                       return;
+               } else {
+                       who = player == PLAYER1 ? theme_get_player_turn (PlayerID.PLAYER1)
+                               : theme_get_player_turn (PlayerID.PLAYER2);
+                       str =  _(who);
+               }
+
+               set_status_message (str);
+               break;
+       }
 }
diff --git a/src/prefs.vala b/src/prefs.vala
index dd5f96d..5a279aa 100644
--- a/src/prefs.vala
+++ b/src/prefs.vala
@@ -1,6 +1,14 @@
 //public const int DEFAULT_THEME_ID = 0;
 //extern int n_themes;
-extern Settings settings;
+
+struct Prefs {
+  bool do_sound;
+  int theme_id;
+  Level level[2];
+  int keypress[3];
+}
+
+Settings settings;
 Gtk.Dialog? prefsbox = null;
 Gtk.ComboBox combobox;
 Gtk.ComboBoxText combobox_theme;
diff --git a/src/temp.vapi b/src/temp.vapi
index df7c71a..a30478b 100644
--- a/src/temp.vapi
+++ b/src/temp.vapi
@@ -1,97 +1,20 @@
-[CCode (cname = "Prefs", cheader_filename="prefs.h")]
-struct Prefs {
-  bool do_sound;
-  int theme_id;
-  Level level[2];
-  int keypress[3];
-}
-
-[CCode (cname = "Theme", cheader_filename="theme.h")]
-struct Theme {
-    public string title;
-    public string fname_tileset;
-    public string fname_bground;
-    public string grid_color;
-    public string player1;
-    public string player2;
-    public string player1_win;
-    public string player2_win;
-    public string player1_turn;
-    public string player2_turn;
-}
-
-[CCode (cname = "AnimID", cprefix = "ANIM_", cheader_filename="main.h")]
-public enum AnimID {
-    NONE,
-    MOVE,
-    DROP,
-    BLINK,
-    HINT
-}
-
-[CCode (cname = "PlayerID", cprefix = "", cheader_filename="main.h")]
-public enum PlayerID {
-    PLAYER1,
-  PLAYER2,
-  NOBODY
-}
-
-
-[CCode (cname = "LevelID", cprefix = "LEVEL_", cheader_filename="main.h")]
-public enum Level {
-   HUMAN,
-  WEAK,
-  MEDIUM,
-  STRONG
-}
+[CCode (cprefix = "", cheader_filename = "config.h")]
+namespace Config {
+       [CCode (cname = "GETTEXT_PACKAGE")]
+       public const string GETTEXT_PACKAGE;
 
+       [CCode (cname = "DATA_DIRECTORY")]
+       public const string DATA_DIRECTORY;
 
-[CCode (cname = "int", cprefix="TILE_", has_type_id = false, cheader_filename="main.h")]
-public enum Tile {
-    PLAYER1,
-    PLAYER2,
-    CLEAR,
-    CLEAR_CURSOR,
-    PLAYER1_CURSOR,
-    PLAYER2_CURSOR,
-}
+       [CCode (cname = "APPNAME_LONG")]
+       public const string APPNAME_LONG;
 
-[CCode (cname = "MoveID", cprefix = "MOVE_", cheader_filename="main.h")]
-public enum Move {
-  LEFT,
-  RIGHT,
-  DROP
-}
+       [CCode (cname = "VERSION")]
+       public const string VERSION;
 
-[CCode (cname = "SoundID", cprefix = "SOUND_", cheader_filename="main.h")]
-public enum SoundID{
-  DROP,
-  I_WIN,
-  YOU_WIN,
-  PLAYER_WIN,
-  DRAWN_GAME,
-  COLUMN_FULL
-}
-
-void game_reset ();
-//void process_move(int c);
-void gfx_refresh_pixmaps();
-bool gfx_load_pixmaps();
-void gfx_paint_tile(Cairo.Context cr, int r, int c);
-//void gfx_draw_grid(Cairo.Context c);
-//static void gfx_draw_all ();
-void gfx_free ();
-void scorebox_update ();       /* update visible player descriptions */
-void prompt_player ();
-void on_dialog_close(int response_id);
-bool on_animate();
-//static void settings_changed_cb (string key);
-void play_sound(SoundID id);
+       [CCode (cname = "SOUND_DIRECTORY")]
+       public const string SOUND_DIRECTORY;
 
-[CCode (cprefix = "", cheader_filename = "config.h")]
-namespace Config {
-    [CCode (cname = "GETTEXT_PACKAGE")]
-    public const string GETTEXT_PACKAGE;
+       [CCode (cname = "LOCALEDIR")]
+       public const string LOCALEDIR;
 }
-//[CCode(cname="GETTEXT_PACKAGE", cheader_filename="config.h,glib/gi18n-lib.h")]
-//extern const string GETTEXT_PACKAGE;
diff --git a/src/theme.vala b/src/theme.vala
index 4193f74..38588f6 100644
--- a/src/theme.vala
+++ b/src/theme.vala
@@ -1,20 +1,33 @@
+struct Theme {
+       public string title;
+       public string fname_tileset;
+       public string fname_bground;
+       public string grid_color;
+       public string player1;
+       public string player2;
+       public string player1_win;
+       public string player2_win;
+       public string player1_turn;
+       public string player2_turn;
+}
+
 //extern Theme theme[];
 const string random_shit = Config.GETTEXT_PACKAGE;
 
 string theme_get_title (int id) {
-   return theme[id].title;
+       return theme[id].title;
 }
 
 string theme_get_player_turn (PlayerID who) {
-  if (who == PlayerID.PLAYER1)
-    return theme[p.theme_id].player1_turn;
-  return theme[p.theme_id].player2_turn;
+       if (who == PlayerID.PLAYER1)
+               return theme[p.theme_id].player1_turn;
+       return theme[p.theme_id].player2_turn;
 }
 
 string theme_get_player_win (PlayerID who) {
-  if (who == PlayerID.PLAYER1)
-    return theme[p.theme_id].player1_win;
-  return theme[p.theme_id].player2_win;
+       if (who == PlayerID.PLAYER1)
+               return theme[p.theme_id].player1_win;
+       return theme[p.theme_id].player2_win;
 }
 
 string theme_get_player (PlayerID who) {



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