[gnome-klotski] Separate app and window.
- From: Arnaud Bonatti <arnaudb src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-klotski] Separate app and window.
- Date: Thu, 15 Oct 2015 04:34:47 +0000 (UTC)
commit 407b335aebf043705449b149ff04a8b217c93897
Author: Arnaud Bonatti <arnaud bonatti gmail com>
Date: Sun Oct 11 05:54:17 2015 +0200
Separate app and window.
data/klotski.ui | 21 +-
po/POTFILES.in | 1 +
po/POTFILES.skip | 1 +
src/Makefile.am | 1 +
src/gnome-klotski.vala | 855 +---------------------------------------------
src/klotski-window.vala | 836 +++++++++++++++++++++++++++++++++++++++++++++
src/score-dialog.vala | 2 +-
7 files changed, 871 insertions(+), 846 deletions(-)
---
diff --git a/data/klotski.ui b/data/klotski.ui
index 10dab99..62fb088 100644
--- a/data/klotski.ui
+++ b/data/klotski.ui
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk+" version="3.12"/>
- <object class="GtkPopover" id="puzzles-popover">
+ <object class="GtkPopover" id="puzzles_popover">
<property name="visible">False</property>
<property name="name">puzzles-popover</property>
<child>
@@ -30,7 +30,7 @@
</object>
</child>
<child>
- <object class="GtkStack" id="stack-packs">
+ <object class="GtkStack" id="stack_packs">
<property name="name">stack-packs</property>
<property name="visible">True</property>
<child>
@@ -88,7 +88,7 @@
</object>
</child>
<child>
- <object class="GtkStack" id="stack-puzzles"> <!-- GtkScrolledWindow children are here for when big
text -->
+ <object class="GtkStack" id="stack_puzzles"> <!-- GtkScrolledWindow children are here for when big
text -->
<property name="visible">True</property>
<property name="homogeneous">True</property>
<property name="height-request">270</property>
@@ -99,7 +99,7 @@
<property name="hscrollbar-policy">never</property>
<style><class name="treeview-container"/></style>
<child>
- <object class="GtkTreeView" id="treeview-huarong">
+ <object class="GtkTreeView" id="treeview_huarong">
<property name="visible">True</property>
<property name="headers-visible">False</property>
<property name="activate-on-single-click">True</property>
@@ -143,7 +143,7 @@
<property name="hscrollbar-policy">never</property>
<style><class name="treeview-container"/></style>
<child>
- <object class="GtkTreeView" id="treeview-challenge">
+ <object class="GtkTreeView" id="treeview_challenge">
<property name="visible">True</property>
<property name="headers-visible">False</property>
<property name="activate-on-single-click">True</property>
@@ -187,7 +187,7 @@
<property name="hscrollbar-policy">never</property>
<style><class name="treeview-container"/></style>
<child>
- <object class="GtkTreeView" id="treeview-skill">
+ <object class="GtkTreeView" id="treeview_skill">
<property name="visible">True</property>
<property name="headers-visible">False</property>
<property name="activate-on-single-click">True</property>
@@ -263,12 +263,15 @@
</object>
</child>
</object>
- <object class="GtkApplicationWindow" id="window">
+ <template class="KlotskiWindow" parent="GtkApplicationWindow">
<!-- <initial-focus name=""/> -->
<property name="title" translatable="yes">Klotski</property>
<property name="width-request">600</property>
<property name="height-request">400</property>
<property name="border-width">25</property> <!-- TODO a view margin -->
+ <signal name="size_allocate" handler="on_size_allocate"/>
+ <signal name="window_state_event" handler="on_window_state_event"/>
+ <signal name="destroy" handler="on_destroy"/>
<child type="titlebar">
<object class="GtkHeaderBar" id="headerbar">
<property name="visible">True</property>
@@ -297,7 +300,7 @@
<property name="can-focus">True</property>
<property name="focus-on-click">False</property>
<property name="direction">down</property>
- <property name="popover">puzzles-popover</property>
+ <property name="popover">puzzles_popover</property>
</object>
<packing>
<property name="pack-type">end</property>
@@ -308,5 +311,5 @@
<child>
<placeholder/>
</child>
- </object>
+ </template>
</interface>
diff --git a/po/POTFILES.in b/po/POTFILES.in
index d4cde8a..c973e7e 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -8,5 +8,6 @@ data/gnome-klotski.desktop.in
[type: gettext/glade]data/klotski-scores.ui
data/org.gnome.klotski.gschema.xml
src/gnome-klotski.vala
+src/klotski-window.vala
src/puzzle-view.vala
src/score-dialog.vala
diff --git a/po/POTFILES.skip b/po/POTFILES.skip
index 04d2b4f..996c341 100644
--- a/po/POTFILES.skip
+++ b/po/POTFILES.skip
@@ -1,3 +1,4 @@
src/gnome-klotski.c
+src/klotski-window.c
src/puzzle-view.c
src/score-dialog.c
diff --git a/src/Makefile.am b/src/Makefile.am
index bc4c005..e56d099 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -6,6 +6,7 @@ gnome_klotski_SOURCES = \
config.vapi \
gnome-klotski.vala \
history.vala \
+ klotski-window.vala \
puzzle.vala \
puzzle-view.vala \
score-dialog.vala \
diff --git a/src/gnome-klotski.vala b/src/gnome-klotski.vala
index fee3392..dfa06a0 100644
--- a/src/gnome-klotski.vala
+++ b/src/gnome-klotski.vala
@@ -10,459 +10,34 @@
using Gtk;
-/* Puzzle Info */
-private struct LevelInfo
-{
- string name;
- int group;
- int width;
- int height;
- string data;
-}
-
public class Klotski : Gtk.Application
{
- /* Settings */
- private GLib.Settings settings;
- private bool is_tiled;
- private bool is_maximized;
- private int window_width;
- private int window_height;
-
- private const string KEY_LEVEL = "level";
-
- /* Widgets */
- private ApplicationWindow window;
- private HeaderBar headerbar;
- private Stack stack_packs;
- private Stack stack_puzzles;
- private Popover puzzles_popover;
- private PuzzleView view;
-
- /* Actions, to disable or enable */
- private SimpleAction prev_pack;
- private SimpleAction next_pack;
- private SimpleAction prev_puzzle;
- private SimpleAction next_puzzle;
- private SimpleAction start_game;
-
- /* The game being played */
- private Puzzle puzzle;
-
- private int current_pack = -1;
- private int current_level = -1;
-
- private History history;
-
- /* The "puzzle name" remarks provide context for translation. */
- private Gtk.ListStore liststore_huarong;
- private Gtk.ListStore liststore_challenge;
- private Gtk.ListStore liststore_skill;
- private TreeIter[] puzzles_items;
- public const LevelInfo level[] =
- {
- /* puzzle name */
- {N_("Only 18 Steps"), 0,
- 6, 9,
- "######" +
- "#a**b#" +
- "#m**n#" +
- "#cdef#" +
- "#ghij#" +
- "#k l#" +
- "##--##" +
- " .." +
- " .."},
-
- /* puzzle name */
- {N_("Daisy"), 0,
- 6, 9,
- "######" +
- "#a**b#" +
- "#a**b#" +
- "#cdef#" +
- "#zghi#" +
- "#j k#" +
- "##--##" +
- " .." +
- " .."},
-
- /* puzzle name */
- {N_("Violet"), 0,
- 6, 9,
- "######" +
- "#a**b#" +
- "#a**b#" +
- "#cdef#" +
- "#cghi#" +
- "#j k#" +
- "##--##" +
- " .." +
- " .."},
-
- /* puzzle name */
- {N_("Poppy"), 0,
- 6, 9,
- "######" +
- "#a**b#" +
- "#a**b#" +
- "#cdde#" +
- "#fghi#" +
- "#j k#" +
- "##--##" +
- " .." +
- " .."},
-
- /* puzzle name */
- {N_("Pansy"), 0,
- 6, 9,
- "######" +
- "#a**b#" +
- "#a**b#" +
- "#cdef#" +
- "#cghf#" +
- "#i j#" +
- "##--##" +
- " .." +
- " .."},
-
- /* puzzle name */
- {N_("Snowdrop"), 0,
- 6, 9,
- "######" +
- "#a**b#" +
- "#a**b#" +
- "#cdde#" +
- "#cfgh#" +
- "#i j#" +
- "##--##" +
- " .." +
- " .."},
-
- /* puzzle name - sometimes called "Le'Ane Rouge" */
- {N_("Red Donkey"), 0,
- 6, 9,
- "######" +
- "#a**b#" +
- "#a**b#" +
- "#cdde#" +
- "#cfge#" +
- "#h i#" +
- "##--##" +
- " .." +
- " .."},
-
- /* puzzle name */
- {N_("Trail"), 0,
- 6, 9,
- "######" +
- "#a**c#" +
- "#a**c#" +
- "#eddg#" +
- "#hffj#" +
- "# ii #" +
- "##--##" +
- " .." +
- " .."},
-
- /* puzzle name */
- {N_("Ambush"), 0,
- 6, 9,
- "######" +
- "#a**c#" +
- "#d**e#" +
- "#dffe#" +
- "#ghhi#" +
- "# jj #" +
- "##--##" +
- " .." +
- " .."},
-
- /* puzzle name */
- {N_("Agatka"), 1,
- 7, 7,
- ".. " +
- ". " +
- "#####--" +
- "#**aab-" +
- "#*ccde#" +
- "#fgh #" +
- "#######"},
-
- /* puzzle name */
- {N_("Success"), 1,
- 9, 6,
- "####### " +
- "#**bbc# " +
- "#defgh# " +
- "#ijkgh- " +
- "#llk # " +
- "#######.."},
-
- /* puzzle name */
- {N_("Bone"), 1,
- 6, 9,
- "######" +
- "#abc*#" +
- "# dd*#" +
- "# ee*#" +
- "# fgh#" +
- "##-###" +
- " ." +
- " ." +
- " ."},
-
- /* puzzle name */
- {N_("Fortune"), 1,
- 7, 10,
- " .." +
- " . " +
- "####-. " +
- "#ab - " +
- "#ccd # " +
- "#ccd # " +
- "#**ee# " +
- "#*fgh# " +
- "#*iih# " +
- "###### "},
-
- /* puzzle name */
- {N_("Fool"), 1,
- 10, 6,
- " ########" +
- " -aabc #" +
- " #aabdef#" +
- " #ijggef#" +
- " #klhh**#" +
- "..########"},
-
- /* puzzle name */
- {N_("Solomon"), 1,
- 7, 9,
- " . " +
- ".. " +
- "#--####" +
- "# aab#" +
- "# cdfb#" +
- "#hcefg#" +
- "#hijk*#" +
- "#hll**#" +
- "#######"},
-
- /* puzzle name */
- {N_("Cleopatra"), 1,
- 6, 8,
- "######" +
- "#abcd#" +
- "#**ee#" +
- "#f*g #" +
- "#fh i-" +
- "####--" +
- " .." +
- " ."},
-
- /* puzzle name */
- {N_("Shark"), 1,
- 11, 8,
- "######## " +
- "#nrr s # " +
- "#n*op q# " +
- "#***jml# " +
- "#hhijkl# " +
- "#ffcddg- " +
- "#abcdde- . " +
- "########..."},
-
- /* puzzle name */
- {N_("Rome"), 1,
- 8, 8,
- "########" +
- "#abcc**#" +
- "#ddeef*#" +
- "#ddghfi#" +
- "# jki#" +
- "#--#####" +
- " .. " +
- " . "},
-
- /* puzzle name */
- {N_("Pennant Puzzle"), 1,
- 6, 9,
- "######" +
- "#**aa#" +
- "#**bb#" +
- "#de #" +
- "#fghh#" +
- "#fgii#" +
- "#--###" +
- " .." +
- " .."},
-
- /* puzzle name */
- {N_("Ithaca"), 2,
- 19, 19,
- ".aaaaaaaaaaaaaaaaab" +
- ".. cddeffffffffffb" +
- " .. cddeffffffffffb" +
- " . cddeffffffffffb" +
- "ggg-############hhb" +
- "ggg- ABCDEFFGH#hhb" +
- "ggg- FFIJ#hhb" +
- "ggg# KLMJ#hhb" +
- "ggg#NNNNOOOPQMJ#hhb" +
- "ggg#NNNNOOOP*RS#hhb" +
- "ggg#TTTTTUVW**X#hhb" +
- "ggg#YZ12222W3**#hhb" +
- "ggg#YZ12222W34*#iib" +
- "jjj#YZ155555367#klb" +
- "jjj#############mmb" +
- "jjjnooooooooooppppb" +
- "jjjqooooooooooppppb" +
- " rrrssssppppb" +
- "ttttttuvvvvvvvwwwwx"},
-
- /* puzzle name */
- {N_("Pelopones"), 2,
- 9, 8,
- "#########" +
- "#abbb***#" +
- "#abbb*c*#" +
- "#adeefgg#" +
- "# eefhh#" +
- "#... ihh#" +
- "#. . ihh#" +
- "#########"},
-
- /* puzzle name */
- {N_("Transeuropa"), 2,
- 15, 8,
- " ###########" +
- " -AAAAABBCC#" +
- " - DEFGHI#" +
- " # DEFGJI#" +
- " # KEFGLI#" +
- " # KEFG*I#" +
- " . # MM****#" +
- "....###########"},
-
- /* puzzle name */
- {N_("Lodzianka"), 2,
- 9, 7,
- "#########" +
- "#**abbcc#" +
- "#**abbdd#" +
- "#eefgh #" +
- "#iiijk..#" +
- "#iiijk..#" +
- "#########"},
-
- /* puzzle name */
- {N_("Polonaise"), 2,
- 7, 7,
- "#######" +
- "#aab**#" +
- "#aabc*#" +
- "#defgg#" +
- "#..fhh#" +
- "# .ihh#" +
- "#######"},
-
- /* puzzle name */
- {N_("Baltic Sea"), 2,
- 6, 8,
- "######" +
- "#.abc#" +
- "#.dec#" +
- "#fggc#" +
- "#fhhi#" +
- "#fjk*#" +
- "#flk*#" +
- "######"},
-
- /* puzzle name */
- {N_("American Pie"), 2,
- 10, 12,
- "##########" +
- "#a*bcdefg#" +
- "#**bhhhhg#" +
- "#*iijjkkg#" +
- "#liimnoop#" +
- "#qiirrr #" +
- "#qstuvv #" +
- "#qwwxvv #" +
- "######--##" +
- " ." +
- " .." +
- " . "},
-
- /* puzzle name */
- {N_("Traffic Jam"), 2,
- 10, 7,
- "######## " +
- "#** ffi# " +
- "#** fgh# " +
- "#aacehh# " +
- "#bbdjlm- " +
- "#bddklm-.." +
- "########.."},
-
- /* puzzle name */
- {N_("Sunshine"), 2,
- 17, 22,
- " ... " +
- " .. .. " +
- " . . " +
- " .. .. " +
- " ... " +
- "######-----######" +
- "#hh0iilltmmpp;qq#" +
- "#hh,iill mmpp:qq#" +
- "#2y{45v s w89x/z#" +
- "#jj6kkaa nnoo<rr#" +
- "#jj7kkaaunnoo>rr#" +
- "#33333TTJWW11111#" +
- "#33333TTJWW11111#" +
- "#33333GG HH11111#" +
- "#33333YYIgg11111#" +
- "#33333YYIgg11111#" +
- "#ddFeeA***BffOZZ#" +
- "#ddFee** **ffOZZ#" +
- "#MMKQQ* *PPS^^#" +
- "#VVLXX** **bbRcc#" +
- "#VVLXXD***EbbRcc#" +
- "#################"}
- };
-
- private const OptionEntry[] option_entries =
+ private const OptionEntry [] option_entries =
{
{ "version", 'v', 0, OptionArg.NONE, null, N_("Print release version and exit"), null },
{ null }
};
- private const GLib.ActionEntry app_actions[] =
+ private const GLib.ActionEntry action_entries [] =
{
{"scores", scores_cb},
{"help", help_cb},
{"about", about_cb},
- {"quit", quit}
- };
- private const GLib.ActionEntry win_actions[] =
- {
- {"prev-pack", prev_pack_cb},
- {"next-pack", next_pack_cb},
- {"prev-puzzle", prev_puzzle_cb},
- {"next-puzzle", next_puzzle_cb},
- {"start-game", start_puzzle_cb}
+ {"quit", quit_cb}
};
- public static int main (string[] args)
+ /*\
+ * * Application init
+ \*/
+
+ public static int main (string [] args)
{
Intl.setlocale (LocaleCategory.ALL, "");
Intl.bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
Intl.bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
Intl.textdomain (GETTEXT_PACKAGE);
- var app = new Klotski ();
+ Klotski app = new Klotski ();
return app.run (args);
}
@@ -481,8 +56,6 @@ public class Klotski : Gtk.Application
stdout.printf ("%1$s %2$s\n", "gnome-klotski", VERSION);
return Posix.EXIT_SUCCESS;
}
-
- /* Activate */
return -1;
}
@@ -493,146 +66,20 @@ public class Klotski : Gtk.Application
Environment.set_application_name (_("Klotski"));
Window.set_default_icon_name ("gnome-klotski");
- var css_provider = new CssProvider ();
- css_provider.load_from_resource ("/org/gnome/klotski/ui/klotski.css");
- StyleContext.add_provider_for_screen (Gdk.Screen.get_default (), css_provider,
STYLE_PROVIDER_PRIORITY_APPLICATION);
-
- settings = new GLib.Settings ("org.gnome.klotski");
+ add_action_entries (action_entries, this);
- var builder = new Builder.from_resource ("/org/gnome/klotski/ui/klotski.ui");
- window = builder.get_object ("window") as ApplicationWindow;
- window.size_allocate.connect (size_allocate_cb);
- window.window_state_event.connect (window_state_event_cb);
- window.set_default_size (settings.get_int ("window-width"), settings.get_int ("window-height"));
- if (settings.get_boolean ("window-is-maximized"))
- window.maximize ();
+ add_window (new KlotskiWindow ());
- add_action_entries (app_actions, this);
- window.add_action_entries (win_actions, this);
- prev_pack = window.lookup_action ("prev-pack") as SimpleAction;
- next_pack = window.lookup_action ("next-pack") as SimpleAction;
- prev_puzzle = window.lookup_action ("prev-puzzle") as SimpleAction;
- next_puzzle = window.lookup_action ("next-puzzle") as SimpleAction;
- start_game = window.lookup_action ("start-game") as SimpleAction;
// set_accels_for_action ("win.start-game", {"<Primary>n"}); /* or <Primary>r ? or both ? */
set_accels_for_action ("win.prev-puzzle", {"Up"}); // TODO
set_accels_for_action ("win.next-puzzle", {"Down"}); // TODO a weird behaviour exists when you
first change puzzle pack, then go to
set_accels_for_action ("win.prev-pack", {"Page_Up"}); // TODO the first/last one, click on a
puzzle, and immediatly hit Up or Down arrows.
set_accels_for_action ("win.next-pack", {"Page_Down"}); // TODO that makes these keybindings
sometimes act strangely, but they’re good.
-
- string histfile = Path.build_filename (Environment.get_user_data_dir (), "gnome-klotski", "history");
-
- history = new History (histfile);
- history.load ();
-
- headerbar = builder.get_object ("headerbar") as HeaderBar;
- stack_packs = builder.get_object ("stack-packs") as Stack;
- stack_puzzles = builder.get_object ("stack-puzzles") as Stack;
- puzzles_popover = builder.get_object ("puzzles-popover") as Popover;
-
- // name, active, puzzle number (or -1), sensitive=false CSS hack
- liststore_huarong = new Gtk.ListStore (4, typeof (string), typeof (bool), typeof (int), typeof
(bool));
- liststore_challenge = new Gtk.ListStore (4, typeof (string), typeof (bool), typeof (int), typeof
(bool));
- liststore_skill = new Gtk.ListStore (4, typeof (string), typeof (bool), typeof (int), typeof (bool));
-
- puzzles_items = new TreeIter[level.length];
- for (var i = 0; i < level.length; i++)
- {
- switch (level[i].group)
- {
- case 0:
- liststore_huarong.append (out puzzles_items[i]);
- liststore_huarong.set (puzzles_items[i],
- 0, _(level[i].name),
- 1, false,
- 2, i,
- 3, false);
- break;
- case 1:
- liststore_challenge.append (out puzzles_items[i]);
- liststore_challenge.set (puzzles_items[i],
- 0, _(level[i].name),
- 1, false,
- 2, i,
- 3, false);
- break;
- case 2:
- liststore_skill.append (out puzzles_items[i]);
- liststore_skill.set (puzzles_items[i],
- 0, _(level[i].name),
- 1, false,
- 2, i,
- 3, false);
- break;
- }
- }
-
- var treeview_huarong = builder.get_object ("treeview-huarong") as TreeView;
- var treeview_challenge = builder.get_object ("treeview-challenge") as TreeView;
- var treeview_skill = builder.get_object ("treeview-skill") as TreeView;
-
- treeview_huarong.set_model (liststore_huarong);
- treeview_challenge.set_model (liststore_challenge);
- treeview_skill.set_model (liststore_skill);
-
- treeview_huarong.row_activated.connect (level_huarong_cb);
- treeview_challenge.row_activated.connect (level_challenge_cb);
- treeview_skill.row_activated.connect (level_skill_cb);
-
- view = new PuzzleView ();
- view.halign = Align.FILL;
- view.can_focus = true;
- view.show ();
- window.add (view);
-
- load_solved_state (); // TODO use GSettings, or the history…
-
- current_level = settings.get_int (KEY_LEVEL).clamp (0, level.length - 1);
- puzzles_popover.show.connect (() => { update_popover (true); });
- update_popover (true); // or “Start Over” logically complains
-
- start_puzzle ();
- add_window (window);
}
protected override void activate ()
{
- window.present ();
- }
-
- protected override void shutdown ()
- {
- base.shutdown ();
-
- /* Save game state */
- settings.set_int (KEY_LEVEL, current_level);
-
- /* Save window state */
- settings.set_int ("window-width", window_width);
- settings.set_int ("window-height", window_height);
- settings.set_boolean ("window-is-maximized", is_maximized);
- }
-
- /*\
- * * Window events
- \*/
-
- private void size_allocate_cb (Allocation allocation)
- {
- if (is_maximized || is_tiled)
- return;
- window_width = allocation.width;
- window_height = allocation.height;
- }
-
- private bool window_state_event_cb (Gdk.EventWindowState event)
- {
- if ((event.changed_mask & Gdk.WindowState.MAXIMIZED) != 0)
- is_maximized = (event.new_window_state & Gdk.WindowState.MAXIMIZED) != 0;
- /* We don’t save this state, but track it for saving size allocation */
- if ((event.changed_mask & Gdk.WindowState.TILED) != 0)
- is_tiled = (event.new_window_state & Gdk.WindowState.TILED) != 0;
- return false;
+ get_active_window ().present ();
}
/*\
@@ -641,14 +88,14 @@ public class Klotski : Gtk.Application
private void scores_cb ()
{
- show_scores (null);
+ ((KlotskiWindow) get_active_window ()).show_scores (null);
}
private void help_cb ()
{
try
{
- show_uri (window.get_screen (), "help:gnome-klotski", get_current_event_time ());
+ show_uri (get_active_window ().get_screen (), "help:gnome-klotski", get_current_event_time ());
}
catch (Error e)
{
@@ -658,10 +105,10 @@ public class Klotski : Gtk.Application
private void about_cb ()
{
- const string authors[] = { "Lars Rydlinge (original author)", "Robert Ancell (port to vala)", "John
Cheetham (port to vala)", null };
- const string documenters[] = { "Andrew Sobala", null };
+ const string authors [] = { "Lars Rydlinge (original author)", "Robert Ancell (port to vala)", "John
Cheetham (port to vala)", null };
+ const string documenters [] = { "Andrew Sobala", null };
- show_about_dialog (window,
+ show_about_dialog (get_active_window (),
"program-name", _("Klotski"),
"version", VERSION,
"comments", _("Sliding block puzzles"),
@@ -678,272 +125,8 @@ public class Klotski : Gtk.Application
null);
}
- /*\
- * * Popover’s buttons callbacks
- \*/
-
- private void prev_pack_cb ()
- {
- if (!puzzles_popover.visible)
- return;
- current_pack--;
- update_popover (false);
- }
-
- private void next_pack_cb ()
- {
- if (!puzzles_popover.visible)
- return;
- current_pack++;
- update_popover (false);
- }
-
- private void prev_puzzle_cb ()
- {
- if (!puzzles_popover.visible)
- return;
- current_level--;
- update_popover (true);
- start_puzzle ();
- }
-
- private void next_puzzle_cb ()
- {
- if (!puzzles_popover.visible)
- return;
- current_level++;
- update_popover (true);
- start_puzzle ();
- }
-
- private void start_puzzle_cb ()
- {
- TreeView tree = ((TreeView) (((ScrolledWindow) (stack_puzzles.get_children ().nth_data
(current_pack))).get_child ()));
- TreeModel model = tree.get_model ();
- TreeIter iter;
-
- if (tree.get_selection ().get_selected (out model, out iter))
- start_puzzle_from_iter ((Gtk.ListStore) model, iter);
- else
- start_puzzle ();
- puzzles_popover.hide ();
- }
-
- /*\
- * * Update popover
- \*/
-
- private void update_popover (bool make_current)
- {
- int current_level_pack;
- TreeIter iter = puzzles_items[current_level];
- if (liststore_huarong.iter_is_valid (iter)) // "slow"
- current_level_pack = 0;
- else if (liststore_challenge.iter_is_valid (iter)) // same here
- current_level_pack = 1;
- else
- current_level_pack = 2;
-
- if (make_current)
- current_pack = current_level_pack;
-
- /* select or not a level */
- TreeSelection selection = ((TreeView) (((ScrolledWindow) (stack_puzzles.get_children ().nth_data
(current_pack))).get_child ())).get_selection ();
- if (current_pack == current_level_pack)
- selection.select_iter (iter);
- else
- selection.unselect_all ();
-
- update_buttons_state ();
-
- /* update stacks */
- stack_packs.set_visible_child (stack_packs.get_children ().nth_data (current_pack));
- stack_puzzles.set_visible_child (stack_puzzles.get_children ().nth_data (current_pack));
- }
-
- private void update_buttons_state ()
- {
- prev_pack.set_enabled (current_pack > 0);
- next_pack.set_enabled (current_pack < 2);
-
- prev_puzzle.set_enabled (current_level > 0);
- next_puzzle.set_enabled (current_level < level.length - 1);
- }
-
- /*\
- * * Selecting puzzle by the treeview
- \*/
-
- private void level_huarong_cb (TreePath path, TreeViewColumn column)
- {
- level_cb (liststore_huarong, path, column);
- }
- private void level_challenge_cb (TreePath path, TreeViewColumn column)
- {
- level_cb (liststore_challenge, path, column);
- }
- private void level_skill_cb (TreePath path, TreeViewColumn column)
- {
- level_cb (liststore_skill, path, column);
- }
- private void level_cb (Gtk.ListStore liststore, TreePath path, TreeViewColumn column)
- {
- TreeIter iter;
-
- liststore.get_iter (out iter, path);
- start_puzzle_from_iter (liststore, iter);
- }
-
- /*\
- * * Creating and starting game
- \*/
-
- private void start_puzzle_from_iter (Gtk.ListStore model, TreeIter iter)
- {
- Value val;
- model.get_value (iter, 2, out val);
-
- int requested_level = (int) val;
- if (requested_level < 0)
- return;
-
- current_level = requested_level;
- update_buttons_state ();
- start_puzzle ();
- }
-
- private void start_puzzle ()
- {
- headerbar.set_title (_(level[current_level].name));
- puzzle = new Puzzle (level[current_level].width, level[current_level].height,
level[current_level].data);
- puzzle.moved.connect (puzzle_moved_cb); // TODO disconnect previous puzzle?
- view.puzzle = puzzle;
-
- update_moves_label ();
- start_game.set_enabled (false);
- }
-
- private void puzzle_moved_cb ()
- {
- update_moves_label ();
- }
-
- private void update_moves_label ()
- {
- start_game.set_enabled (true);
- headerbar.set_subtitle (_("Moves: %d").printf (puzzle.moves));
- if (puzzle.game_over ())
- {
- headerbar.set_title (_("Level completed."));
- game_score ();
- }
- }
-
- /*\
- * * Scores
- \*/
-
- private void game_score ()
- {
- /* Level is complete */
- var key = get_level_key (current_level);
- var keyfile = new KeyFile ();
- var filename = Path.build_filename (Environment.get_user_data_dir (), "gnome-klotski", "levels");
// filename:~/.local/share/gnome-klotski/levels
-
- try
- {
- keyfile.load_from_file (filename, KeyFileFlags.NONE);
- }
- catch (Error e)
- {
- }
-
- keyfile.set_boolean (key, "solved", true);
-
- try
- {
- FileUtils.set_contents (filename, keyfile.to_data ());
- }
- catch (Error e)
- {
- }
-
- puzzle_solved (puzzles_items[current_level], true);
-
- var date = new DateTime.now_local ();
- var entry = new HistoryEntry (date, current_level, puzzle.moves);
- history.add (entry);
- history.save ();
-
- show_scores (entry);
- }
-
- private void show_scores (HistoryEntry? selected_entry = null)
- {
- var dialog = new ScoreDialog (history, selected_entry);
- dialog.set_transient_for (window);
-
- /* var result = */ dialog.run ();
- dialog.destroy ();
- }
-
- private string get_level_key (int level_number)
- {
- /* Calculate the CRC of the level data */
- uint32 result = 0xFFFFFFFFu;
- var data = level[level_number].data;
- for (var i = 0; data[i] != '\0'; i++)
- {
- var octet = data[i];
- for (var j = 0; j < 8; j++)
- {
- if (((octet >> 7) ^ (result >> 31)) != 0)
- result = (result << 1) ^ 0x04c11db7;
- else
- result = (result << 1);
- result &= 0xFFFFFFFF;
- octet <<= 1;
- }
- }
-
- return "%08X".printf (~result);
- }
-
- private void load_solved_state ()
- {
- var keyfile = new KeyFile ();
- var filename = Path.build_filename (Environment.get_user_data_dir (), "gnome-klotski", "levels");
- try
- {
- keyfile.load_from_file (filename, KeyFileFlags.NONE);
- }
- catch (Error e)
- {
- }
-
- for (var i = 0; i < level.length; i++)
- {
- var key = get_level_key (i);
- var value = false;
- try
- {
- value = keyfile.get_boolean (key, "solved");
- }
- catch (Error e)
- {
- }
-
- puzzle_solved (puzzles_items[i], value);
- }
- }
-
- private void puzzle_solved (TreeIter iter, bool solved)
+ private void quit_cb ()
{
- if (liststore_huarong.iter_is_valid (iter)) // "slow"
- liststore_huarong.set (iter, 1, solved);
- else if (liststore_challenge.iter_is_valid (iter)) // same here
- liststore_challenge.set (iter, 1, solved);
- else
- liststore_skill.set (iter, 1, solved);
+ get_active_window ().destroy ();
}
}
diff --git a/src/klotski-window.vala b/src/klotski-window.vala
new file mode 100644
index 0000000..b99e44e
--- /dev/null
+++ b/src/klotski-window.vala
@@ -0,0 +1,836 @@
+/*
+ * Copyright (C) 2010-2013 Robert Ancell
+ *
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 2 of the License, or (at your option) any later
+ * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
+ * license.
+ */
+
+using Gtk;
+
+/* Puzzle Info */
+private struct LevelInfo
+{
+ string name;
+ int group;
+ int width;
+ int height;
+ string data;
+}
+
+[GtkTemplate (ui = "/org/gnome/klotski/ui/klotski.ui")]
+public class KlotskiWindow : ApplicationWindow
+{
+ /* Settings */
+ private GLib.Settings settings;
+ private bool is_tiled;
+ private bool window_is_maximized;
+ private int window_width;
+ private int window_height;
+
+ private const string KEY_LEVEL = "level";
+
+ /* Widgets */
+ [GtkChild] private HeaderBar headerbar;
+ [GtkChild] private Stack stack_packs;
+ [GtkChild] private Stack stack_puzzles;
+ [GtkChild] private Popover puzzles_popover;
+ private PuzzleView view;
+
+ [GtkChild] private TreeView treeview_huarong;
+ [GtkChild] private TreeView treeview_challenge;
+ [GtkChild] private TreeView treeview_skill;
+
+ /* Actions, to disable or enable */
+ private SimpleAction prev_pack;
+ private SimpleAction next_pack;
+ private SimpleAction prev_puzzle;
+ private SimpleAction next_puzzle;
+ private SimpleAction start_game;
+
+ /* The game being played */
+ private Puzzle puzzle;
+
+ private int current_pack = -1;
+ private int current_level = -1;
+
+ private History history;
+
+ /* The "puzzle name" remarks provide context for translation. */
+ private Gtk.ListStore liststore_huarong;
+ private Gtk.ListStore liststore_challenge;
+ private Gtk.ListStore liststore_skill;
+ private TreeIter[] puzzles_items;
+ public const LevelInfo level[] =
+ {
+ /* puzzle name */
+ {N_("Only 18 Steps"), 0,
+ 6, 9,
+ "######" +
+ "#a**b#" +
+ "#m**n#" +
+ "#cdef#" +
+ "#ghij#" +
+ "#k l#" +
+ "##--##" +
+ " .." +
+ " .."},
+
+ /* puzzle name */
+ {N_("Daisy"), 0,
+ 6, 9,
+ "######" +
+ "#a**b#" +
+ "#a**b#" +
+ "#cdef#" +
+ "#zghi#" +
+ "#j k#" +
+ "##--##" +
+ " .." +
+ " .."},
+
+ /* puzzle name */
+ {N_("Violet"), 0,
+ 6, 9,
+ "######" +
+ "#a**b#" +
+ "#a**b#" +
+ "#cdef#" +
+ "#cghi#" +
+ "#j k#" +
+ "##--##" +
+ " .." +
+ " .."},
+
+ /* puzzle name */
+ {N_("Poppy"), 0,
+ 6, 9,
+ "######" +
+ "#a**b#" +
+ "#a**b#" +
+ "#cdde#" +
+ "#fghi#" +
+ "#j k#" +
+ "##--##" +
+ " .." +
+ " .."},
+
+ /* puzzle name */
+ {N_("Pansy"), 0,
+ 6, 9,
+ "######" +
+ "#a**b#" +
+ "#a**b#" +
+ "#cdef#" +
+ "#cghf#" +
+ "#i j#" +
+ "##--##" +
+ " .." +
+ " .."},
+
+ /* puzzle name */
+ {N_("Snowdrop"), 0,
+ 6, 9,
+ "######" +
+ "#a**b#" +
+ "#a**b#" +
+ "#cdde#" +
+ "#cfgh#" +
+ "#i j#" +
+ "##--##" +
+ " .." +
+ " .."},
+
+ /* puzzle name - sometimes called "Le'Ane Rouge" */
+ {N_("Red Donkey"), 0,
+ 6, 9,
+ "######" +
+ "#a**b#" +
+ "#a**b#" +
+ "#cdde#" +
+ "#cfge#" +
+ "#h i#" +
+ "##--##" +
+ " .." +
+ " .."},
+
+ /* puzzle name */
+ {N_("Trail"), 0,
+ 6, 9,
+ "######" +
+ "#a**c#" +
+ "#a**c#" +
+ "#eddg#" +
+ "#hffj#" +
+ "# ii #" +
+ "##--##" +
+ " .." +
+ " .."},
+
+ /* puzzle name */
+ {N_("Ambush"), 0,
+ 6, 9,
+ "######" +
+ "#a**c#" +
+ "#d**e#" +
+ "#dffe#" +
+ "#ghhi#" +
+ "# jj #" +
+ "##--##" +
+ " .." +
+ " .."},
+
+ /* puzzle name */
+ {N_("Agatka"), 1,
+ 7, 7,
+ ".. " +
+ ". " +
+ "#####--" +
+ "#**aab-" +
+ "#*ccde#" +
+ "#fgh #" +
+ "#######"},
+
+ /* puzzle name */
+ {N_("Success"), 1,
+ 9, 6,
+ "####### " +
+ "#**bbc# " +
+ "#defgh# " +
+ "#ijkgh- " +
+ "#llk # " +
+ "#######.."},
+
+ /* puzzle name */
+ {N_("Bone"), 1,
+ 6, 9,
+ "######" +
+ "#abc*#" +
+ "# dd*#" +
+ "# ee*#" +
+ "# fgh#" +
+ "##-###" +
+ " ." +
+ " ." +
+ " ."},
+
+ /* puzzle name */
+ {N_("Fortune"), 1,
+ 7, 10,
+ " .." +
+ " . " +
+ "####-. " +
+ "#ab - " +
+ "#ccd # " +
+ "#ccd # " +
+ "#**ee# " +
+ "#*fgh# " +
+ "#*iih# " +
+ "###### "},
+
+ /* puzzle name */
+ {N_("Fool"), 1,
+ 10, 6,
+ " ########" +
+ " -aabc #" +
+ " #aabdef#" +
+ " #ijggef#" +
+ " #klhh**#" +
+ "..########"},
+
+ /* puzzle name */
+ {N_("Solomon"), 1,
+ 7, 9,
+ " . " +
+ ".. " +
+ "#--####" +
+ "# aab#" +
+ "# cdfb#" +
+ "#hcefg#" +
+ "#hijk*#" +
+ "#hll**#" +
+ "#######"},
+
+ /* puzzle name */
+ {N_("Cleopatra"), 1,
+ 6, 8,
+ "######" +
+ "#abcd#" +
+ "#**ee#" +
+ "#f*g #" +
+ "#fh i-" +
+ "####--" +
+ " .." +
+ " ."},
+
+ /* puzzle name */
+ {N_("Shark"), 1,
+ 11, 8,
+ "######## " +
+ "#nrr s # " +
+ "#n*op q# " +
+ "#***jml# " +
+ "#hhijkl# " +
+ "#ffcddg- " +
+ "#abcdde- . " +
+ "########..."},
+
+ /* puzzle name */
+ {N_("Rome"), 1,
+ 8, 8,
+ "########" +
+ "#abcc**#" +
+ "#ddeef*#" +
+ "#ddghfi#" +
+ "# jki#" +
+ "#--#####" +
+ " .. " +
+ " . "},
+
+ /* puzzle name */
+ {N_("Pennant Puzzle"), 1,
+ 6, 9,
+ "######" +
+ "#**aa#" +
+ "#**bb#" +
+ "#de #" +
+ "#fghh#" +
+ "#fgii#" +
+ "#--###" +
+ " .." +
+ " .."},
+
+ /* puzzle name */
+ {N_("Ithaca"), 2,
+ 19, 19,
+ ".aaaaaaaaaaaaaaaaab" +
+ ".. cddeffffffffffb" +
+ " .. cddeffffffffffb" +
+ " . cddeffffffffffb" +
+ "ggg-############hhb" +
+ "ggg- ABCDEFFGH#hhb" +
+ "ggg- FFIJ#hhb" +
+ "ggg# KLMJ#hhb" +
+ "ggg#NNNNOOOPQMJ#hhb" +
+ "ggg#NNNNOOOP*RS#hhb" +
+ "ggg#TTTTTUVW**X#hhb" +
+ "ggg#YZ12222W3**#hhb" +
+ "ggg#YZ12222W34*#iib" +
+ "jjj#YZ155555367#klb" +
+ "jjj#############mmb" +
+ "jjjnooooooooooppppb" +
+ "jjjqooooooooooppppb" +
+ " rrrssssppppb" +
+ "ttttttuvvvvvvvwwwwx"},
+
+ /* puzzle name */
+ {N_("Pelopones"), 2,
+ 9, 8,
+ "#########" +
+ "#abbb***#" +
+ "#abbb*c*#" +
+ "#adeefgg#" +
+ "# eefhh#" +
+ "#... ihh#" +
+ "#. . ihh#" +
+ "#########"},
+
+ /* puzzle name */
+ {N_("Transeuropa"), 2,
+ 15, 8,
+ " ###########" +
+ " -AAAAABBCC#" +
+ " - DEFGHI#" +
+ " # DEFGJI#" +
+ " # KEFGLI#" +
+ " # KEFG*I#" +
+ " . # MM****#" +
+ "....###########"},
+
+ /* puzzle name */
+ {N_("Lodzianka"), 2,
+ 9, 7,
+ "#########" +
+ "#**abbcc#" +
+ "#**abbdd#" +
+ "#eefgh #" +
+ "#iiijk..#" +
+ "#iiijk..#" +
+ "#########"},
+
+ /* puzzle name */
+ {N_("Polonaise"), 2,
+ 7, 7,
+ "#######" +
+ "#aab**#" +
+ "#aabc*#" +
+ "#defgg#" +
+ "#..fhh#" +
+ "# .ihh#" +
+ "#######"},
+
+ /* puzzle name */
+ {N_("Baltic Sea"), 2,
+ 6, 8,
+ "######" +
+ "#.abc#" +
+ "#.dec#" +
+ "#fggc#" +
+ "#fhhi#" +
+ "#fjk*#" +
+ "#flk*#" +
+ "######"},
+
+ /* puzzle name */
+ {N_("American Pie"), 2,
+ 10, 12,
+ "##########" +
+ "#a*bcdefg#" +
+ "#**bhhhhg#" +
+ "#*iijjkkg#" +
+ "#liimnoop#" +
+ "#qiirrr #" +
+ "#qstuvv #" +
+ "#qwwxvv #" +
+ "######--##" +
+ " ." +
+ " .." +
+ " . "},
+
+ /* puzzle name */
+ {N_("Traffic Jam"), 2,
+ 10, 7,
+ "######## " +
+ "#** ffi# " +
+ "#** fgh# " +
+ "#aacehh# " +
+ "#bbdjlm- " +
+ "#bddklm-.." +
+ "########.."},
+
+ /* puzzle name */
+ {N_("Sunshine"), 2,
+ 17, 22,
+ " ... " +
+ " .. .. " +
+ " . . " +
+ " .. .. " +
+ " ... " +
+ "######-----######" +
+ "#hh0iilltmmpp;qq#" +
+ "#hh,iill mmpp:qq#" +
+ "#2y{45v s w89x/z#" +
+ "#jj6kkaa nnoo<rr#" +
+ "#jj7kkaaunnoo>rr#" +
+ "#33333TTJWW11111#" +
+ "#33333TTJWW11111#" +
+ "#33333GG HH11111#" +
+ "#33333YYIgg11111#" +
+ "#33333YYIgg11111#" +
+ "#ddFeeA***BffOZZ#" +
+ "#ddFee** **ffOZZ#" +
+ "#MMKQQ* *PPS^^#" +
+ "#VVLXX** **bbRcc#" +
+ "#VVLXXD***EbbRcc#" +
+ "#################"}
+ };
+
+ private const GLib.ActionEntry win_actions[] =
+ {
+ {"prev-pack", prev_pack_cb},
+ {"next-pack", next_pack_cb},
+ {"prev-puzzle", prev_puzzle_cb},
+ {"next-puzzle", next_puzzle_cb},
+ {"start-game", start_puzzle_cb}
+ };
+
+ public KlotskiWindow ()
+ {
+ var css_provider = new CssProvider ();
+ css_provider.load_from_resource ("/org/gnome/klotski/ui/klotski.css");
+ StyleContext.add_provider_for_screen (Gdk.Screen.get_default (), css_provider,
STYLE_PROVIDER_PRIORITY_APPLICATION);
+
+ settings = new GLib.Settings ("org.gnome.klotski");
+ set_default_size (settings.get_int ("window-width"), settings.get_int ("window-height"));
+ if (settings.get_boolean ("window-is-maximized"))
+ maximize ();
+
+ add_action_entries (win_actions, this);
+ prev_pack = lookup_action ("prev-pack") as SimpleAction;
+ next_pack = lookup_action ("next-pack") as SimpleAction;
+ prev_puzzle = lookup_action ("prev-puzzle") as SimpleAction;
+ next_puzzle = lookup_action ("next-puzzle") as SimpleAction;
+ start_game = lookup_action ("start-game") as SimpleAction;
+
+ string histfile = Path.build_filename (Environment.get_user_data_dir (), "gnome-klotski", "history");
+
+ history = new History (histfile);
+ history.load ();
+
+ // name, active, puzzle number (or -1), sensitive=false CSS hack
+ liststore_huarong = new Gtk.ListStore (4, typeof (string), typeof (bool), typeof (int), typeof
(bool));
+ liststore_challenge = new Gtk.ListStore (4, typeof (string), typeof (bool), typeof (int), typeof
(bool));
+ liststore_skill = new Gtk.ListStore (4, typeof (string), typeof (bool), typeof (int), typeof (bool));
+
+ puzzles_items = new TreeIter[level.length];
+ for (var i = 0; i < level.length; i++)
+ {
+ switch (level[i].group)
+ {
+ case 0:
+ liststore_huarong.append (out puzzles_items[i]);
+ liststore_huarong.set (puzzles_items[i],
+ 0, _(level[i].name),
+ 1, false,
+ 2, i,
+ 3, false);
+ break;
+ case 1:
+ liststore_challenge.append (out puzzles_items[i]);
+ liststore_challenge.set (puzzles_items[i],
+ 0, _(level[i].name),
+ 1, false,
+ 2, i,
+ 3, false);
+ break;
+ case 2:
+ liststore_skill.append (out puzzles_items[i]);
+ liststore_skill.set (puzzles_items[i],
+ 0, _(level[i].name),
+ 1, false,
+ 2, i,
+ 3, false);
+ break;
+ }
+ }
+
+ treeview_huarong.set_model (liststore_huarong);
+ treeview_challenge.set_model (liststore_challenge);
+ treeview_skill.set_model (liststore_skill);
+
+ treeview_huarong.row_activated.connect (level_huarong_cb);
+ treeview_challenge.row_activated.connect (level_challenge_cb);
+ treeview_skill.row_activated.connect (level_skill_cb);
+
+ view = new PuzzleView ();
+ view.halign = Align.FILL;
+ view.can_focus = true;
+ view.show ();
+ add (view);
+
+ load_solved_state (); // TODO use GSettings, or the history…
+
+ current_level = settings.get_int (KEY_LEVEL).clamp (0, level.length - 1);
+ puzzles_popover.show.connect (() => { update_popover (true); });
+ update_popover (true); // or “Start Over” logically complains
+
+ start_puzzle ();
+ }
+
+ /*\
+ * * Window management callbacks
+ \*/
+
+ [GtkCallback]
+ private void on_size_allocate (Allocation allocation)
+ {
+ if (window_is_maximized || is_tiled)
+ return;
+ window_width = allocation.width;
+ window_height = allocation.height;
+ }
+
+ [GtkCallback]
+ private bool on_window_state_event (Gdk.EventWindowState event)
+ {
+ if ((event.changed_mask & Gdk.WindowState.MAXIMIZED) != 0)
+ window_is_maximized = (event.new_window_state & Gdk.WindowState.MAXIMIZED) != 0;
+ /* We don’t save this state, but track it for saving size allocation */
+ if ((event.changed_mask & Gdk.WindowState.TILED) != 0)
+ is_tiled = (event.new_window_state & Gdk.WindowState.TILED) != 0;
+ return false;
+ }
+
+ [GtkCallback]
+ private void on_destroy ()
+ {
+ /* Save game state */
+ settings.set_int (KEY_LEVEL, current_level);
+
+ /* Save window state */
+ settings.set_int ("window-width", window_width);
+ settings.set_int ("window-height", window_height);
+ settings.set_boolean ("window-is-maximized", window_is_maximized);
+ }
+
+ /*\
+ * * Popover’s buttons callbacks
+ \*/
+
+ private void prev_pack_cb ()
+ {
+ if (!puzzles_popover.visible)
+ return;
+ current_pack--;
+ update_popover (false);
+ }
+
+ private void next_pack_cb ()
+ {
+ if (!puzzles_popover.visible)
+ return;
+ current_pack++;
+ update_popover (false);
+ }
+
+ private void prev_puzzle_cb ()
+ {
+ if (!puzzles_popover.visible)
+ return;
+ current_level--;
+ update_popover (true);
+ start_puzzle ();
+ }
+
+ private void next_puzzle_cb ()
+ {
+ if (!puzzles_popover.visible)
+ return;
+ current_level++;
+ update_popover (true);
+ start_puzzle ();
+ }
+
+ private void start_puzzle_cb ()
+ {
+ TreeView tree = ((TreeView) (((ScrolledWindow) (stack_puzzles.get_children ().nth_data
(current_pack))).get_child ()));
+ TreeModel model = tree.get_model ();
+ TreeIter iter;
+
+ if (tree.get_selection ().get_selected (out model, out iter))
+ start_puzzle_from_iter ((Gtk.ListStore) model, iter);
+ else
+ start_puzzle ();
+ puzzles_popover.hide ();
+ }
+
+ /*\
+ * * Update popover
+ \*/
+
+ private void update_popover (bool make_current)
+ {
+ int current_level_pack;
+ TreeIter iter = puzzles_items[current_level];
+ if (liststore_huarong.iter_is_valid (iter)) // "slow"
+ current_level_pack = 0;
+ else if (liststore_challenge.iter_is_valid (iter)) // same here
+ current_level_pack = 1;
+ else
+ current_level_pack = 2;
+
+ if (make_current)
+ current_pack = current_level_pack;
+
+ /* select or not a level */
+ TreeSelection selection = ((TreeView) (((ScrolledWindow) (stack_puzzles.get_children ().nth_data
(current_pack))).get_child ())).get_selection ();
+ if (current_pack == current_level_pack)
+ selection.select_iter (iter);
+ else
+ selection.unselect_all ();
+
+ update_buttons_state ();
+
+ /* update stacks */
+ stack_packs.set_visible_child (stack_packs.get_children ().nth_data (current_pack));
+ stack_puzzles.set_visible_child (stack_puzzles.get_children ().nth_data (current_pack));
+ }
+
+ private void update_buttons_state ()
+ {
+ prev_pack.set_enabled (current_pack > 0);
+ next_pack.set_enabled (current_pack < 2);
+
+ prev_puzzle.set_enabled (current_level > 0);
+ next_puzzle.set_enabled (current_level < level.length - 1);
+ }
+
+ /*\
+ * * Selecting puzzle by the treeview
+ \*/
+
+ private void level_huarong_cb (TreePath path, TreeViewColumn column)
+ {
+ level_cb (liststore_huarong, path, column);
+ }
+ private void level_challenge_cb (TreePath path, TreeViewColumn column)
+ {
+ level_cb (liststore_challenge, path, column);
+ }
+ private void level_skill_cb (TreePath path, TreeViewColumn column)
+ {
+ level_cb (liststore_skill, path, column);
+ }
+ private void level_cb (Gtk.ListStore liststore, TreePath path, TreeViewColumn column)
+ {
+ TreeIter iter;
+
+ liststore.get_iter (out iter, path);
+ start_puzzle_from_iter (liststore, iter);
+ }
+
+ /*\
+ * * Creating and starting game
+ \*/
+
+ private void start_puzzle_from_iter (Gtk.ListStore model, TreeIter iter)
+ {
+ Value val;
+ model.get_value (iter, 2, out val);
+
+ int requested_level = (int) val;
+ if (requested_level < 0)
+ return;
+
+ current_level = requested_level;
+ update_buttons_state ();
+ start_puzzle ();
+ }
+
+ private void start_puzzle ()
+ {
+ headerbar.set_title (_(level[current_level].name));
+ puzzle = new Puzzle (level[current_level].width, level[current_level].height,
level[current_level].data);
+ puzzle.moved.connect (puzzle_moved_cb); // TODO disconnect previous puzzle?
+ view.puzzle = puzzle;
+
+ update_moves_label ();
+ start_game.set_enabled (false);
+ }
+
+ private void puzzle_moved_cb ()
+ {
+ update_moves_label ();
+ }
+
+ private void update_moves_label ()
+ {
+ start_game.set_enabled (true);
+ headerbar.set_subtitle (_("Moves: %d").printf (puzzle.moves));
+ if (puzzle.game_over ())
+ {
+ headerbar.set_title (_("Level completed."));
+ game_score ();
+ }
+ }
+
+ /*\
+ * * Scores
+ \*/
+
+ private void game_score ()
+ {
+ /* Level is complete */
+ var key = get_level_key (current_level);
+ var keyfile = new KeyFile ();
+ var filename = Path.build_filename (Environment.get_user_data_dir (), "gnome-klotski", "levels");
// filename:~/.local/share/gnome-klotski/levels
+
+ try
+ {
+ keyfile.load_from_file (filename, KeyFileFlags.NONE);
+ }
+ catch (Error e)
+ {
+ }
+
+ keyfile.set_boolean (key, "solved", true);
+
+ try
+ {
+ FileUtils.set_contents (filename, keyfile.to_data ());
+ }
+ catch (Error e)
+ {
+ }
+
+ puzzle_solved (puzzles_items[current_level], true);
+
+ var date = new DateTime.now_local ();
+ var entry = new HistoryEntry (date, current_level, puzzle.moves);
+ history.add (entry);
+ history.save ();
+
+ show_scores (entry);
+ }
+
+ public void show_scores (HistoryEntry? selected_entry = null)
+ {
+ var dialog = new ScoreDialog (history, selected_entry);
+ dialog.set_transient_for (this);
+
+ /* var result = */ dialog.run ();
+ dialog.destroy ();
+ }
+
+ private string get_level_key (int level_number)
+ {
+ /* Calculate the CRC of the level data */
+ uint32 result = 0xFFFFFFFFu;
+ var data = level[level_number].data;
+ for (var i = 0; data[i] != '\0'; i++)
+ {
+ var octet = data[i];
+ for (var j = 0; j < 8; j++)
+ {
+ if (((octet >> 7) ^ (result >> 31)) != 0)
+ result = (result << 1) ^ 0x04c11db7;
+ else
+ result = (result << 1);
+ result &= 0xFFFFFFFF;
+ octet <<= 1;
+ }
+ }
+
+ return "%08X".printf (~result);
+ }
+
+ private void load_solved_state ()
+ {
+ var keyfile = new KeyFile ();
+ var filename = Path.build_filename (Environment.get_user_data_dir (), "gnome-klotski", "levels");
+ try
+ {
+ keyfile.load_from_file (filename, KeyFileFlags.NONE);
+ }
+ catch (Error e)
+ {
+ }
+
+ for (var i = 0; i < level.length; i++)
+ {
+ var key = get_level_key (i);
+ var value = false;
+ try
+ {
+ value = keyfile.get_boolean (key, "solved");
+ }
+ catch (Error e)
+ {
+ }
+
+ puzzle_solved (puzzles_items[i], value);
+ }
+ }
+
+ private void puzzle_solved (TreeIter iter, bool solved)
+ {
+ if (liststore_huarong.iter_is_valid (iter)) // "slow"
+ liststore_huarong.set (iter, 1, solved);
+ else if (liststore_challenge.iter_is_valid (iter)) // same here
+ liststore_challenge.set (iter, 1, solved);
+ else
+ liststore_skill.set (iter, 1, solved);
+ }
+}
diff --git a/src/score-dialog.vala b/src/score-dialog.vala
index d20e65e..53ecd1f 100644
--- a/src/score-dialog.vala
+++ b/src/score-dialog.vala
@@ -138,7 +138,7 @@ public class ScoreDialog : Dialog
if (!have_level_entry)
{
- var label = _(Klotski.level[entry.level].name);
+ var label = _(KlotskiWindow.level[entry.level].name);
levels_liststore.append (out iter);
levels_liststore.set (iter,
0, label,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]