[gnome-games] swell-foop: Port to Vala
- From: Robert Ancell <rancell src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-games] swell-foop: Port to Vala
- Date: Sat, 10 Mar 2012 13:41:47 +0000 (UTC)
commit a1b6e5ca9cf1fa25f662867db29f584aa2b328ed
Author: Sophia Yu <sophia receiving gmail com>
Date: Thu Mar 8 00:23:53 2012 -0600
swell-foop: Port to Vala
po/POTFILES.in | 10 +-
swell-foop/data/Makefile.am | 3 +-
.../data/org.gnome.swell-foop.gschema.xml.in | 11 +-
swell-foop/data/{settings.ui => preferences.ui} | 213 ++++++----
swell-foop/data/swell-foop.ui | 165 -------
swell-foop/data/themes/colors/Makefile.am | 6 +-
swell-foop/data/themes/colors/theme.js | 12 -
swell-foop/data/themes/shapesandcolors/Makefile.am | 6 +-
swell-foop/data/themes/shapesandcolors/theme.js | 12 -
swell-foop/src/About.js | 32 --
swell-foop/src/Board.js | 308 -------------
swell-foop/src/Light.js | 126 ------
swell-foop/src/Makefile.am | 72 ++--
swell-foop/src/Path.js.in | 1 -
swell-foop/src/Score.js | 151 -------
swell-foop/src/Settings.js | 157 -------
swell-foop/src/ThemeLoader.js | 38 --
swell-foop/src/config.vapi | 4 +
swell-foop/src/game-view.vala | 345 +++++++++++++++
swell-foop/src/game.vala | 290 ++++++++++++
swell-foop/src/main.js | 121 -----
swell-foop/src/swell-foop.in | 5 -
swell-foop/src/swell-foop.vala | 463 ++++++++++++++++++++
23 files changed, 1285 insertions(+), 1266 deletions(-)
---
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 1bdd46b..25eb965 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -125,10 +125,8 @@ quadrapassel/src/game-view.vala
quadrapassel/src/preview.vala
quadrapassel/src/quadrapassel.vala
swell-foop/data/org.gnome.swell-foop.gschema.xml.in
-[type: gettext/glade]swell-foop/data/settings.ui
swell-foop/data/swell-foop.desktop.in.in
-[type: gettext/glade]swell-foop/data/swell-foop.ui
-swell-foop/src/About.js
-swell-foop/src/Board.js
-swell-foop/src/Score.js
-swell-foop/src/Settings.js
+[type: gettext/glade]swell-foop/data/preferences.ui
+swell-foop/src/game.vala
+swell-foop/src/game-view.vala
+swell-foop/src/swell-foop.vala
diff --git a/swell-foop/data/Makefile.am b/swell-foop/data/Makefile.am
index 80f24a0..16bfc69 100644
--- a/swell-foop/data/Makefile.am
+++ b/swell-foop/data/Makefile.am
@@ -7,8 +7,7 @@ gsettings_SCHEMAS = $(gsettings_in_file:.xml.in=.xml)
swelldir=$(pkgdatadir)/swell-foop
swell_DATA = \
- swell-foop.ui \
- settings.ui
+ preferences.ui
desktop_in_files = swell-foop.desktop.in.in
desktopdir = $(datadir)/applications
diff --git a/swell-foop/data/org.gnome.swell-foop.gschema.xml.in b/swell-foop/data/org.gnome.swell-foop.gschema.xml.in
index 539d655..f0111b7 100644
--- a/swell-foop/data/org.gnome.swell-foop.gschema.xml.in
+++ b/swell-foop/data/org.gnome.swell-foop.gschema.xml.in
@@ -1,12 +1,17 @@
<schemalist>
+ <enum id="org.gnome.swell-foop.Sizes">
+ <value value="0" nick="small"/>
+ <value value="1" nick="normal"/>
+ <value value="2" nick="large"/>
+ </enum>
<schema id="org.gnome.swell-foop" path="/org/gnome/swell-foop/" gettext-domain="gnome-games">
<key name="theme" type="s">
- <default>'Shapes and Colors'</default>
+ <default>'shapesandcolors'</default>
<_summary>The theme to use</_summary>
<_description>The title of the tile theme to use.</_description>
</key>
- <key name="size" type="i">
- <default>1</default>
+ <key name="size" enum="org.gnome.swell-foop.Sizes">
+ <default>'small'</default>
<_summary>Board size</_summary>
<_description>The size of the game board.</_description>
</key>
diff --git a/swell-foop/data/settings.ui b/swell-foop/data/preferences.ui
similarity index 70%
rename from swell-foop/data/settings.ui
rename to swell-foop/data/preferences.ui
index 101dfd9..9dbf1b8 100644
--- a/swell-foop/data/settings.ui
+++ b/swell-foop/data/preferences.ui
@@ -1,74 +1,144 @@
-<?xml version="1.0"?>
+<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk+" version="2.16"/>
- <!-- interface-naming-policy project-wide -->
- <object class="GtkDialog" id="dialog1">
+ <object class="GtkAdjustment" id="color-adjustment">
+ <property name="lower">2</property>
+ <property name="upper">4</property>
+ <property name="step_increment">1</property>
+ </object>
+ <object class="GtkAdjustment" id="columns-adjustment">
+ <property name="lower">3</property>
+ <property name="upper">21</property>
+ <property name="step_increment">1</property>
+ </object>
+ <object class="GtkListStore" id="liststore1">
+ <columns>
+ <!-- column-name str -->
+ <column type="gchararray"/>
+ </columns>
+ </object>
+ <object class="GtkListStore" id="liststore2">
+ <columns>
+ <!-- column-name str -->
+ <column type="gchararray"/>
+ </columns>
+ </object>
+ <object class="GtkDialog" id="preferences">
+ <property name="can_focus">False</property>
<property name="border_width">5</property>
<property name="title" translatable="yes">Swell Foop</property>
- <property name="icon_name">swell-foop</property>
+ <property name="icon_name">gnome-swell-foop</property>
<property name="type_hint">normal</property>
<child internal-child="vbox">
- <object class="GtkVBox" id="dialog-vbox1">
+ <object class="GtkBox" id="dialog-vbox1">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="dialog-action_area1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="close-button">
+ <property name="label">gtk-close</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_action_appearance">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
<child>
<object class="GtkVBox" id="vbox2">
<property name="visible">True</property>
- <property name="orientation">vertical</property>
+ <property name="can_focus">False</property>
<child>
<object class="GtkFrame" id="frame3">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkAlignment" id="alignment3">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="left_padding">12</property>
<child>
<object class="GtkHBox" id="hbox1">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<child>
<object class="GtkVBox" id="vbox3">
<property name="visible">True</property>
- <property name="orientation">vertical</property>
+ <property name="can_focus">False</property>
<child>
<object class="GtkLabel" id="label3">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Board size:</property>
</object>
<packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label9">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Number of colors:</property>
</object>
<packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkVBox" id="vbox4">
<property name="visible">True</property>
- <property name="orientation">vertical</property>
+ <property name="can_focus">False</property>
<child>
- <object class="GtkComboBoxText" id="size-selector">
+ <object class="GtkComboBox" id="size-selector">
<property name="visible">True</property>
- <property name="entry-text-column">0</property>
- <property name="id-column">1</property>
- <signal name="changed" handler="update_size"/>
+ <property name="can_focus">False</property>
+ <property name="model">size_model</property>
+ <child>
+ <object class="GtkCellRendererText" id="size_cellrenderer"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ <signal name="changed" handler="update_size" swapped="no"/>
</object>
<packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
@@ -76,16 +146,20 @@
<object class="GtkSpinButton" id="colors-spinner">
<property name="visible">True</property>
<property name="can_focus">True</property>
- <property name="invisible_char">•</property>
+ <property name="invisible_char">â</property>
<property name="adjustment">color-adjustment</property>
- <signal name="value_changed" handler="update_colors"/>
+ <signal name="value-changed" handler="update_colors" swapped="no"/>
</object>
<packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
@@ -96,6 +170,7 @@
<child type="label">
<object class="GtkLabel" id="label5">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="ypad">5</property>
<property name="label" translatable="yes">Setup</property>
<attributes>
@@ -106,43 +181,57 @@
</object>
<packing>
<property name="expand">False</property>
+ <property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkFrame" id="frame1">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkAlignment" id="alignment1">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="left_padding">12</property>
<child>
<object class="GtkVBox" id="vbox1">
<property name="visible">True</property>
- <property name="orientation">vertical</property>
+ <property name="can_focus">False</property>
<child>
<object class="GtkHBox" id="hbox2">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<child>
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="label" translatable="yes">Theme:</property>
</object>
<packing>
<property name="expand">False</property>
+ <property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
- <object class="GtkComboBoxText" id="theme-selector">
+ <object class="GtkComboBox" id="theme-selector">
<property name="visible">True</property>
- <property name="entry-text-column">0</property>
- <property name="id-column">1</property>
- <signal name="changed" handler="select_theme"/>
+ <property name="can_focus">False</property>
+ <property name="model">theme_model</property>
+ <child>
+ <object class="GtkCellRendererText" id="theme_cellrenderer"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ <signal name="changed" handler="select_theme" swapped="no"/>
</object>
<packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
<property name="padding">8</property>
<property name="position">1</property>
</packing>
@@ -150,6 +239,7 @@
</object>
<packing>
<property name="expand">False</property>
+ <property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
@@ -160,6 +250,7 @@
<child type="label">
<object class="GtkLabel" id="label2">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="ypad">5</property>
<property name="label" translatable="yes">Appearance</property>
<attributes>
@@ -170,38 +261,45 @@
</object>
<packing>
<property name="expand">False</property>
+ <property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
+ <property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkFrame" id="frame2">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkAlignment" id="alignment2">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="left_padding">12</property>
<child>
<object class="GtkVBox" id="vbox5">
<property name="visible">True</property>
- <property name="orientation">vertical</property>
+ <property name="can_focus">False</property>
<child>
<object class="GtkCheckButton" id="zealous-checkbox">
<property name="label" translatable="yes">Zealous Animation</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
+ <property name="use_action_appearance">False</property>
<property name="draw_indicator">True</property>
- <signal name="toggled" handler="set_zealous_animation"/>
+ <signal name="toggled" handler="set_zealous_animation" swapped="no"/>
</object>
<packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
@@ -212,6 +310,7 @@
<child type="label">
<object class="GtkLabel" id="label8">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="ypad">5</property>
<property name="label" translatable="yes">Operation</property>
<attributes>
@@ -222,81 +321,35 @@
</object>
<packing>
<property name="expand">False</property>
+ <property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
- <child internal-child="action_area">
- <object class="GtkHButtonBox" id="dialog-action_area1">
- <property name="visible">True</property>
- <property name="layout_style">end</property>
- <child>
- <object class="GtkButton" id="reset-button">
- <property name="label">gtk-revert-to-saved</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <property name="use_stock">True</property>
- <signal name="activate" handler="reset_defaults"/>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkButton" id="close-button">
- <property name="label">gtk-close</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <property name="use_stock">True</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">1</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="pack_type">end</property>
- <property name="position">0</property>
- </packing>
- </child>
</object>
</child>
<action-widgets>
- <action-widget response="0">reset-button</action-widget>
<action-widget response="0">close-button</action-widget>
</action-widgets>
</object>
- <object class="GtkListStore" id="liststore1">
+ <object class="GtkListStore" id="theme_model">
<columns>
- <!-- column-name str -->
+ <!-- column-name label -->
+ <column type="gchararray"/>
+ <!-- column-name id -->
<column type="gchararray"/>
</columns>
</object>
- <object class="GtkAdjustment" id="rows-adjustment">
- <property name="lower">3</property>
- <property name="upper">21</property>
- <property name="step_increment">1</property>
+ <object class="GtkListStore" id="size_model">
+ <columns>
+ <!-- column-name label -->
+ <column type="gchararray"/>
+ <!-- column-name id -->
+ <column type="gchararray"/>
+ </columns>
</object>
- <object class="GtkAdjustment" id="columns-adjustment">
+ <object class="GtkAdjustment" id="rows-adjustment">
<property name="lower">3</property>
<property name="upper">21</property>
<property name="step_increment">1</property>
</object>
- <object class="GtkAdjustment" id="color-adjustment">
- <property name="lower">2</property>
- <property name="upper">4</property>
- <property name="step_increment">1</property>
- </object>
- <object class="GtkListStore" id="liststore2">
- <columns>
- <!-- column-name str -->
- <column type="gchararray"/>
- </columns>
- </object>
</interface>
diff --git a/swell-foop/data/themes/colors/Makefile.am b/swell-foop/data/themes/colors/Makefile.am
index 3a921f6..16467bf 100644
--- a/swell-foop/data/themes/colors/Makefile.am
+++ b/swell-foop/data/themes/colors/Makefile.am
@@ -4,15 +4,13 @@ theme_DATA = \
blue.svg \
green.svg \
red.svg \
- yellow.svg \
- theme.js
+ yellow.svg
EXTRA_DIST = \
bkg.svg \
blue.svg \
green.svg \
red.svg \
- yellow.svg \
- theme.js
+ yellow.svg
-include $(top_srcdir)/git.mk
diff --git a/swell-foop/data/themes/shapesandcolors/Makefile.am b/swell-foop/data/themes/shapesandcolors/Makefile.am
index 2d9272b..ca7c22e 100644
--- a/swell-foop/data/themes/shapesandcolors/Makefile.am
+++ b/swell-foop/data/themes/shapesandcolors/Makefile.am
@@ -4,15 +4,13 @@ theme_DATA = \
blue.svg \
green.svg \
red.svg \
- yellow.svg \
- theme.js
+ yellow.svg
EXTRA_DIST = \
bkg.svg \
blue.svg \
green.svg \
red.svg \
- yellow.svg \
- theme.js
+ yellow.svg
-include $(top_srcdir)/git.mk
diff --git a/swell-foop/src/Makefile.am b/swell-foop/src/Makefile.am
index 41a9962..a81e180 100644
--- a/swell-foop/src/Makefile.am
+++ b/swell-foop/src/Makefile.am
@@ -1,41 +1,35 @@
-swelldir=$(pkgdatadir)/swell-foop
-
-bin_SCRIPTS = swell-foop
-
-swell-foop: swell-foop.in Makefile
- $(AM_V_GEN) $(SED) -e "s|%pkglibdir%|$(pkglibdir)|" -e "s|%pkgdatadir%|$(pkgdatadir)|" $< > $@
- chmod +x $@
-
-swell_DATA = \
- About.js \
- Board.js \
- Light.js \
- main.js \
- Settings.js \
- Score.js \
- Path.js \
- ThemeLoader.js
-
-Path.js: Path.js.in
- $(AM_V_GEN) $(SED) -e "s|%pkgdatadir%|$(pkgdatadir)|" $< > $@
-
-EXTRA_DIST = \
- swell-foop.in \
- About.js \
- Board.js \
- Light.js \
- main.js \
- Settings.js \
- Score.js \
- Path.js.in \
- ThemeLoader.js
-
-CLEANFILES = \
- swell-foop \
- Path.js
-
-DISTCLEANFILES = \
- swell-foop \
- Path.js
+bin_PROGRAMS = swell-foop
+
+swell_foop_SOURCES = \
+ game-view.vala \
+ game.vala \
+ config.vapi \
+ swell-foop.vala
+
+swell_foop_VALAFLAGS = \
+ --pkg posix \
+ --pkg gmodule-2.0 \
+ --pkg clutter-gtk-1.0 \
+ --vapidir $(top_srcdir)/libgames-support \
+ --pkg GnomeGamesSupport-1.0
+
+swell_foop_CFLAGS = \
+ -I$(top_srcdir)/libgames-support \
+ -DVERSION=\"$(VERSION)\" \
+ -DGETTEXT_PACKAGE=\"$(GETTEXT_PACKAGE)\" \
+ -DPKGDATADIR=\""$(pkgdatadir)/swell-foop"\" \
+ -DLOCALEDIR=\"$(pkgdatadir)/locale\" \
+ $(GHTREAD_CFLAGS) \
+ $(GMODULE_CFLAGS) \
+ $(GTK_CFLAGS) \
+ $(CLUTTER_GTK_CFLAGS)
+
+swell_foop_LDADD = \
+ $(top_builddir)/libgames-support/libgames-support.la \
+ $(GTHREAD_LIBS) \
+ $(GMODULE_LIBS) \
+ $(GTK_LIBS) \
+ $(CLUTTER_GTK_LIBS) \
+ $(INTLLIBS)
-include $(top_srcdir)/git.mk
diff --git a/swell-foop/src/config.vapi b/swell-foop/src/config.vapi
new file mode 100644
index 0000000..a1787ca
--- /dev/null
+++ b/swell-foop/src/config.vapi
@@ -0,0 +1,4 @@
+public const string PKGDATADIR;
+public const string LOCALEDIR;
+public const string GETTEXT_PACKAGE;
+public const string VERSION;
diff --git a/swell-foop/src/game-view.vala b/swell-foop/src/game-view.vala
new file mode 100644
index 0000000..3338835
--- /dev/null
+++ b/swell-foop/src/game-view.vala
@@ -0,0 +1,345 @@
+/**
+ * This class defines the view of a game. All clutter related stuff goes here. It follows the
+ * principle of MVC framework. This class deals with the presentation (view) layer. It communicates
+ * with the model class by composite relation and with the control layer by means of signals and
+ * events.
+ */
+public class GameView : Clutter.Group
+{
+ /* A 2D array holding all tiles */
+ private TileActor[,] tiles;
+ private ScoreActor score_text;
+
+ /* Game being played */
+ private Game? _game = null;
+ public Game? game
+ {
+ get { return _game; }
+ set
+ {
+ /* Remove old tiles */
+ remove_tiles ();
+
+ if (game != null)
+ SignalHandler.disconnect_matched (game, SignalMatchType.DATA, 0, 0, null, null, this);
+ _game = value;
+ game.complete.connect (game_complete_cb);
+ game.update_score.connect (update_score_cb);
+
+ /* Put tiles in new locations */
+ tiles = new TileActor [game.columns, game.rows];
+ place_tiles ();
+
+ width = tile_size * game.columns;
+ height = tile_size * game.rows;
+
+ /* View size may change so we create the object score_text everytime with a new game */
+ if (score_text != null)
+ score_text.destroy ();
+ score_text = new ScoreActor (width / 2.0, height / 2.0);
+ add_actor (score_text);
+ }
+ }
+
+ /* This is a <ThemeName -- ThemeObject> container */
+ private HashTable<string, Theme> themes;
+
+ /* Theme being used */
+ private string _theme_name = "shapesandcolors";
+ public string theme_name
+ {
+ get { return _theme_name; }
+ set
+ {
+ if (theme_name == value)
+ return;
+ _theme_name = value;
+ remove_tiles ();
+ place_tiles ();
+ }
+ }
+
+ /* Size of tiles */
+ private int tile_size = 50;
+
+ private void remove_tiles ()
+ {
+ if (game == null)
+ return;
+
+ for (var x = 0; x < game.columns; x++)
+ {
+ for (var y = 0; y < game.rows; y++)
+ {
+ var tile = tiles[x, y];
+ if (tile == null)
+ continue;
+ tiles[x, y] = null;
+
+ SignalHandler.disconnect_matched (tile, SignalMatchType.DATA, 0, 0, null, null, this);
+ tile.destroy ();
+ }
+ }
+ }
+
+ private void place_tiles ()
+ {
+ if (game == null)
+ return;
+
+ var theme = themes.lookup (theme_name);
+ if (theme == null)
+ theme = themes.lookup ("shapesandcolors");
+
+ for (var x = 0; x < game.columns; x++)
+ {
+ for (var y = 0; y < game.rows; y++)
+ {
+ /* For each tile object, we create a tile actor for it */
+ var l = game.get_tile (x, y);
+ if (l == null)
+ continue;
+ var tile = new TileActor (l, theme.textures[l.color], tile_size);
+
+ /* The event from the model will be caught and responded by the view */
+ l.move.connect (move_cb);
+ l.close.connect (close_cb);
+
+ /* Physical position in the stage */
+ float xx, yy;
+ xx = x * tile_size + tile_size / 2;
+ yy = (game.rows - y - 1) * tile_size + tile_size / 2;
+ tile.set_position (xx, yy);
+
+ /* Respond to the user interactions */
+ tile.reactive = true;
+ tile.button_release_event.connect (remove_region_cb);
+ tile.enter_event.connect (tile_entered_cb);
+ tile.leave_event.connect (tile_left_cb);
+
+ tiles[x, y] = tile;
+ add_actor (tile);
+ }
+ }
+ }
+
+ public bool is_zealous;
+
+ public GameView ()
+ {
+ /* Initialize the theme resources */
+ themes = new HashTable<string, Theme> (str_hash, str_equal);
+ var theme = new Theme ("colors");
+ themes.insert ("colors", theme);
+ foreach (var t in theme.textures)
+ {
+ t.hide ();
+ add_actor (t);
+ }
+ theme = new Theme ("shapesandcolors");
+ themes.insert ("shapesandcolors", theme);
+ foreach (var t in theme.textures)
+ {
+ t.hide ();
+ add_actor (t);
+ }
+ }
+
+ /* When a tile in the model layer is closed, play an animation at the view layer */
+ public void close_cb (int grid_x, int grid_y)
+ {
+ tiles[grid_x, grid_y].animate_out ();
+ }
+
+ /* When a tile in the model layer is moved, play an animation at the view layer */
+ public void move_cb (int old_x, int old_y, int new_x, int new_y)
+ {
+ var tile = tiles[old_x, old_y];
+ tiles[new_x, new_y] = tile;
+ var new_xx = new_x * tile_size + tile_size / 2.0;
+ var new_yy = (game.rows - new_y - 1) * tile_size + tile_size / 2.0;
+
+ tile.animate_to (new_xx, new_yy, is_zealous);
+ }
+
+ /* When the mouse enters a tile, bright up the connected tiles */
+ private bool tile_entered_cb (Clutter.Actor actor, Clutter.CrossingEvent event)
+ {
+ var tile = (TileActor) actor;
+
+ var connected_tiles = game.connected_tiles (tile.tile);
+ foreach (var l in connected_tiles)
+ tiles[l.grid_x, l.grid_y].opacity = 255;
+
+ return false;
+ }
+
+ /* When the mouse leaves a tile, lower the brightness of the connected tiles */
+ private bool tile_left_cb (Clutter.Actor actor, Clutter.CrossingEvent event)
+ {
+ var tile = (TileActor) actor;
+
+ var connected_tiles = game.connected_tiles (tile.tile);
+ foreach (var l in connected_tiles)
+ tiles[l.grid_x, l.grid_y].opacity = 180;
+
+ return false;
+ }
+
+ /* When the user click a tile, send the model to remove the connected tile. */
+ private bool remove_region_cb (Clutter.Actor actor, Clutter.ButtonEvent event)
+ {
+ var tile = (TileActor) actor;
+
+ game.remove_connected_tiles (tile.tile);
+
+ return false;
+ }
+
+ /* When the mouse leaves the application window, reset all tiles to the default brightness */
+ public bool board_left_cb ()
+ {
+ game.reset_visit ();
+
+ foreach (var tile in tiles)
+ tile.opacity = 180;
+
+ return false;
+ }
+
+ /* Show flying score animation after each tile-removing click */
+ public void update_score_cb (int points_awarded)
+ {
+ if (is_zealous)
+ score_text.animate_score (points_awarded);
+ }
+
+ /* Show the final score when the game is over */
+ public void game_complete_cb ()
+ {
+ score_text.animate_final_score (game.score);
+ }
+}
+
+/**
+ * This class holds the textures for a specific theme. These textures are used for creating light
+ * actors.
+ */
+public class Theme
+{
+ public Clutter.Texture[] textures;
+
+ public Theme (string name)
+ {
+ textures = new Clutter.Texture [4];
+ string[4] colors = {"blue", "green", "yellow", "red"};
+
+ /* Create the textures required to render */
+ try
+ {
+ for (int i = 0; i < 4; i++)
+ textures[i] = new Clutter.Texture.from_file (Path.build_filename (PKGDATADIR, "themes", name, colors[i] + ".svg"));
+ }
+ catch (Clutter.TextureError e)
+ {
+ warning ("Failed to load textures: %s", e.message);
+ }
+ }
+}
+
+/**
+ * This class defines the view of a tile. All clutter related stuff goes here
+ */
+private class TileActor : Clutter.Clone
+{
+ /* Tile being represented */
+ public Tile tile;
+
+ public TileActor (Tile tile, Clutter.Texture texture, int size)
+ {
+ this.tile = tile;
+ source = texture;
+ opacity = 180;
+ set_size (size, size);
+ set_anchor_point (size / 2, size / 2);
+ }
+
+ /* Destroy the tile */
+ public void animate_out ()
+ {
+ /* When the animination is done, hide the actor */
+ var a = animate (Clutter.AnimationMode.LINEAR, 500, "scale-x", 2.0, "scale-y", 2.0, "opacity", 0);
+ a.timeline.completed.connect (hide_tile_cb);
+ }
+
+ private void hide_tile_cb ()
+ {
+ hide ();
+ }
+
+ /* Define how the tile moves */
+ public void animate_to (double new_x, double new_y, bool is_zealous = false)
+ {
+ var anim_mode = is_zealous ? Clutter.AnimationMode.EASE_OUT_BOUNCE : Clutter.AnimationMode.EASE_OUT_QUAD;
+ animate (anim_mode, 500, "x", new_x, "y", new_y);
+ }
+}
+
+/**
+ * This class defines the view of a score. All clutter related stuff goes here
+ */
+public class ScoreActor : Clutter.Group
+{
+ private Clutter.Text label;
+
+ public ScoreActor (double x, double y)
+ {
+ label = new Clutter.Text ();
+ label.set_color (Clutter.Color.from_string ("rgba(255, 255, 255, 255)"));
+
+ anchor_gravity = Clutter.Gravity.CENTER;
+ add_actor (label);
+
+ this.x = (float) x;
+ this.y = (float) y;
+ }
+
+ public void hide_score_cb ()
+ {
+ hide ();
+ }
+
+ public void animate_score (int points)
+ {
+ if (points <= 0)
+ return;
+
+ label.set_font_name ("Bitstrem Vera Sans Bold 40");
+ label.set_text ("+" + points.to_string());
+
+ /* The score will be shown repeatedly therefore we need to reset some important properties
+ * before the actual animation */
+ show ();
+ opacity = 255;
+ depth = 0;
+
+ var a = animate (Clutter.AnimationMode.EASE_OUT_SINE, 600, "depth", 500.0, "opacity", 0);
+ a.timeline.completed.connect (hide_score_cb);
+ }
+
+ public void animate_final_score (uint points)
+ {
+ label.set_font_name ("Bitstrem Vera Sans 50");
+ label.set_markup ("<b>" + _ ("Game Over!") + "</b>\n" + points.to_string () + _ ("points"));
+ label.set_line_alignment (Pango.Alignment.CENTER);
+
+ /* The score will be shown repeatedly therefore we need to reset some important properties
+ * before the actual animation */
+ show ();
+ opacity = 255;
+ depth = 0;
+
+ scale_x = scale_y = 0.0;
+ animate (Clutter.AnimationMode.EASE_OUT_ELASTIC, 2000, scale_x: 1.0, scale_y: 1.0, opacity: 255);
+ }
+}
diff --git a/swell-foop/src/game.vala b/swell-foop/src/game.vala
new file mode 100644
index 0000000..372a5a6
--- /dev/null
+++ b/swell-foop/src/game.vala
@@ -0,0 +1,290 @@
+/**
+ * This is the model layer of a tile.
+ */
+public class Tile
+{
+ /* Property */
+ private bool _closed = false;
+ public bool closed
+ {
+ get { return _closed; }
+ set
+ {
+ _closed = value;
+ /* Send close signal */
+ if (_closed)
+ close (grid_x, grid_y);
+ }
+ }
+
+ public int grid_x;
+ public int grid_y;
+ public int color;
+ public bool visited = false;
+
+ /* Signals */
+ public signal void move (int old_x, int old_y, int new_x, int new_y);
+ public signal void close (int grid_x, int grid_y);
+
+ /* Constructor */
+ public Tile (int x, int y, int c)
+ {
+ grid_x = x;
+ grid_y = y;
+ color = c;
+ }
+
+ /* Do not use this mothod to initialize the position. */
+ public void update_position (int new_x, int new_y)
+ {
+ var old_x = grid_x;
+ var old_y = grid_y;
+
+ if ((new_x != old_x) || (new_y != old_y))
+ {
+ grid_x = new_x;
+ grid_y = new_y;
+
+ /* Send move signal to actor in the view */
+ if (!closed)
+ move (old_x, old_y, new_x, new_y);
+ }
+ }
+}
+
+/**
+ * This is the model layer of the whole game. All game logic goes here. This class tries not to
+ * bring in any visual stuff to comply the separation of view-model idea.
+ */
+public class Game : Object
+{
+ private Tile[,] tiles;
+
+ /* Game score */
+ public int score { get; set; default = 0; }
+
+ private int _color_num = 3;
+ public int color_num
+ {
+ get { return _color_num; }
+ set
+ {
+ if (value < 2 || value > 4)
+ _color_num = 3;
+ else
+ _color_num = value;
+ }
+ }
+
+ /* Property */
+ public int rows { get; set; default = 8; }
+ public int columns { get; set; default = 8; }
+
+ public signal void update_score (int points_awarded);
+ public signal void complete ();
+
+ /* Constructor */
+ public Game (int rows, int columns, int color_num)
+ {
+ _rows = rows;
+ _columns = columns;
+ _color_num = color_num;
+
+ /* A 2D array holds all tiles */
+ tiles = new Tile [rows, columns];
+
+ for (var x = 0; x < columns; x++)
+ {
+ for (var y = 0; y < rows; y++)
+ {
+ int c = (int) Math.floor (Random.next_double () * color_num);
+ tiles[y, x] = new Tile (x, y, c);
+ }
+ }
+ }
+
+ /* Recursively find all the connected tile from li */
+ private List<Tile> _connected_tiles (Tile? li)
+ {
+ var cl = new List<Tile> ();
+
+ if (li.visited || li.closed)
+ return cl;
+
+ var x = li.grid_x;
+ var y = li.grid_y;
+
+ li.visited = true;
+
+ cl.append (li);
+
+ if ((y + 1) < rows && tiles[y + 1, x] != null && (li.color == tiles[y + 1, x].color))
+ cl.concat (_connected_tiles (tiles[y + 1, x]));
+
+ if ((y - 1) >= 0 && tiles[y - 1, x] != null && (li.color == tiles[y - 1, x].color))
+ cl.concat (_connected_tiles (tiles[y - 1, x]));
+
+ if ((x + 1) < columns && tiles[y, x + 1] != null && (li.color == tiles[y, x + 1].color))
+ cl.concat (_connected_tiles (tiles[y, x + 1]));
+
+ if ((x - 1) >= 0 && tiles[y, x - 1] != null && (li.color == tiles[y, x - 1].color))
+ cl.concat (_connected_tiles (tiles[y, x - 1]));
+
+ return cl;
+ }
+
+ public List<Tile> connected_tiles (Tile li)
+ {
+ foreach (var l in tiles)
+ {
+ if (l != null)
+ l.visited = false;
+ }
+
+ List<Tile> cl = _connected_tiles (li);
+
+ /* single tile will be ignored */
+ if (cl.length () < 2)
+ cl = null;
+
+ return cl;
+ }
+
+ public Tile get_tile (int x, int y)
+ {
+ return tiles[y, x];
+ }
+
+ public bool remove_connected_tiles (Tile tile)
+ {
+ List<Tile> cl = connected_tiles (tile);
+
+ if (cl == null)
+ return false;
+
+ foreach (var l in cl)
+ l.closed = true;
+
+ int new_x = 0;
+
+ for (int x = 0; x < columns; x++)
+ {
+ var not_closed_tiles = new List<Tile> ();
+ var closed_tiles = new List<Tile> ();
+
+ /* for each column, separate not-closed and closed tiles */
+ for (int y = 0; y < rows; y++)
+ {
+ var li = tiles[y, x];
+
+ if (li == null)
+ break;
+
+ if (li.closed)
+ closed_tiles.append (li);
+ else
+ not_closed_tiles.append (li);
+ }
+
+ /* append closed tiles to not-closed tiles */
+ not_closed_tiles.concat ( (owned) closed_tiles);
+
+ /* update tile array at the current column, not-closed tiles aret at the bottom, closed ones top */
+ for (int y = 0; y < rows; y++)
+ tiles[y, new_x] = not_closed_tiles.nth_data (y);
+
+ /* flag to check if current column is empty */
+ var has_empty_col = true;
+
+ /* update the positions (grid_x, grid_y) of tiles at the current column */
+ for (int y = 0; y < rows; y++)
+ {
+ var l = tiles[y, new_x];
+
+ if (l == null)
+ break;
+
+ l.update_position (new_x, y);
+
+ if (!l.closed)
+ has_empty_col = false;
+ }
+
+ /* If the current column is empty, don't increment new_x. Otherwise increment */
+ if (!has_empty_col)
+ new_x++;
+ }
+
+ /* The remaining columns are do-not-cares. Assign null to them */
+ for (; new_x < columns; new_x++)
+ for (int y = 0; y < rows; y++)
+ tiles[y, new_x] = null;
+
+ increment_score ((int)cl.length ());
+
+ if (this.has_completed ())
+ {
+ if (this.has_won ())
+ score += 1000;
+ complete ();
+ }
+
+ return false;
+ }
+
+ public void reset_visit ()
+ {
+ foreach (var l in tiles)
+ {
+ if (l != null)
+ l.visited = false;
+ }
+ }
+
+ public bool has_completed ()
+ {
+ foreach (var l in tiles)
+ {
+ if (l != null && !l.closed && (connected_tiles (l).length () > 1))
+ return false;
+ }
+
+ return true;
+ }
+
+ public bool has_won ()
+ {
+ foreach (var l in tiles)
+ {
+ if (l != null && !l.closed)
+ return false;
+ }
+
+ return true;
+ }
+
+ public int calculate_score (int n_tiles)
+ {
+ var points_awarded = 0;
+
+ if (n_tiles >= 3)
+ points_awarded = (n_tiles - 2) * (n_tiles - 2);
+
+ update_score (points_awarded);
+
+ return points_awarded;
+ }
+
+ public void increment_score (int tiles)
+ {
+ var points_awarded = calculate_score (tiles);
+ score += points_awarded;
+
+ update_score (points_awarded);
+ }
+
+ public void update_score_category()
+ {
+ // TODO to be implemented
+ }
+}
diff --git a/swell-foop/src/swell-foop.vala b/swell-foop/src/swell-foop.vala
new file mode 100644
index 0000000..31aa6dc
--- /dev/null
+++ b/swell-foop/src/swell-foop.vala
@@ -0,0 +1,463 @@
+public class SwellFoop : Gtk.Application
+{
+ /* Application settings */
+ private Settings settings;
+
+ /* Main window */
+ private Gtk.Window main_window;
+
+ /* Game being played */
+ private Game? game = null;
+
+ /* Rendering of game */
+ private GameView view;
+
+ private Clutter.Stage stage;
+ private GtkClutter.Embed clutter_embed;
+
+ private GnomeGamesSupport.Scores high_scores;
+
+ private Gtk.Dialog? preferences_dialog = null;
+
+ private Gtk.Label current_score_label;
+
+ /* Store size options */
+ public Size[] sizes;
+
+ 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 Gtk.ActionEntry actions[] =
+ {
+ { "NewGame", GnomeGamesSupport.STOCK_NEW_GAME, null, null, null, new_game_cb }
+ };
+
+ /* Constructor */
+ public SwellFoop ()
+ {
+ Object (application_id: "org.gnome.swell-foop", flags: ApplicationFlags.FLAGS_NONE);
+ }
+
+ protected override void startup ()
+ {
+ base.startup ();
+
+ settings = new Settings ("org.gnome.swell-foop");
+
+ GnomeGamesSupport.stock_init ();
+
+ add_action_entries (action_entries, this);
+
+ var action_group = new Gtk.ActionGroup ("group");
+ action_group.set_translation_domain (GETTEXT_PACKAGE);
+ action_group.add_actions (actions, this);
+ action_group.get_action ("NewGame").is_important = true;
+
+ /* Create the main window */
+ main_window = new Gtk.ApplicationWindow (this);
+ main_window.set_title (_("Swell Foop"));
+ main_window.resizable = false;
+
+ var vbox = new Gtk.Box (Gtk.Orientation.VERTICAL, 0);
+ vbox.show ();
+ main_window.add (vbox);
+
+ /* Create the menus */
+ 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);
+
+ /* Create a toolbar */
+ var ui_manager = new Gtk.UIManager ();
+ ui_manager.insert_action_group (action_group, 0);
+ try
+ {
+ var ui_description =
+ "<ui>" +
+ " <toolbar name='Toolbar'>" +
+ " <toolitem action='NewGame'/>" +
+ " </toolbar>" +
+ "</ui>";
+ ui_manager.add_ui_from_string (ui_description, -1);
+ }
+ catch (Error e)
+ {
+ warning ("Failed to load UI: %s", e.message);
+ }
+ main_window.add_accel_group (ui_manager.get_accel_group ());
+
+ var toolbar = (Gtk.Toolbar) ui_manager.get_widget ("/Toolbar");
+ toolbar.show_arrow = false;
+ toolbar.get_style_context ().add_class (Gtk.STYLE_CLASS_PRIMARY_TOOLBAR);
+ toolbar.show ();
+ vbox.pack_start (toolbar, false, true, 0);
+
+ /* Create a label in toolbar showing the score etc. */
+ var status_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 10);
+ status_box.show ();
+
+ /* show the current score */
+ current_score_label = new Gtk.Label ("");
+ current_score_label.show ();
+ status_box.pack_start (current_score_label, false, false, 0);
+ update_score_cb (0);
+
+ var status_alignment = new Gtk.Alignment (1.0f, 0.5f, 0.0f, 0.0f);
+ status_alignment.add (status_box);
+ status_alignment.show();
+
+ var status_item = new Gtk.ToolItem ();
+ status_item.set_expand (true);
+ status_item.add (status_alignment);
+ status_item.show ();
+
+ toolbar.insert (status_item, -1);
+
+ /* Create a clutter renderer widget */
+ clutter_embed = new GtkClutter.Embed ();
+ clutter_embed.show ();
+ vbox.pack_start (clutter_embed, true, true);
+
+ stage = (Clutter.Stage) clutter_embed.get_stage ();
+ stage.color = Clutter.Color.from_string ("#000000"); /* background color is black */
+
+ /* Initialize the options for sizes */
+ sizes = new Size[3];
+ sizes[0] = { "small", _("Small"), 6, 5 };
+ sizes[1] = { "normal", _("Normal"), 15, 10 };
+ sizes[2] = { "large", _("Large"), 20, 15 };
+
+ /* Create an instance of game with initial values for row, column and color */
+ game = new Game (get_size ().rows, get_size ().columns, settings.get_int ("colors"));
+
+ /* Game score change will be sent to the main window and show in the score label */
+ game.update_score.connect (update_score_cb);
+ game.complete.connect (complete_cb);
+
+ /* Create an instance of game view. This follow the Model-View-Controller paradigm */
+ view = new GameView ();
+ /* Initialize the themes needed by actors */
+ view.theme_name = settings.get_string ("theme");
+ view.is_zealous = settings.get_boolean ("zealous");
+ view.game = game;
+ stage.add_actor (view);
+
+ /* Request an appropriate size for the game view */
+ stage.set_size (view.width, view.height);
+ clutter_embed.set_size_request ((int) stage.width, (int) stage.height);
+
+ /* When the mouse leaves the window we need to update the view */
+ clutter_embed.leave_notify_event.connect (view.board_left_cb);
+
+ high_scores = new GnomeGamesSupport.Scores ("swell-foop",
+ new GnomeGamesSupport.ScoresCategory[0],
+ null, null, 0,
+ GnomeGamesSupport.ScoreStyle.PLAIN_DESCENDING);
+ high_scores.set_category (settings.get_string ("size"));
+ high_scores.add_category ("small", _("Small"));
+ high_scores.add_category ("normal", _("Normal"));
+ high_scores.add_category ("large", _("Large"));
+ }
+
+ private Size get_size ()
+ {
+ for (var i = 0; i < sizes.length; i++)
+ {
+ if (sizes[i].id == settings.get_string ("size"))
+ return sizes[i];
+ }
+
+ return sizes[0];
+ }
+
+ private void update_score_cb (int points_awarded)
+ {
+ var score = 0;
+ if (game != null)
+ score = game.score;
+
+ /* I left one more blank space at the end to make the score not too close to the window border */
+ current_score_label.set_text ("Score: %4u ".printf (score));
+ }
+
+ private void complete_cb ()
+ {
+ high_scores.add_plain_score (game.score);
+ }
+
+ protected override void shutdown ()
+ {
+ base.shutdown ();
+
+ /* Record the score if the game isn't over. */
+ if (game != null && game.score > 0)
+ high_scores.add_plain_score (game.score);
+ }
+
+ protected override void activate ()
+ {
+ main_window.present ();
+ }
+
+ public void preferences_cb ()
+ {
+ /* Show existing dialog */
+ if (preferences_dialog != null)
+ {
+ preferences_dialog.present ();
+ return;
+ }
+
+ var preferences_builder = new Gtk.Builder ();
+ try
+ {
+ preferences_builder.add_from_file (Path.build_filename (PKGDATADIR, "preferences.ui", null));
+ }
+ catch (Error e)
+ {
+ warning ("Could not load preferences UI: %s", e.message);
+ }
+
+ preferences_dialog = (Gtk.Dialog) preferences_builder.get_object ("preferences");
+
+ /* Theme */
+ var theme_combo = preferences_builder.get_object ("theme-selector") as Gtk.ComboBox;
+ var model = (Gtk.ListStore) theme_combo.model;
+ Gtk.TreeIter iter;
+ model.append (out iter);
+ model.set (iter, 0, _("Colors"), 1, "colors", -1);
+ if (settings.get_string ("theme") == "colors")
+ theme_combo.set_active_iter (iter);
+ model.append (out iter);
+ model.set (iter, 0, _("Shapes and Colors"), 1, "shapesandcolors", -1);
+ if (settings.get_string ("theme") == "shapesandcolors")
+ theme_combo.set_active_iter (iter);
+
+ /* Board size */
+ var size_combo = preferences_builder.get_object ("size-selector") as Gtk.ComboBox;
+ model = (Gtk.ListStore) size_combo.model;
+ for (int i = 0; i < sizes.length; i++)
+ {
+ model.append (out iter);
+ model.set (iter, 0, sizes[i].name, 1, sizes[i].id, -1);
+ if (settings.get_string ("size") == sizes[i].id)
+ size_combo.set_active_iter (iter);
+ }
+
+ /* Number of colors */
+ ((Gtk.SpinButton) preferences_builder.get_object ("colors-spinner")).value = settings.get_int ("colors");
+
+ /* Zealous moves */
+ ((Gtk.CheckButton) preferences_builder.get_object ("zealous-checkbox")).active = settings.get_boolean ("zealous");
+
+ preferences_builder.connect_signals (this);
+ preferences_dialog.response.connect (preferences_response_cb);
+ preferences_dialog.present ();
+ }
+
+ [CCode (cname = "G_MODULE_EXPORT select_theme", instance_pos = -1)]
+ public void select_theme (Gtk.ComboBox theme_combo)
+ {
+ Gtk.TreeIter iter;
+ if (!theme_combo.get_active_iter (out iter))
+ return;
+ string new_theme;
+ theme_combo.model.get (iter, 1, out new_theme, -1);
+
+ if (new_theme == settings.get_string ("theme"))
+ return;
+
+ settings.set_string ("theme", new_theme);
+
+ view.theme_name = new_theme;
+ }
+
+ [CCode (cname = "G_MODULE_EXPORT set_zealous_animation", instance_pos = -1)]
+ public void set_zealous_animation (Gtk.CheckButton button)
+ {
+ settings.set_boolean ("zealous", button.active);
+ }
+
+ [CCode (cname = "G_MODULE_EXPORT update_size", instance_pos = -1)]
+ public void update_size (Gtk.ComboBox size_combo)
+ {
+ Gtk.TreeIter iter;
+ if (!size_combo.get_active_iter (out iter))
+ return;
+ string new_size;
+ size_combo.model.get (iter, 1, out new_size, -1);
+
+ if (new_size == settings.get_string ("size"))
+ return;
+
+ settings.set_string ("size", new_size);
+ high_scores.set_category (new_size);
+ new_game ();
+ }
+
+ [CCode (cname = "G_MODULE_EXPORT update_colors", instance_pos = -1)]
+ public void update_colors (Gtk.SpinButton button)
+ {
+ int new_colors = (int) button.get_value();
+
+ if (new_colors == settings.get_int ("colors"))
+ return;
+
+ settings.set_int ("colors", new_colors);
+ new_game ();
+ }
+
+ private void preferences_response_cb ()
+ {
+ preferences_dialog.destroy ();
+ preferences_dialog = null;
+ }
+
+ public void show ()
+ {
+ main_window.show ();
+ }
+
+ private void new_game_cb ()
+ {
+ new_game ();
+ }
+
+ private void scores_cb ()
+ {
+ var scores_dialog = new GnomeGamesSupport.ScoresDialog (main_window, high_scores, _("Swell Foop Scores"));
+ scores_dialog.set_category_description (_("Size:"));
+ scores_dialog.run ();
+ scores_dialog.destroy ();
+ }
+
+ private void quit_cb ()
+ {
+ main_window.destroy ();
+ }
+
+ private void help_cb ()
+ {
+ try
+ {
+ Gtk.show_uri (main_window.get_screen (), "help:swell-foop", Gtk.get_current_event_time ());
+ }
+ catch (Error e)
+ {
+ warning ("Failed to show help: %s", e.message);
+ }
+ }
+
+ private void about_cb ()
+ {
+ string[] authors = { "Tim Horton", "Sophia Yu", null };
+ string[] artists = { "Tim Horton", null };
+ string[] documenters = { null };
+
+ Gtk.show_about_dialog (main_window,
+ "program-name", _("Swell Foop"),
+ "version", VERSION,
+ "comments",
+ _("I want to play that game! You know, they all light-up and you click on them and they vanish!\n\nSwell Foop is a part of GNOME Games."),
+ "copyright", _("Copyright \xc2\xa9 2009 Tim Horton"),
+ "license", GnomeGamesSupport.get_license (_("Swell Foop")),
+ "wrap-license", true,
+ "authors", authors,
+ "artists", artists,
+ "documenters", documenters,
+ "translator-credits", _("translator-credits"),
+ "logo-icon-name", "gnome-swell-foop",
+ "website", "http://www.gnome.org/projects/gnome-games",
+ "website-label", _("GNOME Games web site"),
+ null);
+ }
+
+ public void new_game ()
+ {
+ game = new Game (get_size ().rows,
+ get_size ().columns,
+ settings.get_int ("colors"));
+ game.update_score.connect (update_score_cb);
+ game.complete.connect (complete_cb);
+ view.theme_name = settings.get_string ("theme");
+ view.game = game;
+ view.is_zealous = settings.get_boolean ("zealous");
+
+ stage.set_size (view.width, view.height);
+ clutter_embed.set_size_request ( (int) stage.width, (int) stage.height);
+
+ update_score_cb (0);
+ }
+
+ 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);
+
+ GnomeGamesSupport.scores_startup ();
+
+ var context = new OptionContext ("");
+
+ context.add_group (Gtk.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 (_("Swell Foop"));
+
+ Gtk.Window.set_default_icon_name ("swellfoop");
+
+ try
+ {
+ GtkClutter.init_with_args (ref args, "", new OptionEntry[0], null);
+ }
+ catch (Error e)
+ {
+ var dialog = new Gtk.MessageDialog (null, Gtk.DialogFlags.MODAL, Gtk.MessageType.ERROR, Gtk.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;
+ }
+
+ var app = new SwellFoop ();
+ return app.run (args);
+ }
+}
+
+/* An array will store multiply game size options. */
+public struct Size
+{
+ public string id;
+ public string name;
+ public int columns;
+ public int rows;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]