[gnome-klotski] New UI. Use GtkBuilder.
- From: Michael Catanzaro <mcatanzaro src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-klotski] New UI. Use GtkBuilder.
- Date: Mon, 16 Feb 2015 20:35:19 +0000 (UTC)
commit fdf0b06e61625bbace2a76acf594d45bf29ca89f
Author: Arnaud Bonatti <arnaud bonatti gmail com>
Date: Mon Feb 16 20:24:28 2015 +0100
New UI. Use GtkBuilder.
https://bugzilla.gnome.org/show_bug.cgi?id=744023
configure.ac | 2 +
data/Makefile.am | 5 +-
data/klotski-scores.ui | 110 +++++++
data/klotski.css | 37 +++
data/klotski.ui | 311 +++++++++++++++++++
po/POTFILES.in | 2 +
src/Makefile.am | 4 +-
src/gnome-klotski.vala | 758 ++++++++++++++++++++++-----------------------
src/klotski.gresource.xml | 5 +-
src/puzzle-view.vala | 5 +-
src/score-dialog.vala | 152 ++++-----
11 files changed, 911 insertions(+), 480 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 35d4fa8..38debfc 100644
--- a/configure.ac
+++ b/configure.ac
@@ -27,6 +27,8 @@ PKG_CHECK_MODULES(GNOME_KLOTSKI, [
librsvg-2.0 >= $RSVG_REQUIRED
])
+AC_SUBST([GLIB_REQUIRED])
+
AC_PATH_PROG([DESKTOP_FILE_VALIDATE], [desktop-file-validate], [/bin/true])
dnl ###########################################################################
diff --git a/data/Makefile.am b/data/Makefile.am
index 828317e..76b83a7 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -6,7 +6,10 @@ gsettings_SCHEMAS = org.gnome.klotski.gschema.xml
man_MANS = gnome-klotski.6
dist_noinst_DATA = \
- klotski-menus.ui
+ klotski-menus.ui \
+ klotski-scores.ui \
+ klotski.ui \
+ klotski.css
pixmapdir = $(datadir)/gnome-klotski
pixmap_DATA = \
diff --git a/data/klotski-scores.ui b/data/klotski-scores.ui
new file mode 100644
index 0000000..d2b93b9
--- /dev/null
+++ b/data/klotski-scores.ui
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <requires lib="gtk+" version="3.12"/>
+ <object class="GtkListStore" id="levels_liststore">
+ <columns>
+ <column type="gchararray"/> <!-- puzzle name -->
+ <column type="gint"/> <!-- level -->
+ </columns>
+ </object>
+ <object class="GtkListStore" id="scores_liststore">
+ <columns>
+ <column type="gchararray"/> <!-- date -->
+ <column type="gchararray"/> <!-- moves -->
+ <column type="gint"/> <!-- weight -->
+ </columns>
+ </object>
+ <template class="ScoreDialog" parent="GtkDialog">
+ <property name="visible">False</property>
+ <property name="width-request">300</property>
+ <property name="height-request">400</property>
+ <property name="resizable">False</property>
+ <property name="title" translatable="yes">Scores</property>
+ <property name="modal">True</property>
+ <child internal-child="vbox">
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">5</property>
+ <property name="border-width">6</property>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="orientation">horizontal</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Puzzle:</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkComboBox" id="level_combo">
+ <property name="visible">True</property>
+ <property name="model">levels_liststore</property>
+ <child>
+ <object class="GtkCellRendererText"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="shadow-type">etched-in</property>
+ <property name="hscrollbar-policy">never</property>
+ <property name="vscrollbar-policy">automatic</property>
+ <property name="vexpand">True</property>
+ <child>
+ <object class="GtkTreeView" id="scores_tree">
+ <property name="visible">True</property>
+ <property name="headers-visible">True</property>
+ <property name="activate-on-single-click">True</property>
+ <property name="model">scores_liststore</property>
+ <style><class name="toggle-like-pixbuf"/></style>
+ <child>
+ <object class="GtkTreeViewColumn">
+ <property name="title" translatable="yes">Date</property>
+ <property name="expand">True</property>
+ <child>
+ <object class="GtkCellRendererText">
+ <property name="xalign">0.0f</property>
+ </object>
+ <attributes>
+ <attribute name="text">0</attribute>
+ <attribute name="weight">2</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn">
+ <property name="title" translatable="yes">Moves</property>
+ <property name="expand">True</property>
+ <child>
+ <object class="GtkCellRendererText">
+ <property name="xalign">1.0f</property>
+ </object>
+ <attributes>
+ <attribute name="text">1</attribute>
+ <attribute name="weight">2</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/data/klotski.css b/data/klotski.css
new file mode 100644
index 0000000..2c72f50
--- /dev/null
+++ b/data/klotski.css
@@ -0,0 +1,37 @@
+GtkPopover#puzzles-popover {
+ padding: 10px;
+}
+
+GtkStack#stack-packs > GtkLabel {
+ font-weight: bold;
+}
+
+.treeview-container GtkTreeView {
+ background-color: transparent;
+}
+.treeview-container GtkTreeView:backdrop {
+ color: @theme_unfocused_fg_color;
+}
+.treeview-container GtkTreeView:prelight {
+ background-color: @theme_bg_color;
+}
+.treeview-container GtkTreeView:prelight:backdrop {
+ background-color: @theme_unfocused_bg_color;
+}
+.treeview-container GtkTreeView:selected,
+.treeview-container GtkTreeView:selected:prelight {
+ background-color: @theme_selected_bg_color;
+ color: @theme_selected_fg_color;
+}
+.treeview-container GtkTreeView:selected:backdrop,
+.treeview-container GtkTreeView:selected:backdrop:prelight {
+ background-color: @theme_unfocused_selected_bg_color;
+ color: @theme_unfocused_selected_fg_color;
+}
+
+GtkTreeView.toggle-like-pixbuf:insensitive {
+ -gtk-icon-source: none;
+}
+GtkTreeView.toggle-like-pixbuf:insensitive:checked {
+ -gtk-icon-source: -gtk-icontheme("gtk-yes"); /* TODO maybe deprecated */
+}
diff --git a/data/klotski.ui b/data/klotski.ui
new file mode 100644
index 0000000..acc8e1d
--- /dev/null
+++ b/data/klotski.ui
@@ -0,0 +1,311 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <requires lib="gtk+" version="3.12"/>
+ <object class="GtkPopover" id="puzzles-popover">
+ <property name="visible">False</property>
+ <property name="name">puzzles-popover</property>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="orientation">horizontal</property>
+ <property name="halign">fill</property>
+ <child>
+ <object class="GtkButton">
+ <property name="visible">True</property>
+ <property name="action-name">win.prev-pack</property>
+ <style><class name="flat"/><class name="image-button"/></style>
+ <child>
+ <object class="GtkImage">
+ <property name="icon-name">go-previous-symbolic</property>
+ <property name="visible">True</property>
+ <property name="icon-size">1</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkStack" id="stack-packs">
+ <property name="name">stack-packs</property>
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkLabel">
+ <property name="name">pack-name</property>
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Huarong Trail</property>
+ </object>
+ <packing>
+ <property name="name">huarong</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="name">pack-name</property>
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Challenge Pack</property>
+ </object>
+ <packing>
+ <property name="name">challenge</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="name">pack-name</property>
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Skill Pack</property>
+ </object>
+ <packing>
+ <property name="name">skill</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton">
+ <property name="visible">True</property>
+ <property name="action-name">win.next-pack</property>
+ <style><class name="flat"/><class name="image-button"/></style>
+ <child>
+ <object class="GtkImage">
+ <property name="icon-name">go-next-symbolic</property>
+ <property name="visible">True</property>
+ <property name="icon-size">1</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <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>
+ <property name="width-request">190</property>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="hscrollbar-policy">never</property>
+ <style><class name="treeview-container"/></style>
+ <child>
+ <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>
+ <property name="can-focus">False</property> <!-- for up/down keybinding -->
+ <!-- <property name="model">*store</property> TODO -->
+ <style><class name="toggle-like-pixbuf"/></style>
+ <child>
+ <object class="GtkTreeViewColumn">
+ <property name="title">Puzzle</property>
+ <child>
+ <object class="GtkCellRendererText"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn">
+ <property name="title">Complete</property>
+ <child>
+ <object class="GtkCellRendererToggle"/>
+ <attributes>
+ <attribute name="active">1</attribute>
+ <attribute name="sensitive">3</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="name">huarong</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="hscrollbar-policy">never</property>
+ <style><class name="treeview-container"/></style>
+ <child>
+ <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>
+ <property name="can-focus">False</property> <!-- for up/down keybinding -->
+ <!-- <property name="model">*store</property> TODO -->
+ <style><class name="toggle-like-pixbuf"/></style>
+ <child>
+ <object class="GtkTreeViewColumn">
+ <property name="title">Puzzle</property>
+ <child>
+ <object class="GtkCellRendererText"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn">
+ <property name="title">Complete</property>
+ <child>
+ <object class="GtkCellRendererToggle"/>
+ <attributes>
+ <attribute name="active">1</attribute>
+ <attribute name="sensitive">3</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="name">challenge</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="hscrollbar-policy">never</property>
+ <style><class name="treeview-container"/></style>
+ <child>
+ <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>
+ <property name="can-focus">False</property> <!-- for up/down keybinding -->
+ <!-- <property name="model">*store</property> TODO -->
+ <style><class name="toggle-like-pixbuf"/></style>
+ <child>
+ <object class="GtkTreeViewColumn">
+ <property name="title">Puzzle</property>
+ <child>
+ <object class="GtkCellRendererText"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn">
+ <property name="title">Complete</property>
+ <child>
+ <object class="GtkCellRendererToggle"/>
+ <attributes>
+ <attribute name="active">1</attribute>
+ <attribute name="sensitive">3</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="name">skill</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="orientation">horizontal</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">True</property>
+ <property name="halign">fill</property>
+ <style><class name="linked"/></style>
+ <child>
+ <object class="GtkButton">
+ <property name="visible">True</property>
+ <!-- <property name="use-underline">True</property> TODO -->
+ <property name="label" translatable="yes">Previous</property>
+ <property name="action-name">win.prev-puzzle</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton">
+ <property name="visible">True</property>
+ <!-- <property name="use-underline">True</property> TODO -->
+ <property name="label" translatable="yes">Next</property>
+ <property name="action-name">win.next-puzzle</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <object class="GtkApplicationWindow" id="window">
+ <!-- <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 -->
+ <child type="titlebar">
+ <object class="GtkHeaderBar" id="headerbar">
+ <property name="visible">True</property>
+ <property name="show-close-button">True</property>
+ <property name="title" translatable="yes">Klotski</property>
+ <child>
+ <object class="GtkButton">
+ <property name="visible">True</property>
+ <property name="use-underline">True</property>
+ <property name="label" translatable="yes">_Start Over</property>
+ <property name="tooltip-text" translatable="yes">Restart the current puzzle</property>
+ <property name="can-focus">True</property>
+ <property name="focus-on-click">False</property>
+ <property name="action-name">win.start-game</property>
+ </object>
+ <packing>
+ <property name="pack-type">start</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkMenuButton">
+ <property name="visible">True</property>
+ <property name="use-underline">True</property>
+ <property name="label" translatable="yes">_Change Puzzle</property>
+ <property name="tooltip-text" translatable="yes">Choose an other puzzle</property>
+ <property name="can-focus">True</property>
+ <property name="focus-on-click">False</property>
+ <property name="direction">down</property>
+ <property name="popover">puzzles-popover</property>
+ </object>
+ <packing>
+ <property name="pack-type">end</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+</interface>
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 275e60c..d4cde8a 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -3,7 +3,9 @@
[encoding: UTF-8]
data/gnome-klotski.appdata.xml.in
data/gnome-klotski.desktop.in
+[type: gettext/glade]data/klotski.ui
[type: gettext/glade]data/klotski-menus.ui
+[type: gettext/glade]data/klotski-scores.ui
data/org.gnome.klotski.gschema.xml
src/gnome-klotski.vala
src/puzzle-view.vala
diff --git a/src/Makefile.am b/src/Makefile.am
index 920da62..bc4c005 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -22,7 +22,9 @@ gnome_klotski_CFLAGS = \
gnome_klotski_VALAFLAGS = \
--pkg posix \
--pkg gtk+-3.0 \
- --pkg librsvg-2.0
+ --pkg librsvg-2.0 \
+ --gresources $(builddir)/klotski.gresource.xml \
+ --target-glib $(GLIB_REQUIRED)
gnome_klotski_LDADD = \
$(GNOME_KLOTSKI_LIBS)
diff --git a/src/gnome-klotski.vala b/src/gnome-klotski.vala
index becb3f4..54ffc32 100644
--- a/src/gnome-klotski.vala
+++ b/src/gnome-klotski.vala
@@ -8,6 +8,8 @@
* license.
*/
+using Gtk;
+
/* Puzzle Info */
private struct LevelInfo
{
@@ -20,42 +22,43 @@ private struct LevelInfo
public class Klotski : Gtk.Application
{
- private Settings settings;
- private const int MINWIDTH = 250;
- private const int MINHEIGHT = 250;
- private const int SPACE_PADDING = 5;
-
- private const string KEY_LEVEL = "level";
-
- /* Main window */
- private Gtk.Window window;
+ /* Settings */
+ private GLib.Settings settings;
+ private bool is_tiled;
+ private bool is_maximized;
private int window_width;
private int window_height;
- private bool is_maximized;
- private bool is_tiled;
-
- private Gtk.Box puzzles_panel;
-
- private Gtk.Button next_button;
- private Gtk.Button prev_button;
- private SimpleAction next_level_action;
- private SimpleAction prev_level_action;
- private SimpleAction new_game_action;
+ 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;
- private Gtk.HeaderBar headerbar;
+ /* 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.TreeStore puzzles;
- private Gtk.TreeIter[] puzzles_items;
+ 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 */
@@ -436,18 +439,33 @@ public class Klotski : Gtk.Application
{ null }
};
- private const GLib.ActionEntry[] action_entries =
+ private const GLib.ActionEntry app_actions[] =
+ {
+ {"scores", scores_cb},
+ {"help", help_cb},
+ {"about", about_cb},
+ {"quit", quit}
+ };
+ private const GLib.ActionEntry win_actions[] =
{
- { "new-game", restart_level_cb },
- { "show-puzzles", toggle_puzzles_cb },
- { "next-level", next_level_cb },
- { "prev-level", prev_level_cb },
- { "scores", scores_cb },
- { "help", help_cb },
- { "about", about_cb },
- { "quit", quit_cb }
+ {"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 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 ();
+ return app.run (args);
+ }
+
public Klotski ()
{
Object (application_id: "org.gnome.klotski", flags: ApplicationFlags.FLAGS_NONE);
@@ -455,199 +473,153 @@ public class Klotski : Gtk.Application
add_main_option_entries (option_entries);
}
- protected override void startup ()
+ protected override int handle_local_options (GLib.VariantDict options)
{
- base.startup ();
-
- Environment.set_application_name (_("Klotski"));
-
- settings = new Settings ("org.gnome.klotski");
-
- Gtk.Window.set_default_icon_name ("gnome-klotski");
-
- var css_provider = new Gtk.CssProvider ();
- try
- {
- /* Pixel-perfect compatibility with games that have a Button without ButtonBox. */
- var data = """GtkButtonBox { -GtkButtonBox-child-internal-pad-x:0; }""";
- css_provider.load_from_data (data, data.length);
- }
- catch (GLib.Error e)
+ if (options.contains ("version"))
{
- warning ("Error loading css styles: %s", e.message);
+ /* NOTE: Is not translated so can be easily parsed */
+ stderr.printf ("%1$s %2$s\n", "gnome-klotski", VERSION);
+ return Posix.EXIT_SUCCESS;
}
- Gtk.StyleContext.add_provider_for_screen (Gdk.Screen.get_default (), css_provider,
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
- add_action_entries (action_entries, this);
- new_game_action = lookup_action ("new-game") as SimpleAction;
- new_game_action.set_enabled (false);
- next_level_action = lookup_action ("next-level") as SimpleAction;
- next_level_action.set_enabled (current_level < level.length - 1);
- prev_level_action = lookup_action ("prev-level") as SimpleAction;
- prev_level_action.set_enabled (current_level > 0);
+ /* Activate */
+ return -1;
+ }
- set_accels_for_action ("app.new-game", {"<Primary>n"});
- set_accels_for_action ("app.quit", {"<Primary>q"});
- set_accels_for_action ("app.help", {"F1"});
- set_accels_for_action ("app.next-level", {"Page_Up"});
- set_accels_for_action ("app.prev-level", {"Page_Down"});
+ protected override void startup ()
+ {
+ base.startup ();
- string histfile = Path.build_filename (Environment.get_user_data_dir (), "gnome-klotski", "history");
+ Environment.set_application_name (_("Klotski"));
+ Window.set_default_icon_name ("gnome-klotski");
- history = new History (histfile);
- history.load ();
+ 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);
- headerbar = new Gtk.HeaderBar ();
- headerbar.show_close_button = true;
- headerbar.show ();
+ settings = new GLib.Settings ("org.gnome.klotski");
- window = new Gtk.ApplicationWindow (this);
- window.set_titlebar (headerbar);
+ 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);
-
- int ww = int.max (settings.get_int ("window-width"), MINWIDTH);
- int wh = int.max (settings.get_int ("window-height"), MINHEIGHT);
- window.set_default_size (ww, wh);
- window.border_width = 25;
-
+ window.set_default_size (settings.get_int ("window-width"), settings.get_int ("window-height"));
if (settings.get_boolean ("window-is-maximized"))
window.maximize ();
- var hbox = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 25);
- window.add (hbox);
-
- puzzles = new Gtk.TreeStore (3, typeof (string), typeof (bool), typeof (int));
+ 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 ("app.help", {"F1"});
+ set_accels_for_action ("app.quit", {"<Primary>q"});
+ // 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.
- Gtk.TreeIter huarong_item;
- puzzles.append (out huarong_item, null);
- puzzles.set (huarong_item, 0, "HuaRong Trail", 2, -1, -1);
+ string histfile = Path.build_filename (Environment.get_user_data_dir (), "gnome-klotski", "history");
- Gtk.TreeIter challenge_item;
- puzzles.append (out challenge_item, null);
- puzzles.set (challenge_item, 0, "Challenge Pack", 2, -1, -1);
+ history = new History (histfile);
+ history.load ();
- Gtk.TreeIter skill_item;
- puzzles.append (out skill_item, null);
- puzzles.set (skill_item, 0, "Skill Pack", 2, -1, -1);
+ 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;
- puzzles_items = new Gtk.TreeIter[level.length];
+ // 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:
- puzzles.append (out puzzles_items[i], huarong_item);
- puzzles.set (puzzles_items[i], 0, _(level[i].name), 1, false, 2, i, -1);
+ 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:
- puzzles.append (out puzzles_items[i], challenge_item);
- puzzles.set (puzzles_items[i], 0, _(level[i].name), 1, false, 2, i, -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:
- puzzles.append (out puzzles_items[i], skill_item);
- puzzles.set (puzzles_items[i], 0, _(level[i].name), 1, false, 2, i, -1);
+ liststore_skill.append (out puzzles_items[i]);
+ liststore_skill.set (puzzles_items[i],
+ 0, _(level[i].name),
+ 1, false,
+ 2, i,
+ 3, false);
break;
}
}
- puzzles_panel = new Gtk.Box (Gtk.Orientation.VERTICAL, 0);
- puzzles_panel.visible = false;
-
- var puzzles_view = new Gtk.TreeView.with_model (puzzles);
- puzzles_view.set_headers_visible (false);
-
- var cell = new Gtk.CellRendererText ();
- var col = new Gtk.TreeViewColumn.with_attributes ("Puzzle", cell, "text", 0, null);
- col.set_data<Klotski> ("app", this);
- col.set_cell_data_func (cell, (Gtk.CellLayoutDataFunc) render_puzzle_name);
- puzzles_view.append_column (col);
-
- puzzles_view.insert_column_with_attributes (-1, "Complete", new CellRendererLevel (), "visible", 1,
null);
- puzzles_view.row_activated.connect (level_cb);
- puzzles_view.show_all ();
-
- var scroll = new Gtk.ScrolledWindow (null, null);
- scroll.name = "puzzles";
- scroll.set_policy (Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
- scroll.add (puzzles_view);
- scroll.show ();
- puzzles_panel.pack_start (scroll, true, true, 0);
-
- var bbox = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0);
- var context = bbox.get_style_context ();
- context.add_class ("linked");
- bbox.margin_top = 12;
- bbox.show ();
-
- prev_button = new Gtk.Button.with_label (_("Previous Puzzle"));
- prev_button.clicked.connect (prev_level_cb);
- prev_button.sensitive = current_level > 0;
- prev_button.show ();
- bbox.add (prev_button);
-
- next_button = new Gtk.Button.with_label (_("Next Puzzle"));
- next_button.clicked.connect (next_level_cb);
- next_button.sensitive = current_level < level.length - 1;
- next_button.show ();
- bbox.add (next_button);
-
- puzzles_panel.pack_start (bbox, false, true, 0);
- hbox.pack_start (puzzles_panel, false, true, 0);
+ 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.set_size_request (MINWIDTH, MINHEIGHT);
+ view.halign = Align.FILL;
+ view.can_focus = true;
view.show ();
- hbox.pack_start (view, true, true, 0);
-
- bbox = new Gtk.ButtonBox (Gtk.Orientation.VERTICAL);
- bbox.halign = Gtk.Align.END;
- bbox.valign = Gtk.Align.END;
- bbox.spacing = 6;
- bbox.show ();
- hbox.pack_start (bbox, false, true, 0);
-
- var button = new Gtk.Button ();
- button.label = _("_Start Over");
- button.use_underline = true;
- button.width_request = 120;
- button.height_request = 60;
- button.action_name = "app.new-game";
- button.show ();
- bbox.pack_end (button, false, true, 0);
-
- var togglebutton = new Gtk.ToggleButton ();
- togglebutton.label = _("_View Puzzles");
- togglebutton.use_underline = true;
- togglebutton.width_request = 120;
- togglebutton.height_request = 60;
- togglebutton.action_name = "app.show-puzzles";
- togglebutton.show ();
- bbox.pack_end (togglebutton, false, true, 0);
-
- hbox.show ();
-
- load_solved_state ();
-
- var startup_level = settings.get_int (KEY_LEVEL);
- new_game (startup_level);
+ 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);
}
- private static void render_puzzle_name (Gtk.CellLayout cell_layout, Gtk.CellRendererText cell,
- Gtk.TreeModel tree_model, Gtk.TreeIter iter)
+ protected override void activate ()
{
- Value val;
- tree_model.get_value (iter, 2, out val);
- int selected_level = (int) val;
- Klotski app = cell_layout.get_data<Klotski> ("app");
- if (app.current_level == selected_level)
- cell.weight = 700;
- else
- cell.weight = 400;
+ 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);
}
- private void size_allocate_cb (Gtk.Allocation allocation)
+ /*\
+ * * Window events
+ \*/
+
+ private void size_allocate_cb (Allocation allocation)
{
if (is_maximized || is_tiled)
return;
@@ -665,305 +637,315 @@ public class Klotski : Gtk.Application
return false;
}
+ /*\
+ * * App-menu callbacks
+ \*/
+
private void scores_cb ()
{
- show_scores (null, false);
+ show_scores (null);
}
- private void game_score ()
+ private void help_cb ()
{
- /* 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);
+ show_uri (window.get_screen (), "help:gnome-klotski", get_current_event_time ());
}
catch (Error e)
{
+ warning ("Failed to show help: %s", e.message);
}
+ }
- keyfile.set_boolean (key, "solved", true);
-
- try
- {
- FileUtils.set_contents (filename, keyfile.to_data ());
- }
- catch (Error e)
- {
- }
+ 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 };
- puzzles.set (puzzles_items[current_level], 1, true, -1);
+ show_about_dialog (window,
+ "program-name", _("Klotski"),
+ "version", VERSION,
+ "comments", _("Sliding block puzzles"),
+ "copyright",
+ "Copyright © 1999–2008 Lars Rydlinge\n"+
+ "Copyright © 2014–2015 Michael Catanzaro\n"+
+ "Copyright © 2015 Arnaud Bonatti\n",
+ "license-type", License.GPL_2_0, // TODO
+ "authors", authors,
+ "documenters", documenters,
+ "translator-credits", _("translator-credits"),
+ "logo-icon-name", "gnome-klotski",
+ "website", "https://wiki.gnome.org/Apps/Klotski",
+ null);
+ }
- var date = new DateTime.now_local ();
- var entry = new HistoryEntry (date, current_level, puzzle.moves);
- history.add (entry);
- history.save ();
+ /*\
+ * * Popover’s buttons callbacks
+ \*/
- if (show_scores (entry, true) == Gtk.ResponseType.OK)
- new_game (current_level);
+ private void prev_pack_cb ()
+ {
+ if (!puzzles_popover.visible)
+ return;
+ current_pack--;
+ update_popover (false);
}
- private int show_scores (HistoryEntry? selected_entry = null, bool show_close = false)
+ private void next_pack_cb ()
{
- var dialog = new ScoreDialog (history, selected_entry, show_close);
- dialog.modal = true;
- dialog.transient_for = window;
-
- var result = dialog.run ();
- dialog.destroy ();
-
- return result;
+ if (!puzzles_popover.visible)
+ return;
+ current_pack++;
+ update_popover (false);
}
- private string get_level_key (int level_number)
+ private void prev_puzzle_cb ()
{
- /* 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;
- }
- }
+ if (!puzzles_popover.visible)
+ return;
+ current_level--;
+ update_popover (true);
+ start_puzzle ();
+ }
- return "%08X".printf (~result);
+ private void next_puzzle_cb ()
+ {
+ if (!puzzles_popover.visible)
+ return;
+ current_level++;
+ update_popover (true);
+ start_puzzle ();
}
- private void load_solved_state ()
+ private void start_puzzle_cb ()
{
- 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)
- {
- }
+ TreeView tree = ((TreeView) (((ScrolledWindow) (stack_puzzles.get_children ().nth_data
(current_pack))).get_child ()));
+ TreeModel model = tree.get_model ();
+ TreeIter iter;
- 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)
- {
- }
- puzzles.set (puzzles_items[i], 1, value, -1);
- }
+ if (tree.get_selection ().get_selected (out model, out iter))
+ start_puzzle_from_iter ((Gtk.ListStore) model, iter);
+ else
+ start_puzzle ();
+ puzzles_popover.hide ();
}
- private void update_menu_state ()
+ /*\
+ * * Update popover
+ \*/
+
+ private void update_popover (bool make_current)
{
- puzzles_panel.queue_draw ();
+ 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;
- next_button.sensitive = current_level < level.length - 1;
- prev_button.sensitive = current_level > 0;
+ /* 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 ();
- next_level_action.set_enabled (current_level < level.length - 1);
- prev_level_action.set_enabled (current_level > 0);
+ update_buttons_state ();
- update_moves_label ();
+ /* 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 new_game (int requested_level)
+ private void update_buttons_state ()
{
- current_level = requested_level.clamp (0, level.length - 1);
+ prev_pack.set_enabled (current_pack > 0);
+ next_pack.set_enabled (current_pack < 2);
- settings.set_int (KEY_LEVEL, current_level);
-
- 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);
- view.puzzle = puzzle;
- new_game_action.set_enabled (false);
- update_menu_state ();
+ prev_puzzle.set_enabled (current_level > 0);
+ next_puzzle.set_enabled (current_level < level.length - 1);
}
- private void puzzle_moved_cb ()
+ /*\
+ * * Selecting puzzle by the treeview
+ \*/
+
+ private void level_huarong_cb (TreePath path, TreeViewColumn column)
{
- update_moves_label ();
- new_game_action.set_enabled (true);
+ level_cb (liststore_huarong, path, column);
}
-
- private void update_moves_label ()
+ private void level_challenge_cb (TreePath path, TreeViewColumn column)
{
- headerbar.set_subtitle (_("Moves: %d").printf (puzzle.moves));
- if (puzzle.game_over ())
- {
- headerbar.set_title (_("Level completed."));
- game_score ();
- }
+ level_cb (liststore_challenge, path, column);
}
-
- private void quit_cb ()
+ private void level_skill_cb (TreePath path, TreeViewColumn column)
{
- window.destroy ();
+ level_cb (liststore_skill, path, column);
}
+ private void level_cb (Gtk.ListStore liststore, TreePath path, TreeViewColumn column)
+ {
+ TreeIter iter;
- private void level_cb (Gtk.TreePath path, Gtk.TreeViewColumn column)
+ 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)
{
- Gtk.TreeIter iter;
Value val;
-
- puzzles.get_iter (out iter, path);
- puzzles.get_value (iter, 2, out val);
+ model.get_value (iter, 2, out val);
int requested_level = (int) val;
if (requested_level < 0)
return;
- if (current_level != requested_level)
- new_game (requested_level);
+ current_level = requested_level;
+ update_buttons_state ();
+ start_puzzle ();
}
- private void restart_level_cb ()
+ private void start_puzzle ()
{
- new_game (current_level);
- }
+ 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;
- private void toggle_puzzles_cb ()
- {
- puzzles_panel.visible = !puzzles_panel.visible;
+ update_moves_label ();
+ start_game.set_enabled (false);
}
- private void next_level_cb ()
+ private void puzzle_moved_cb ()
{
- new_game (current_level + 1);
+ update_moves_label ();
}
- private void prev_level_cb ()
+ private void update_moves_label ()
{
- new_game (current_level - 1);
+ start_game.set_enabled (true);
+ headerbar.set_subtitle (_("Moves: %d").printf (puzzle.moves));
+ if (puzzle.game_over ())
+ {
+ headerbar.set_title (_("Level completed."));
+ game_score ();
+ }
}
- private void help_cb ()
+ /*\
+ * * 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
{
- Gtk.show_uri (window.get_screen (), "help:gnome-klotski", Gtk.get_current_event_time ());
+ keyfile.load_from_file (filename, KeyFileFlags.NONE);
}
catch (Error e)
{
- warning ("Failed to show help: %s", e.message);
}
- }
-
- protected override void shutdown ()
- {
- base.shutdown ();
- /* 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);
- }
+ keyfile.set_boolean (key, "solved", true);
- protected override int handle_local_options (GLib.VariantDict options)
- {
- if (options.contains ("version"))
+ try
+ {
+ FileUtils.set_contents (filename, keyfile.to_data ());
+ }
+ catch (Error e)
{
- /* NOTE: Is not translated so can be easily parsed */
- stderr.printf ("%1$s %2$s\n", "gnome-klotski", VERSION);
- return Posix.EXIT_SUCCESS;
}
- /* Activate */
- return -1;
- }
-
- protected override void activate ()
- {
- window.present ();
- }
-
- 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 };
+ puzzle_solved (puzzles_items[current_level], true);
- Gtk.show_about_dialog (window,
- "program-name", _("Klotski"),
- "version", VERSION,
- "comments", _("Sliding block puzzles"),
- "copyright",
- "Copyright © 1999–2008 Lars Rydlinge\nCopyright © 2014–2015 Michael
Catanzaro",
- "license-type", Gtk.License.GPL_2_0,
- "authors", authors,
- "documenters", documenters,
- "translator-credits", _("translator-credits"),
- "logo-icon-name", "gnome-klotski",
- "website", "https://wiki.gnome.org/Apps/Klotski",
- null);
+ var date = new DateTime.now_local ();
+ var entry = new HistoryEntry (date, current_level, puzzle.moves);
+ history.add (entry);
+ history.save ();
+ show_scores (entry);
}
- public static int main (string[] args)
+ private void show_scores (HistoryEntry? selected_entry = null)
{
- Intl.setlocale (LocaleCategory.ALL, "");
- Intl.bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
- Intl.bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
- Intl.textdomain (GETTEXT_PACKAGE);
+ var dialog = new ScoreDialog (history, selected_entry);
+ dialog.set_transient_for (window);
- var app = new Klotski ();
- return app.run (args);
+ /* var result = */ dialog.run ();
+ dialog.destroy ();
}
-}
-
-private class CellRendererLevel : Gtk.CellRenderer
-{
- private const int icon_size = 10;
- public CellRendererLevel ()
+ private string get_level_key (int level_number)
{
- GLib.Object ();
- }
+ /* 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;
+ }
+ }
- public override void get_size (Gtk.Widget widget, Gdk.Rectangle? cell_area,
- out int x_offset, out int y_offset,
- out int width, out int height)
- {
- x_offset = 0;
- y_offset = 0;
- width = height = icon_size;
+ return "%08X".printf (~result);
}
- public override void render (Cairo.Context ctx, Gtk.Widget widget,
- Gdk.Rectangle background_area,
- Gdk.Rectangle cell_area,
- Gtk.CellRendererState flags)
+ private void load_solved_state ()
{
- Gdk.cairo_rectangle (ctx, background_area);
-
+ var keyfile = new KeyFile ();
+ var filename = Path.build_filename (Environment.get_user_data_dir (), "gnome-klotski", "levels");
try
{
- var icon_theme = Gtk.IconTheme.get_default ();
- var icon = icon_theme.load_icon ("gtk-yes", icon_size, 0);
-
- int x = background_area.x + (background_area.width - icon_size)/2;
- int y = background_area.y + (background_area.height - icon_size)/2;
- Gdk.cairo_set_source_pixbuf (ctx, icon, x, y);
+ keyfile.load_from_file (filename, KeyFileFlags.NONE);
}
catch (Error e)
{
- warning (e.message);
}
- ctx.fill ();
+ 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/klotski.gresource.xml b/src/klotski.gresource.xml
index adf4e0e..71609ef 100644
--- a/src/klotski.gresource.xml
+++ b/src/klotski.gresource.xml
@@ -1,9 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
- <!-- <gresource prefix="/org/gnome/klotski/ui">
+ <gresource prefix="/org/gnome/klotski/ui">
<file preprocess="xml-stripblanks" alias="klotski.ui">../data/klotski.ui</file>
+ <file preprocess="xml-stripblanks" alias="scores.ui">../data/klotski-scores.ui</file>
<file alias="klotski.css">../data/klotski.css</file>
- </gresource> -->
+ </gresource>
<gresource prefix="/org/gnome/klotski/gtk">
<file preprocess="xml-stripblanks" alias="menus.ui">../data/klotski-menus.ui</file>
</gresource>
diff --git a/src/puzzle-view.vala b/src/puzzle-view.vala
index fc2a072..6a64db9 100644
--- a/src/puzzle-view.vala
+++ b/src/puzzle-view.vala
@@ -70,6 +70,7 @@ public class PuzzleView : Gtk.DrawingArea
public PuzzleView ()
{
+ set_size_request (250, 250); // TODO enough? Taquin is in 350^2
set_events (Gdk.EventMask.EXPOSURE_MASK | Gdk.EventMask.BUTTON_PRESS_MASK |
Gdk.EventMask.POINTER_MOTION_MASK | Gdk.EventMask.BUTTON_RELEASE_MASK);
load_image ();
}
@@ -199,7 +200,7 @@ public class PuzzleView : Gtk.DrawingArea
protected override bool button_press_event (Gdk.EventButton event)
{
- if (event.button == 1)
+ if (event.button == Gdk.BUTTON_PRIMARY)
{
if (puzzle.game_over ())
return false;
@@ -227,7 +228,7 @@ public class PuzzleView : Gtk.DrawingArea
protected override bool button_release_event (Gdk.EventButton event)
{
- if (event.button == 1 && piece_id != '\0')
+ if (event.button == Gdk.BUTTON_PRIMARY && piece_id != '\0')
{
if (piece_unmoved)
return false;
diff --git a/src/score-dialog.vala b/src/score-dialog.vala
index 7bc34be..d20e65e 100644
--- a/src/score-dialog.vala
+++ b/src/score-dialog.vala
@@ -8,79 +8,61 @@
* license.
*/
- public class ScoreDialog : Gtk.Dialog
+using Gtk;
+
+[GtkTemplate (ui = "/org/gnome/klotski/ui/scores.ui")]
+public class ScoreDialog : Dialog
{
private History history;
private HistoryEntry? selected_entry = null;
- private Gtk.ListStore level_model;
- private Gtk.ListStore score_model;
- private Gtk.ComboBox level_combo;
- private Gtk.TreeView scores;
- public ScoreDialog (History history, HistoryEntry? selected_entry = null, bool show_close = false)
+ [GtkChild]
+ private Gtk.ListStore levels_liststore;
+ [GtkChild]
+ private Gtk.ListStore scores_liststore;
+ [GtkChild]
+ private ComboBox level_combo;
+ [GtkChild]
+ private TreeView scores_tree;
+
+ public ScoreDialog (History history, HistoryEntry? selected_entry = null)
{
+ bool use_header = Gtk.Settings.get_default ().gtk_dialogs_use_header;
+ Object (use_header_bar: use_header ? 1 : 0);
+ if (!use_header)
+ add_button (_("_OK"), ResponseType.DELETE_EVENT);
+
this.history = history;
history.entry_added.connect (entry_added_cb);
this.selected_entry = selected_entry;
- if (show_close)
- {
- add_button (_("_Close"), Gtk.ResponseType.CLOSE);
- add_button (_("New Game"), Gtk.ResponseType.OK);
- }
- else
- add_button (_("_OK"), Gtk.ResponseType.DELETE_EVENT);
- set_size_request (200, 300);
-
- var vbox = new Gtk.Box (Gtk.Orientation.VERTICAL, 5);
- vbox.border_width = 6;
- vbox.show ();
- get_content_area ().pack_start (vbox, true, true, 0);
+ level_combo.changed.connect (level_changed_cb);
- var hbox = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 6);
- hbox.show ();
- vbox.pack_start (hbox, false, false, 0);
+ foreach (var entry in history.entries)
+ entry_added_cb (entry);
+ }
- var label = new Gtk.Label (_("Puzzle:"));
- label.show ();
- hbox.pack_start (label, false, false, 0);
+ /*\
+ * * Combo reaction
+ \*/
- level_model = new Gtk.ListStore (2, typeof (string), typeof (int)); // puzzle name, level
+ private void level_changed_cb (ComboBox combo)
+ {
+ TreeIter iter;
+ if (!combo.get_active_iter (out iter))
+ return;
- level_combo = new Gtk.ComboBox ();
- level_combo.changed.connect (level_changed_cb);
- level_combo.model = level_model;
- var renderer = new Gtk.CellRendererText ();
- level_combo.pack_start (renderer, true);
- level_combo.add_attribute (renderer, "text", 0);
- level_combo.show ();
- hbox.pack_start (level_combo, true, true, 0);
-
- var scroll = new Gtk.ScrolledWindow (null, null);
- scroll.shadow_type = Gtk.ShadowType.ETCHED_IN;
- scroll.set_policy (Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
- scroll.show ();
- vbox.pack_start (scroll, true, true, 0);
-
- score_model = new Gtk.ListStore (3, typeof (string), typeof (string), typeof (int));
-
- scores = new Gtk.TreeView ();
- renderer = new Gtk.CellRendererText ();
- scores.insert_column_with_attributes (-1, _("Date"), renderer, "text", 0, "weight", 2);
- renderer = new Gtk.CellRendererText ();
- renderer.xalign = 1.0f;
- scores.insert_column_with_attributes (-1, _("Moves"), renderer, "text", 1, "weight", 2);
- scores.model = score_model;
- scores.show ();
- scroll.add (scores);
+ int level;
+ levels_liststore.get (iter, 1, out level);
- foreach (var entry in history.entries)
- entry_added_cb (entry);
+/* set_level ((uint) level);
}
- public void set_level (uint level)
+ public void set_level (uint level) // TODO why??
{
- score_model.clear ();
+ TreeIter iter;
+*/
+ scores_liststore.clear ();
var entries = history.entries.copy ();
entries.sort (compare_entries);
@@ -90,30 +72,34 @@
if (entry.level != level)
continue;
- var date_label = entry.date.format ("%d/%m/%Y");
-
+ var date_label = entry.date.format ("%d/%m/%Y"); // TODO
var moves_label = "%u".printf (entry.moves);
- int weight = Pango.Weight.NORMAL;
- if (entry == selected_entry)
- weight = Pango.Weight.BOLD;
+ scores_liststore.append (out iter);
- Gtk.TreeIter iter;
- score_model.append (out iter);
- score_model.set (iter, 0, date_label, 1, moves_label, 2, weight);
-
- if (entry == selected_entry)
+ if (entry != selected_entry)
+ {
+ scores_liststore.set (iter,
+ 0, date_label,
+ 1, moves_label,
+ 2, Pango.Weight.NORMAL);
+ }
+ else
{
+ scores_liststore.set (iter,
+ 0, date_label,
+ 1, moves_label,
+ 2, Pango.Weight.BOLD);
var piter = iter;
- if (score_model.iter_previous (ref piter))
+ if (scores_liststore.iter_previous (ref piter))
{
var ppiter = piter;
- if (score_model.iter_previous (ref ppiter))
+ if (scores_liststore.iter_previous (ref ppiter))
piter = ppiter;
}
else
piter = iter;
- scores.scroll_to_cell (score_model.get_path (piter), null, false, 0, 0);
+ scores_tree.scroll_to_cell (scores_liststore.get_path (piter), null, false, 0, 0);
}
}
}
@@ -127,41 +113,36 @@
return a.date.compare (b.date);
}
- private void level_changed_cb (Gtk.ComboBox combo)
- {
- Gtk.TreeIter iter;
- if (!combo.get_active_iter (out iter))
- return;
-
- int level;
- combo.model.get (iter, 1, out level);
- set_level ((uint) level);
- }
+ /*\
+ * * Combo and TreeView population
+ \*/
private void entry_added_cb (HistoryEntry entry)
{
/* Ignore if already have an entry for this */
- Gtk.TreeIter iter;
+ TreeIter iter;
var have_level_entry = false;
- if (level_model.get_iter_first (out iter))
+ if (levels_liststore.get_iter_first (out iter))
{
do
{
uint level;
- level_model.get (iter, 1, out level);
+ levels_liststore.get (iter, 1, out level);
if (level == entry.level)
{
have_level_entry = true;
break;
}
- } while (level_model.iter_next (ref iter));
+ } while (levels_liststore.iter_next (ref iter));
}
if (!have_level_entry)
{
var label = _(Klotski.level[entry.level].name);
- level_model.append (out iter);
- level_model.set (iter, 0, label, 1, entry.level, -1);
+ levels_liststore.append (out iter);
+ levels_liststore.set (iter,
+ 0, label,
+ 1, entry.level);
/* Select this entry if don't have any */
if (level_combo.get_active () == -1)
@@ -170,7 +151,6 @@
/* Select this entry if the same category as the selected one */
if (selected_entry != null && entry.level == selected_entry.level)
level_combo.set_active_iter (iter);
-
}
}
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]