[five-or-more/vala-port] start the port to vala
- From: Thomas Hindoe Paaboel Andersen <thomashpa src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [five-or-more/vala-port] start the port to vala
- Date: Sat, 3 Nov 2012 01:35:13 +0000 (UTC)
commit 312e70c8384710a0fa5a9a3324eafd233e94eda6
Author: Thomas Hindoe Paaboel Andersen <phomes gmail com>
Date: Sat Nov 3 02:34:51 2012 +0100
start the port to vala
configure.ac | 11 +
data/five-or-more.ui | 5 +-
src/Makefile.am | 32 +-
src/application.vala | 157 ++++
src/board.vala | 314 +++++++
src/config.vapi | 8 +
src/field.vala | 32 +
src/five-or-more.gresource.xml.in | 7 +
src/glines.c | 1676 -------------------------------------
src/glines.h | 47 -
src/main.vala | 41 +
src/piece.vala | 13 +
src/preview-queue.vala | 31 +
src/view-2d.vala | 144 ++++
src/view-cli.vala | 146 ++++
15 files changed, 934 insertions(+), 1730 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 0d61494..9626ce7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -5,6 +5,7 @@ AM_MAINTAINER_MODE
GNOME_MAINTAINER_MODE_DEFINES
AC_CONFIG_HEADERS([config.h])
+AM_PROG_VALAC([0.16.0])
AM_PROG_CC_C_O
GLIB_GSETTINGS
@@ -59,14 +60,23 @@ dnl ###########################################################################
GTK_REQUIRED=3.4.0
RSVG_REQUIRED=2.32.0
+GEE_REQUIRED=0.6.0
PKG_CHECK_MODULES(FIVE_OR_MORE, [
gmodule-2.0
gtk+-3.0 >= $GTK_REQUIRED
librsvg-2.0 >= $RSVG_REQUIRED
+ gee-1.0 >= $GEE_REQUIRED
])
dnl ###########################################################################
+dnl GResources
+dnl ###########################################################################
+
+GLIB_COMPILE_RESOURCES=`$PKG_CONFIG --variable glib_compile_resources gio-2.0`
+AC_SUBST(GLIB_COMPILE_RESOURCES)
+
+dnl ###########################################################################
dnl Internationalization
dnl ###########################################################################
@@ -92,4 +102,5 @@ data/icons/Makefile
data/five-or-more.desktop.in
help/Makefile
src/Makefile
+src/five-or-more.gresource.xml
])
diff --git a/data/five-or-more.ui b/data/five-or-more.ui
index 859169d..426b771 100644
--- a/data/five-or-more.ui
+++ b/data/five-or-more.ui
@@ -2,7 +2,7 @@
<interface>
<!-- interface-requires gtk+ 3.0 -->
<object class="GtkAccelGroup" id="accelgroup"/>
- <object class="GtkWindow" id="glines_window">
+ <object class="GtkApplicationWindow" id="glines_window">
<property name="can_focus">False</property>
<property name="title" translatable="yes">Five or more</property>
<property name="default_width">320</property>
@@ -11,6 +11,7 @@
<accel-groups>
<group name="accelgroup"/>
</accel-groups>
+ <signal name="delete-event" handler="game_quit_callback" swapped="no"/>
<child>
<object class="GtkBox" id="vbox">
<property name="visible">True</property>
@@ -18,7 +19,7 @@
<property name="orientation">vertical</property>
<child>
<object class="GtkMenuBar" id="menubar">
- <property name="visible">True</property>
+ <property name="visible">False</property>
<property name="can_focus">False</property>
<child>
<object class="GtkMenuItem" id="game_menu_item">
diff --git a/src/Makefile.am b/src/Makefile.am
index 169e7b3..58f7cc1 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,5 +1,7 @@
bin_PROGRAMS = five-or-more
+BUILT_SOURCES = five-or-more-resources.c
+
five_or_more_SOURCES = \
games-file-list.c \
games-file-list.h \
@@ -17,12 +19,20 @@ five_or_more_SOURCES = \
games-scores-backend.h \
games-stock.c \
games-stock.h \
- glines.c \
- glines.h
+ config.vapi \
+ main.vala \
+ application.vala \
+ board.vala \
+ field.vala \
+ piece.vala \
+ preview-queue.vala \
+ view-2d.vala \
+ view-cli.vala \
+ $(BUILT_SOURCES)
if ENABLE_SETGID
-five_or_more_SOURCES += \
- games-setgid-io.c \
+five_or_more_SOURCES += \
+ games-setgid-io.c \
games-setgid-io.h
endif # ENABLE_SETGID
@@ -31,8 +41,9 @@ five_or_more_CPPFLAGS = \
$(AM_CPPFLAGS)
five_or_more_CFLAGS = \
- -DDATA_DIRECTORY=\"$(datadir)/five-or-more\" \
-DLOCALEDIR=\"$(datadir)/locale\" \
+ -DGETTEXT_PACKAGE=\"$(GETTEXT_PACKAGE)\" \
+ -DDATA_DIRECTORY=\"$(datadir)/five-or-more\" \
-DICON_THEME_DIRECTORY="\"$(datadir)/icons\"" \
-DSCORESDIR="\"$(scoredir)\"" \
$(FIVE_OR_MORE_CFLAGS)
@@ -41,6 +52,17 @@ five_or_more_LDADD = \
$(FIVE_OR_MORE_LIBS) \
-lm
+five_or_more_VALAFLAGS = \
+ --pkg posix \
+ --pkg gtk+-3.0 \
+ --pkg gee-1.0
+
+five-or-more-resources.c: five-or-more.gresource.xml $(shell $(GLIB_COMPILE_RESOURCES) --generate-dependencies five-or-more.gresource.xml)
+ $(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) --target=$@ --sourcedir=$(srcdir) --generate-source five-or-more.gresource.xml
+
+EXTRA_DIST = \
+ five-or-more.gresource.xml
+
install-exec-hook:
-if test "$(setgid)" = "true"; then \
chgrp $(scores_group) $(DESTDIR)$(bindir)/five-or-more && chmod 2555 $(DESTDIR)$(bindir)/five-or-more ;\
diff --git a/src/application.vala b/src/application.vala
new file mode 100644
index 0000000..f109bc1
--- /dev/null
+++ b/src/application.vala
@@ -0,0 +1,157 @@
+namespace FiveOrMore
+{
+ public class FiveOrMoreApp : Gtk.Application
+ {
+ private Gtk.ApplicationWindow window;
+ private Settings settings;
+ private Gtk.Builder builder;
+ //private GnomeGamesSupport.Scores highscores;
+
+ private Gtk.Dialog preferences_dialog;
+
+ private const GLib.ActionEntry[] action_entries =
+ {
+ { "new-game", new_game_cb },
+ { "scores", scores_cb },
+ { "preferences", preferences_cb },
+ { "help", help_cb },
+ { "about", about_cb },
+ { "quit", quit_cb }
+ };
+
+ //private const GnomeGamesSupport.ScoresCategory scorecats[] =
+ //{
+ // { "Small", NC_("board size", "Small") },
+ // { "Medium", NC_("board size", "Medium") },
+ // { "Large", NC_("board size", "Large") }
+ //};
+
+ private const string[] authors = { "Thomas Andersen <phomes gmail com>", "Robert Szokovacs <szo appaloosacorp hu>", "Szabolcs B\xc3\xa1n <shooby gnome hu>" };
+ //private const string[] documenters = { "Tiffany Antopolski", "Lanka Rathnayaka" };
+
+ private GlinesBoard board = new GlinesBoard(10, 10, 5, 3);
+
+ public FiveOrMoreApp ()
+ {
+ Object (application_id: "org.gnome.five-or-more", flags: ApplicationFlags.FLAGS_NONE);
+
+ add_action_entries (action_entries, this);
+ }
+
+ protected override void startup ()
+ {
+ base.startup ();
+
+ settings = new Settings ("org.gnome.five-or-more");
+
+ //highscores = new GnomeGamesSupport.Scores ("glines", scorecats, "board size", null, 0, GnomeGamesSupport.ScoreStyle.PLAIN_DESCENDING);
+
+ builder = new Gtk.Builder ();
+ try
+ {
+ builder.add_from_resource ("/org/gnome/five-or-more/ui/glines.ui");
+ builder.add_from_resource ("/org/gnome/five-or-more/ui/glines-preferences.ui");
+ }
+ catch (GLib.Error e)
+ {
+ GLib.warning ("Could not load UI: %s", e.message);
+ }
+
+ var menu = new Menu ();
+
+ var section = new Menu ();
+ menu.append_section (null, section);
+ section.append (_("_New Game"), "app.new-game");
+ section.append (_("_Scores"), "app.scores");
+ section.append (_("_Preferences"), "app.preferences");
+
+ section = new Menu ();
+ menu.append_section (null, section);
+ section.append (_("_Help"), "app.help");
+ section.append (_("_About"), "app.about");
+
+ section = new Menu ();
+ menu.append_section (null, section);
+ section.append (_("_Quit"), "app.quit");
+ set_app_menu (menu);
+
+ var box = (Gtk.Box) builder.get_object ("vbox");
+ var view2d = new View2D (board);
+ box.add (view2d);
+ view2d.show ();
+
+ window = (Gtk.ApplicationWindow) builder.get_object ("glines_window");
+ add_window (window);
+ }
+
+ public override void activate ()
+ {
+ //var v = new ViewCli (board);
+ //v.run();
+
+ window.present ();
+ }
+
+ private void new_game_cb ()
+ {
+ stdout.printf ("new game\n");
+ }
+
+ private void scores_cb ()
+ {
+ stdout.printf ("FIXME: Showing scores does not currently work\n");
+
+ //var scores_dialog = new GnomeGamesSupport.ScoresDialog (window, highscores, _("GNOME Five or More"));
+ //scores_dialog.set_category_description (_("_Board size:"));
+ //scores_dialog.run ();
+ //scores_dialog.destroy ();
+ }
+
+ private void preferences_cb ()
+ {
+ stdout.printf ("preferences\n");
+ if (preferences_dialog == null)
+ preferences_dialog = (Gtk.Dialog) builder.get_object ("preferences_dialog");
+
+ preferences_dialog.run();
+ preferences_dialog.destroy ();
+ }
+
+ private void help_cb ()
+ {
+ try
+ {
+ Gtk.show_uri (window.get_screen (), "ghelp:five-or-more", Gtk.get_current_event_time ());
+ }
+ catch (GLib.Error e)
+ {
+ GLib.warning ("Unable to open help: %s", e.message);
+ }
+ }
+
+ private void about_cb ()
+ {
+ Gtk.show_about_dialog (window,
+ "program-name", _("Five or More"),
+ "logo-icon-name", "five-or-more",
+ "version", Config.VERSION,
+ "comments", _("GNOME port of the once-popular Color Lines game.\n\nFive or More is a part of GNOME Games."),
+ "copyright", "Copyright \xc2\xa9 1997-2012 Free Software Foundation, Inc.",
+ "license-type", Gtk.License.GPL_3_0,
+ "wrap-license", false,
+ "authors", authors,
+ //FIXME: "documenters", documenters,
+ "translator-credits", _("translator-credits"),
+ "website", "http://www.gnome.org/projects/gnome-games/",
+ "website-label", _("GNOME Games web site"),
+ null);
+ }
+
+ private void quit_cb ()
+ {
+ window.destroy ();
+ }
+ }
+}
+
+
diff --git a/src/board.vala b/src/board.vala
new file mode 100644
index 0000000..d859476
--- /dev/null
+++ b/src/board.vala
@@ -0,0 +1,314 @@
+using Gee;
+
+namespace FiveOrMore
+{
+ public class GlinesBoard
+ {
+ public int cols { get; private set; }
+ public int rows { get; private set; }
+
+ public GlinesField[,] fields { get; private set; }
+ public GlinesField active_field = null;
+
+ public GlinesPreviewQueue preview_queue;
+
+ public bool show_cursor { get; set; }
+ private int _cursor_x;
+ public int cursor_x
+ {
+ get { return this._cursor_x; }
+ set { this._cursor_x = this.clamp(0, value, this.cols - 1); }
+ }
+ private int _cursor_Y;
+ public int cursor_y
+ {
+ get { return this._cursor_Y; }
+ set { this._cursor_Y = this.clamp(0, value, this.rows - 1); }
+ }
+
+ public bool move_in_progress { get; set; }
+
+ public signal void changed ();
+ public signal void move (ArrayList<GlinesField> path);
+ public signal void info (string text);
+ public signal void gameover ();
+
+ public GlinesBoard(int cols, int rows, int preview_queue_size, int n_types)
+ {
+ this.cols = cols;
+ this.rows = rows;
+
+ preview_queue = new GlinesPreviewQueue(preview_queue_size, n_types);
+
+ this.fields = new GlinesField[this.cols, this.rows];
+
+ for (int x = 0; x < this.cols; x++)
+ {
+ for (int y = 0; y < this.rows; y++)
+ {
+ this.fields[x, y] = new GlinesField();
+ }
+ }
+
+ //Connect the neigbouring fields
+ for (int x = 0; x < this.cols; x++)
+ {
+ for (int y = 0; y < this.rows; y++)
+ {
+ var field = this.fields[x, y];
+ if (x > 0)
+ field.neigbour_west = this.fields[x - 1, y];
+ if (x < this.cols - 1)
+ field.neigbour_east = this.fields[x + 1, y];
+ if (y > 0)
+ field.neigbour_north = this.fields[x, y - 1];
+ if (y < this.rows - 1)
+ field.neigbour_south = this.fields[x, y + 1];
+ }
+ }
+
+ this.move_preview_queue_to_board();
+ }
+
+ public void select_field(int x, int y)
+ {
+ if (this.move_in_progress)
+ return;
+
+ var clicked_field = this.fields[x, y];
+
+ if (this.active_field == null && !clicked_field.has_piece)
+ {
+ info("No piece to select");
+ }
+ else if (this.active_field == null && clicked_field.has_piece)
+ {
+ //select a field
+ clicked_field.active = true;
+ this.active_field = clicked_field;
+ info("Field selected");
+ }
+ else if (this.active_field == clicked_field)
+ {
+ //deselect the active field
+ clicked_field.active = false;
+ this.active_field = null;
+ info("Field deselected");
+ }
+ else
+ {
+ //attempt to move the piece
+ if (find_route(this.active_field, clicked_field))
+ {
+ info("moving");
+
+ this.move_in_progress = true;
+
+ // Let the listener do the animation.
+ this.move(this.backtrack_route(clicked_field));
+
+ //actually move the piece
+ clicked_field.piece = this.active_field.piece;
+ this.active_field.piece = null;
+
+ this.active_field.active = false;
+ this.active_field = null;
+
+ move_completed();
+ }
+ else
+ {
+ info("no route");
+ }
+ }
+
+ this.changed();
+ }
+
+ private void move_completed()
+ {
+ //remove lines to make space for adding pieces
+ this.remove_lines();
+
+ this.move_preview_queue_to_board();
+
+ //remove lines again. New once could be formed when adding the new pieces
+ this.remove_lines();
+
+ if (this.check_for_game_over())
+ {
+ gameover();
+ }
+
+ this.move_in_progress = false;
+ }
+
+ private void remove_lines()
+ {
+ //todo: check for lines to remove
+ // + add scoring
+ }
+
+ private void move_preview_queue_to_board()
+ {
+ foreach (var piece in preview_queue.pieces)
+ {
+ this.add_piece_at_random_location(piece);
+ }
+
+ preview_queue.refill();
+ }
+
+ private void add_piece_at_random_location(GlinesPiece piece)
+ {
+ var vert = new ArrayList<int>();
+ var hori = new ArrayList<int>();
+
+ for (int i = 0; i < this.cols; i++)
+ vert.add(i);
+ for (int i = 0; i < this.rows; i++)
+ hori.add(i);
+
+ shuffle(hori);
+ shuffle(vert);
+
+ foreach(int x in vert)
+ {
+ foreach(int y in hori)
+ {
+ if(!fields[x,y].has_piece)
+ {
+ fields[x, y].piece = piece;
+ return;
+ }
+ }
+ }
+ }
+
+ private void shuffle(ArrayList<int> list)
+ {
+ for (int from = list.size - 1; from > 0; from--)
+ {
+ int to = Random.int_range(0, from);
+ int temp = list[to];
+ list[to] = list[from];
+ list[from] = temp;
+ }
+ }
+
+ private bool check_for_game_over()
+ {
+ for (int x = 0; x < this.cols; x++)
+ for (int y = 0; y < this.rows; y++)
+ if (!this.fields[x, y].has_piece)
+ return false;
+
+ return true;
+ }
+
+ private void reset_path_search()
+ {
+ for (int x = 0; x < this.cols; x++)
+ for (int y = 0; y < this.rows; y++)
+ fields[x, y].path_search = null;
+ }
+
+ //After the search has been performed a route will (if possible)
+ //exist from the target to the origin. Use the Pathsearch to follow
+ //the path.
+ public bool find_route(GlinesField from, GlinesField target)
+ {
+ reset_path_search();
+
+ var check_now = new ArrayList<GlinesField> ();
+ check_now.add (from);
+
+ while (check_now.size != 0)
+ {
+ var check_next = new ArrayList<GlinesField>();
+
+ foreach (var current in check_now)
+ {
+ foreach (var neighbour in this.non_searched_neighbours(current))
+ {
+ if (neighbour == from)
+ continue;
+
+ neighbour.path_search = current;
+ check_next.add(neighbour);
+
+ // We have reached the target so there is no use in continuing
+ if (neighbour == target)
+ return true;
+ }
+ }
+
+ check_now = check_next;
+ }
+
+ return false;
+ }
+
+ private ArrayList<GlinesField> non_searched_neighbours(GlinesField field)
+ {
+ var neighbours = new ArrayList<GlinesField>();
+
+ if (field.neigbour_north != null &&
+ !field.neigbour_north.has_piece &&
+ field.neigbour_north.path_search == null)
+ neighbours.add(field.neigbour_north);
+
+ if (field.neigbour_west != null &&
+ !field.neigbour_west.has_piece &&
+ field.neigbour_west.path_search == null)
+ neighbours.add(field.neigbour_west);
+
+ if (field.neigbour_south != null &&
+ !field.neigbour_south.has_piece &&
+ field.neigbour_south.path_search == null)
+ neighbours.add(field.neigbour_south);
+
+ if (field.neigbour_east != null &&
+ !field.neigbour_east.has_piece &&
+ field.neigbour_east.path_search == null)
+ neighbours.add(field.neigbour_east);
+
+ return neighbours;
+ }
+
+ public ArrayList<GlinesField> backtrack_route(GlinesField from)
+ {
+ var route = new ArrayList<GlinesField> ();
+ route.add (from);
+
+ //the routes origin may have more than one
+ while (route[route.size -1 ].path_search != null)
+ route.add(route[route.size -1 ].path_search);
+
+ return route;
+ }
+
+ public void place_cursor(int x, int y)
+ {
+ this.cursor_x = x;
+ this.cursor_y = y;
+
+ this.changed();
+ }
+
+ public void move_cursor(int x, int y)
+ {
+ this.place_cursor(this.cursor_x + x, this.cursor_y + y);
+ }
+
+ private int clamp(int min, int val, int max)
+ {
+ if (val < min)
+ return min;
+ if (val > max)
+ return max;
+ return val;
+ }
+ }
+}
+
diff --git a/src/config.vapi b/src/config.vapi
new file mode 100644
index 0000000..6908fe6
--- /dev/null
+++ b/src/config.vapi
@@ -0,0 +1,8 @@
+[CCode (cprefix = "", lower_case_cprefix = "", cheader_filename = "config.h")]
+namespace Config
+{
+ public const string DATA_DIRECTORY;
+ public const string LOCALEDIR;
+ public const string GETTEXT_PACKAGE;
+ public const string VERSION;
+}
diff --git a/src/field.vala b/src/field.vala
new file mode 100644
index 0000000..f5c2118
--- /dev/null
+++ b/src/field.vala
@@ -0,0 +1,32 @@
+namespace FiveOrMore
+{
+ public class GlinesField
+ {
+ public GlinesField()
+ {
+ this.piece = null;
+
+ this.neigbour_north = null;
+ this.neigbour_south = null;
+ this.neigbour_east = null;
+ this.neigbour_west = null;
+ this.path_search = null;
+ }
+
+ public GlinesPiece piece { get; set; }
+ public bool active { get; set; }
+
+ public GlinesField neigbour_north { get; set; }
+ public GlinesField neigbour_south { get; set; }
+ public GlinesField neigbour_east { get; set; }
+ public GlinesField neigbour_west { get; set; }
+
+ public GlinesField path_search { get; set; }
+
+ public bool has_piece
+ {
+ get { return this.piece != null; }
+ }
+ }
+}
+
diff --git a/src/five-or-more.gresource.xml.in b/src/five-or-more.gresource.xml.in
new file mode 100644
index 0000000..8ec7f1f
--- /dev/null
+++ b/src/five-or-more.gresource.xml.in
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+ <gresource prefix="/org/gnome/five-or-more/ui">
+ <file alias="five-or-more.ui" preprocess="xml-stripblanks">@top_srcdir@/data/five-or-more.ui</file>
+ <file alias="five-or-more-preferences.ui" preprocess="xml-stripblanks">@top_srcdir@/data/five-or-more-preferences.ui</file>
+ </gresource>
+</gresources>
diff --git a/src/main.vala b/src/main.vala
new file mode 100644
index 0000000..34fcdbd
--- /dev/null
+++ b/src/main.vala
@@ -0,0 +1,41 @@
+private static bool show_version;
+
+private static const OptionEntry[] options =
+{
+ { "version", 'v', 0, OptionArg.NONE, ref show_version,
+ /* Help string for command line --version flag */
+ N_("Show release version"), null},
+ { null }
+};
+
+public static int main (string[] args)
+{
+ Gtk.init (ref args);
+
+ var c = new OptionContext (/* Arguments and description for --help text */
+ _("[FILE] - Play Glines"));
+ c.add_main_entries (options, Config.GETTEXT_PACKAGE);
+ c.add_group (Gtk.get_option_group (true));
+ try
+ {
+ c.parse (ref args);
+ }
+ catch (Error e)
+ {
+ stderr.printf ("%s\n", e.message);
+ stderr.printf (/* Text printed out when an unknown command-line argument provided */
+ _("Run '%s --help' to see a full list of available command line options."), args[0]);
+ stderr.printf ("\n");
+ return Posix.EXIT_FAILURE;
+ }
+ if (show_version)
+ {
+ /* Note, not translated so can be easily parsed */
+ stderr.printf ("glines %s\n", Config.VERSION);
+ return Posix.EXIT_SUCCESS;
+ }
+
+ var app = new FiveOrMore.FiveOrMoreApp ();
+ return app.run ();
+}
+
diff --git a/src/piece.vala b/src/piece.vala
new file mode 100644
index 0000000..e8bf445
--- /dev/null
+++ b/src/piece.vala
@@ -0,0 +1,13 @@
+namespace FiveOrMore
+{
+ public class GlinesPiece
+ {
+ public int id { get; private set; }
+
+ public GlinesPiece(int id)
+ {
+ this.id = id;
+ }
+ }
+}
+
diff --git a/src/preview-queue.vala b/src/preview-queue.vala
new file mode 100644
index 0000000..d4e58e6
--- /dev/null
+++ b/src/preview-queue.vala
@@ -0,0 +1,31 @@
+using Gee;
+
+namespace FiveOrMore
+{
+ public class GlinesPreviewQueue
+ {
+ public ArrayList<GlinesPiece> pieces { get; set; }
+ private int size { get; set; }
+ private int types { get; set; }
+
+ public GlinesPreviewQueue(int size, int types)
+ {
+ this.pieces = new ArrayList<GlinesPiece>();
+ this.size = size;
+ this.types = types;
+ this.refill();
+ }
+
+ public void refill()
+ {
+ this.pieces.clear();
+
+ for (int i = 0; i < this.size; i++)
+ {
+ int id = Random.int_range(0, types);
+ this.pieces.add(new GlinesPiece(id));
+ }
+ }
+ }
+}
+
diff --git a/src/view-2d.vala b/src/view-2d.vala
new file mode 100644
index 0000000..6e8a721
--- /dev/null
+++ b/src/view-2d.vala
@@ -0,0 +1,144 @@
+using Cairo;
+using Gdk;
+using Gtk;
+
+namespace FiveOrMore
+{
+ public class View2D : DrawingArea
+ {
+ public GlinesBoard board { get; private set; }
+ public double line_width { get; set; }
+
+ public View2D(GlinesBoard board)
+ {
+ this.board = board;
+ this.line_width = 1.0;
+
+ this.vexpand = true;
+ this.hexpand = true;
+ this.add_events (Gdk.EventMask.BUTTON_PRESS_MASK | Gdk.EventMask.BUTTON_RELEASE_MASK | Gdk.EventMask.KEY_PRESS_MASK);
+
+ this.board.changed.connect ((o) => this.queue_draw());
+ //TODO: drop this later:
+ this.board.info.connect ((o, info) => stdout.printf(info + "\n"));
+ }
+
+
+ public override bool draw(Context ctx)
+ {
+ int w = this.get_allocated_width();
+ int h = this.get_allocated_height();
+
+ double boxsize_h = (w - (1 + board.rows) * line_width) / board.rows;
+ double boxsize_v = (h - (1 + board.cols) * line_width) / board.cols;
+
+ //Draw the backgrounds first
+ for (int i = 0; i < board.cols; i++)
+ for (int j = 0; j < board.rows; j++)
+ this.draw_field(this, ctx, j, i);
+
+ ctx.set_source_rgb(52, 95, 108);
+ ctx.set_line_width(line_width);
+
+ for (int i = 0; i < board.rows; i++)
+ {
+ ctx.move_to(0.5 + i * (boxsize_h + line_width), 0.5);
+ ctx.line_to(0.5 + i * (boxsize_h + line_width), 0.5 + h);
+ }
+
+ for (int i = 0; i < board.cols; i++)
+ {
+ ctx.move_to(0.5 + 0, 0.5 + i * (boxsize_v + line_width));
+ ctx.line_to(0.5 + w, 0.5 + i * (boxsize_v + line_width));
+ }
+
+ ctx.rectangle(0.5, 0.5, w - 0.5, h - 0.5);
+ ctx.stroke();
+
+ /* Cursor */
+ if (board.show_cursor)
+ {
+ ctx.set_source_rgb(255, 0, 0);
+ ctx.set_line_width(line_width);
+
+ ctx.rectangle(board.cursor_x * (boxsize_h + line_width) + 1.5, board.cursor_y * (boxsize_v + line_width) + 1.5, (boxsize_h + line_width) - 2.5, (boxsize_v + line_width) - 2.5);
+ ctx.stroke();
+ }
+
+ return true;
+ }
+
+ private void draw_field(Widget da, Context ctx, int x, int y)
+ {
+ int w = da.get_allocated_width();
+ int h = da.get_allocated_height();
+
+ double boxsizeH = (w - (1 + board.rows) * line_width) / board.rows;
+ double boxsizeV = (h - (1 + board.cols) * line_width) / board.cols;
+
+ var field = board.fields[x, y];
+
+ ctx.set_source_rgb(50, 50, 50);
+
+ ctx.rectangle(x * (boxsizeH + line_width) + 1.5, y * (boxsizeV + line_width) + 1.5, (boxsizeH + line_width) - 2.5, (boxsizeV + line_width) - 2.5);
+ ctx.fill();
+
+ if (field.piece != null)
+ {
+ this.draw_piece(da, ctx, field.piece, x, y);
+ }
+ }
+
+ private void draw_piece(Widget da, Context ctx, GlinesPiece p, int x, int y)
+ {
+ int w = da.get_allocated_width();
+ int h = da.get_allocated_height();
+
+ double boxsizeH = (w - (1 + board.rows) * line_width) / board.rows;
+ double boxsizeV = (h - (1 + board.cols) * line_width) / board.cols;
+
+ //TODO: look up surfaces instead. This is just for debug:
+ if (p.id == 0)
+ ctx.set_source_rgb(255, 0, 0);
+ else if (p.id == 1)
+ ctx.set_source_rgb(0, 255, 0);
+ else if (p.id == 2)
+ ctx.set_source_rgb(0, 0, 255);
+ else
+ ctx.set_source_rgb(0, 0, 0);
+
+
+ ctx.rectangle(x * (boxsizeH + line_width) + 1.5, y * (boxsizeV + line_width) + 1.5, (boxsizeH + line_width) - 2.5, (boxsizeV + line_width) - 2.5);
+ ctx.fill();
+ }
+
+ public override bool key_press_event (EventKey e)
+ {
+ var key = e.keyval;
+
+ if (key == Gdk.Key.Up) this.board.cursor_y--;
+ if (key == Gdk.Key.Down) this.board.cursor_y++;
+ if (key == Gdk.Key.Left) this.board.cursor_x--;
+ if (key == Gdk.Key.Right) this.board.cursor_x++;
+
+ if (key == Gdk.Key.space) board.select_field(board.cursor_x, board.cursor_y);
+
+ return true;
+ }
+
+ public override bool button_press_event (EventButton e)
+ {
+ double boxsize_x = this.get_allocated_width() / (board.rows * 1.0);
+ int x = (int)(e.x / boxsize_x);
+
+ double boxsize_y = this.get_allocated_height() / (board.cols * 1.0);
+ int y = (int)(e.y / boxsize_y);
+
+ board.place_cursor(x, y);
+ board.select_field(x, y);
+
+ return false;
+ }
+ }
+}
+
diff --git a/src/view-cli.vala b/src/view-cli.vala
new file mode 100644
index 0000000..03b52cb
--- /dev/null
+++ b/src/view-cli.vala
@@ -0,0 +1,146 @@
+using Gee;
+
+namespace FiveOrMore
+{
+ class ViewCli
+ {
+ private GlinesBoard board;
+
+ private bool gameover = false;
+ private string message = "";
+ private char[] id_to_char_symbol = { 'a', 'b', 'c', 'd', 'e' };
+
+ public ViewCli(GlinesBoard board)
+ {
+ this.board = board;
+ board.show_cursor = true;
+ board.place_cursor(5,5);
+
+ board.changed.connect ((o) => this.print(null));
+ board.move.connect ((o, path) => this.animate_move(path));
+ board.info.connect ((o, info) => message = info);
+ board.gameover.connect ((o) => this.gameover = true);
+
+ this.print(null);
+ }
+
+ public void run()
+ {
+ while (!gameover)
+ {
+ var c = stdin.getc();
+
+ if (c == 49) //southwest
+ board.move_cursor(-1, 1);
+
+ if (c == 50) //south
+ board.move_cursor(0, 1);
+
+ if (c == 51) //southeast
+ board.move_cursor(1, 1);
+
+ if (c == 52) //west
+ board.move_cursor(-1, 0);
+
+ if (c == 54) //east
+ board.move_cursor(1, 0);
+
+ if (c == 55) //northwest
+ board.move_cursor(-1, -1);
+
+ if (c == 56) //north
+ board.move_cursor(0, -1);
+
+ if (c == 57) //northeast
+ board.move_cursor(1, -1);
+
+ if (c == 53) //click
+ board.select_field(board.cursor_x, board.cursor_y);
+ }
+
+ stdout.printf("Game over.\n");
+ }
+
+ private void print(ArrayList<GlinesField>? path)
+ {
+ var sb = new StringBuilder();
+
+ sb.append("Preview: ");
+ foreach (var preview in board.preview_queue.pieces)
+ sb.append_c(id_to_char_symbol[preview.id]);
+ sb.append("\n\n");
+
+ for (int n = 0; n < board.cols + 2; n++)
+ sb.append("#");
+ sb.append("\n");
+
+ for (int y = 0; y < board.rows; y++)
+ {
+ sb.append("#");
+ for (int x = 0; x < board.cols; x++)
+ {
+ var field = board.fields[x,y];
+
+ bool is_cursor = board.cursor_x == x && board.cursor_y == y;
+
+ if (field.active)
+ {
+ sb.append("@");
+ continue;
+ }
+
+ if (!field.has_piece)
+ {
+ if (is_cursor) sb.append("Â");
+ else
+ {
+ if (path != null && field.path_search != null && path.contains(field))
+ {
+ if (field.path_search == field.neigbour_north)
+ sb.append("â");
+ if (field.path_search == field.neigbour_south)
+ sb.append("â");
+ if (field.path_search == field.neigbour_west)
+ sb.append("â");
+ if (field.path_search == field.neigbour_east)
+ sb.append("â");
+ }
+ else
+ sb.append(" ");
+ }
+ }
+ else
+ {
+ char symbol = id_to_char_symbol[field.piece.id];
+
+ if (is_cursor)
+ sb.append_c(symbol.toupper());
+ else
+ sb.append_c(symbol);
+ }
+ }
+
+ sb.append("#\n");
+ }
+
+ for (int n = 0; n < board.cols + 2; n++)
+ sb.append("#");
+
+ sb.append("\n\n");
+ sb.append(message);
+ sb.append("\n");
+
+ stdout.printf(sb.str);
+ }
+
+ private void animate_move(ArrayList<GlinesField> path)
+ {
+ //"animate" the move:
+ this.message = "'Animating' the move...";
+ this.print(path);
+ this.message = "";
+ stdin.getc();
+ }
+ }
+}
+
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]