[gnome-games/sudoku-vala] Port of Sudoku from Python to Vala



commit bb0c39f08565484cb887edc7e8f105ec72ee11b8
Author: Robert Ancell <robert ancell canonical com>
Date:   Wed Dec 8 18:38:16 2010 +1100

    Port of Sudoku from Python to Vala

 configure.in                                      |   11 +-
 gnome-sudoku/AUTHORS                              |    1 -
 gnome-sudoku/ChangeLog.old                        |  763 ---------------
 gnome-sudoku/README                               |   16 -
 gnome-sudoku/data/Makefile.am                     |   30 +-
 gnome-sudoku/data/gnome-sudoku.schemas.in         |  329 -------
 gnome-sudoku/data/gnome-sudoku.ui                 |  376 ++++++++
 gnome-sudoku/data/print_games.ui                  |  327 -------
 gnome-sudoku/data/select_game.ui                  |  135 ---
 gnome-sudoku/data/tracker.ui                      |  104 --
 gnome-sudoku/src/Makefile.am                      |   26 +-
 gnome-sudoku/src/gnome-sudoku.in.in               |   67 --
 gnome-sudoku/src/gnome-sudoku.vala                |  343 +++++++
 gnome-sudoku/src/lib/Makefile.am                  |   30 -
 gnome-sudoku/src/lib/__init__.py                  |    1 -
 gnome-sudoku/src/lib/colors.py                    |   85 --
 gnome-sudoku/src/lib/dancer.py                    |  136 ---
 gnome-sudoku/src/lib/defaults.py.in               |   70 --
 gnome-sudoku/src/lib/dialog_swallower.py          |   77 --
 gnome-sudoku/src/lib/game_selector.py             |  282 ------
 gnome-sudoku/src/lib/gnome_sudoku.py              |   22 -
 gnome-sudoku/src/lib/gsudoku.py                   |  813 ----------------
 gnome-sudoku/src/lib/gtk_goodies/Makefile.am      |    8 -
 gnome-sudoku/src/lib/gtk_goodies/Undo.py          |  473 ----------
 gnome-sudoku/src/lib/gtk_goodies/__init__.py      |    1 -
 gnome-sudoku/src/lib/gtk_goodies/dialog_extras.py |  231 -----
 gnome-sudoku/src/lib/gtk_goodies/gconf_wrapper.py |  206 ----
 gnome-sudoku/src/lib/main.py                      | 1038 ---------------------
 gnome-sudoku/src/lib/number_box.py                |  821 ----------------
 gnome-sudoku/src/lib/pausable.py                  |   65 --
 gnome-sudoku/src/lib/printing.py                  |  210 -----
 gnome-sudoku/src/lib/saver.py                     |  267 ------
 gnome-sudoku/src/lib/simple_debug.py              |   45 -
 gnome-sudoku/src/lib/sudoku.py                    |  912 ------------------
 gnome-sudoku/src/lib/sudoku_maker.py              |  607 ------------
 gnome-sudoku/src/lib/sudoku_thumber.py            |  162 ----
 gnome-sudoku/src/lib/timer.py                     |   87 --
 gnome-sudoku/src/lib/tracker_info.py              |  208 ----
 gnome-sudoku/src/sudoku-game.vala                 |  147 +++
 gnome-sudoku/src/sudoku-view.vala                 |  278 ++++++
 40 files changed, 1169 insertions(+), 8641 deletions(-)
---
diff --git a/configure.in b/configure.in
index c1fdaf2..46750e7 100644
--- a/configure.in
+++ b/configure.in
@@ -141,7 +141,7 @@ for game in $gamelist; do
     *) ;;
   esac
   case $game in
-    glchess|gnome-sudoku) need_python=yes ;;
+    glchess) need_python=yes ;;
     *) ;;
   esac
   case $game in
@@ -208,6 +208,7 @@ PKG_PROG_PKG_CONFIG([0.15])
 
 AC_PROG_CC
 AC_PROG_CPP
+AM_PROG_VALAC
 AC_PROG_LN_S
 AC_PROG_SED
 
@@ -608,6 +609,10 @@ PKG_CHECK_MODULES([GTHREAD],[gthread-2.0])
 AC_SUBST([GTHREAD_CFLAGS])
 AC_SUBST([GTHREAD_LIBS])
 
+PKG_CHECK_MODULES([GMODULE],[gmodule-2.0])
+AC_SUBST([GMODULE_CFLAGS])
+AC_SUBST([GMODULE_LIBS])
+
 PKG_CHECK_MODULES([GTK],[gtk+-$GTK_API_VERSION >= $GTK_REQUIRED])
 AC_SUBST([GTK_CFLAGS])
 AC_SUBST([GTK_LIBS])
@@ -1187,11 +1192,7 @@ glchess/src/lib/scene/cairo/Makefile
 glchess/src/lib/scene/opengl/Makefile
 glchess/src/lib/ui/Makefile
 gnome-sudoku/Makefile
-gnome-sudoku/src/gnome-sudoku.in
 gnome-sudoku/src/Makefile
-gnome-sudoku/src/lib/Makefile
-gnome-sudoku/src/lib/defaults.py
-gnome-sudoku/src/lib/gtk_goodies/Makefile
 gnome-sudoku/data/Makefile
 gnome-sudoku/images/Makefile
 gnome-sudoku/help/Makefile
diff --git a/gnome-sudoku/data/Makefile.am b/gnome-sudoku/data/Makefile.am
index 5049082..5da5d41 100644
--- a/gnome-sudoku/data/Makefile.am
+++ b/gnome-sudoku/data/Makefile.am
@@ -7,41 +7,13 @@ puzzle_DATA = \
 
 uidir = $(datadir)/gnome-sudoku
 ui_DATA = \
-	print_games.ui \
-	select_game.ui \
-	tracker.ui
-
-schema_in_files = gnome-sudoku.schemas.in
-if HAVE_GNOME
-schemadir = $(GCONF_SCHEMA_FILE_DIR)
-schema_DATA = $(schema_in_files:.schemas.in=.schemas)
-endif
-
-install-schemas-local: $(schema_DATA)
-if GCONF_SCHEMAS_INSTALL
-	if test -z "$(DESTDIR)" ; then \
-		for p in $^ ; do \
-			GCONF_CONFIG_SOURCE=$(GCONF_SCHEMA_CONFIG_SOURCE) $(GCONFTOOL) --makefile-install-rule $$p 2>&1 > /dev/null; \
-		done \
-	fi
-endif
-
-install-data-local: install-schemas-local
+	gnome-sudoku.ui 
 
 man_MANS = gnome-sudoku.6
 
 EXTRA_DIST = \
 	$(puzzle_DATA)	\
 	$(ui_DATA)	\
-	$(schema_in_files) \
 	$(man_MANS)
 
-CLEANFILES = \
-	$(schema_DATA)
-
-DISTCLEANFILES = \
-	$(schema_DATA)
-
- INTLTOOL_SCHEMAS_RULE@
-
 -include $(top_srcdir)/git.mk
diff --git a/gnome-sudoku/data/gnome-sudoku.ui b/gnome-sudoku/data/gnome-sudoku.ui
new file mode 100644
index 0000000..8c17ffe
--- /dev/null
+++ b/gnome-sudoku/data/gnome-sudoku.ui
@@ -0,0 +1,376 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <requires lib="gtk+" version="2.16"/>
+  <!-- interface-naming-policy project-wide -->
+  <object class="GtkWindow" id="sudoku_app">
+    <property name="title" translatable="yes">Sudoku</property>
+    <signal name="delete_event" handler="quit_cb"/>
+    <child>
+      <object class="GtkVBox" id="main_vbox">
+        <property name="visible">True</property>
+        <child>
+          <object class="GtkMenuBar" id="sudoku_menubar">
+            <property name="visible">True</property>
+            <child>
+              <object class="GtkMenuItem" id="game_menuitem">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">_Game</property>
+                <property name="use_underline">True</property>
+                <child type="submenu">
+                  <object class="GtkMenu" id="game_menu">
+                    <property name="visible">True</property>
+                    <child>
+                      <object class="GtkMenuItem" id="new_game_imagemenuitem">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">New</property>
+                        <property name="use_underline">True</property>
+                        <accelerator key="n" signal="activate" modifiers="GDK_CONTROL_MASK"/>
+                        <signal name="activate" handler="new_game_cb"/>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkMenuItem" id="reset_game_imagemenuitem">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">Reset</property>
+                        <property name="use_underline">True</property>
+                        <accelerator key="b" signal="activate" modifiers="GDK_CONTROL_MASK"/>
+                        <signal name="activate" handler="reset_game_cb"/>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkSeparatorMenuItem" id="game_menu_separator0">
+                        <property name="visible">True</property>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkMenuItem" id="undo_imagemenuitem">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">Undo</property>
+                        <property name="use_underline">True</property>
+                        <accelerator key="z" signal="activate" modifiers="GDK_CONTROL_MASK"/>
+                        <signal name="activate" handler="undo_cb"/>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkMenuItem" id="redo_imagemenuitem">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">Redo</property>
+                        <property name="use_underline">True</property>
+                        <accelerator key="z" signal="activate" modifiers="GDK_SHIFT_MASK | GDK_CONTROL_MASK"/>
+                        <signal name="activate" handler="redo_cb"/>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkSeparatorMenuItem" id="game_menu_separator1">
+                        <property name="visible">True</property>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkMenuItem" id="statistics_menuitem">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">Puzzle Statistics...</property>
+                        <property name="use_underline">True</property>
+                        <signal name="activate" handler="statistics_cb"/>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkSeparatorMenuItem" id="game_menu_separator2">
+                        <property name="visible">True</property>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkMenuItem" id="print_menuitem">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">Print...</property>
+                        <property name="use_underline">True</property>
+                        <accelerator key="p" signal="activate" modifiers="GDK_CONTROL_MASK"/>
+                        <signal name="activate" handler="print_cb"/>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkMenuItem" id="print_multiple_menuitem">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">Print Multiple Sudokus...</property>
+                        <property name="use_underline">True</property>
+                        <signal name="activate" handler="print_multiple_cb"/>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkSeparatorMenuItem" id="game_menu_separator3">
+                        <property name="visible">True</property>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkMenuItem" id="quit_imagemenuitem">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">Close</property>
+                        <property name="use_underline">True</property>
+                        <signal name="activate" handler="quit_cb"/>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+            <child>
+              <object class="GtkMenuItem" id="settings_menuitem">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">_Settings</property>
+                <property name="use_underline">True</property>
+                <child type="submenu">
+                  <object class="GtkMenu" id="settings_menu">
+                    <property name="visible">True</property>
+                    <child>
+                      <object class="GtkCheckMenuItem" id="toggle_fullscreen_imagemenuitem">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">Fullscreen</property>
+                        <property name="use_underline">True</property>
+                        <accelerator key="F11" signal="activate"/>
+                        <signal name="toggled" handler="toggle_fullscreen_cb"/>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkCheckMenuItem" id="toggle_toolbar_imagemenuitem">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">Show Toolbar</property>
+                        <property name="use_underline">True</property>
+                        <signal name="toggled" handler="toggle_toolbar_cb"/>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkSeparatorMenuItem" id="settings_menu_separator0">
+                        <property name="visible">True</property>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkCheckMenuItem" id="toggle_highlighter_imagemenuitem">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">Hilighter</property>
+                        <property name="use_underline">True</property>
+                        <signal name="toggled" handler="toggle_highlighter_cb"/>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkCheckMenuItem" id="toggle_hints_menuitem">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">Show Possible Numbers</property>
+                        <property name="use_underline">True</property>
+                        <signal name="toggled" handler="toggle_hints_cb"/>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkCheckMenuItem" id="toggle_warnings_menuitem">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">Warn About Unfillable Squares</property>
+                        <property name="use_underline">True</property>
+                        <signal name="toggled" handler="toggle_warnings_cb"/>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+            <child>
+              <object class="GtkMenuItem" id="tools_menuitem">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">Tools</property>
+                <property name="use_underline">True</property>
+                <child type="submenu">
+                  <object class="GtkMenu" id="tools_menu">
+                    <property name="visible">True</property>
+                    <child>
+                      <object class="GtkMenuItem" id="hint_menuitem">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">Hint</property>
+                        <property name="use_underline">True</property>
+                        <accelerator key="h" signal="activate" modifiers="GDK_CONTROL_MASK"/>
+                        <signal name="activate" handler="hint_cb"/>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkSeparatorMenuItem" id="tools_menu_separator0">
+                        <property name="visible">True</property>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkMenuItem" id="clear_top_notes_menuitem">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">Clear Top Notes</property>
+                        <property name="use_underline">True</property>
+                        <accelerator key="j" signal="activate" modifiers="GDK_CONTROL_MASK"/>
+                        <signal name="activate" handler="clear_top_notes_cb"/>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkMenuItem" id="clear_bottom_notes_menuitem">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">Clear Bottom Notes</property>
+                        <property name="use_underline">True</property>
+                        <accelerator key="k" signal="activate" modifiers="GDK_CONTROL_MASK"/>
+                        <signal name="activate" handler="clear_bottom_notes_cb"/>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkSeparatorMenuItem" id="tools_menu_separator1">
+                        <property name="visible">True</property>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkCheckMenuItem" id="toggle_tracker_menuitem">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">Track Additions</property>
+                        <property name="use_underline">True</property>
+                        <accelerator key="t" signal="activate" modifiers="GDK_CONTROL_MASK"/>
+                        <signal name="toggled" handler="toggle_tracker_cb"/>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+            <child>
+              <object class="GtkMenuItem" id="help_menuitem">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">_Help</property>
+                <property name="use_underline">True</property>
+                <child type="submenu">
+                  <object class="GtkMenu" id="help_menu">
+                    <property name="visible">True</property>
+                    <child>
+                      <object class="GtkMenuItem" id="help_imagemenuitem">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">Contents</property>
+                        <property name="use_underline">True</property>
+                        <accelerator key="F1" signal="activate"/>
+                        <signal name="activate" handler="help_cb"/>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkMenuItem" id="about_menuitem">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">About</property>
+                        <property name="use_underline">True</property>
+                        <signal name="activate" handler="about_cb"/>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkToolbar" id="sudoku_toolbar">
+            <property name="visible">True</property>
+            <child>
+              <object class="GtkToolButton" id="new_game_toolbutton">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">New</property>
+                <property name="use_underline">True</property>
+                <property name="stock_id">gtk-new</property>
+                <signal name="clicked" handler="new_game_cb"/>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="homogeneous">True</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkSeparatorToolItem" id="toolbar_separator0">
+                <property name="visible">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="homogeneous">True</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkToolButton" id="undo_toolbutton">
+                <property name="visible">True</property>
+                <property name="is_important">True</property>
+                <property name="label" translatable="yes">Undo</property>
+                <property name="use_underline">True</property>
+                <property name="stock_id">gtk-undo</property>
+                <signal name="clicked" handler="undo_cb"/>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="homogeneous">True</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkToolButton" id="redo_toolbutton">
+                <property name="visible">True</property>
+                <property name="is_important">True</property>
+                <property name="label" translatable="yes">Redo</property>
+                <property name="use_underline">True</property>
+                <property name="stock_id">gtk-redo</property>
+                <signal name="clicked" handler="redo_cb"/>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="homogeneous">True</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkSeparatorToolItem" id="toolbar_separator1">
+                <property name="visible">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="homogeneous">True</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkToolButton" id="hint_toolbutton">
+                <property name="visible">True</property>
+                <property name="is_important">True</property>
+                <property name="label" translatable="yes">Hint</property>
+                <property name="use_underline">True</property>
+                <property name="stock_id">gtk-info</property>
+                <signal name="clicked" handler="hint_cb"/>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="homogeneous">True</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkSeparatorToolItem" id="toolbar_separator2">
+                <property name="visible">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="homogeneous">True</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkToolButton" id="toggle_tracker_toolbutton">
+                <property name="visible">True</property>
+                <property name="is_important">True</property>
+                <property name="label" translatable="yes">Track Additions</property>
+                <property name="use_underline">True</property>
+                <signal name="clicked" handler="toggle_tracker_cb"/>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="homogeneous">True</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
+          <placeholder/>
+        </child>
+      </object>
+    </child>
+  </object>
+</interface>
diff --git a/gnome-sudoku/src/Makefile.am b/gnome-sudoku/src/Makefile.am
index cb34ee0..be5a239 100644
--- a/gnome-sudoku/src/Makefile.am
+++ b/gnome-sudoku/src/Makefile.am
@@ -1,12 +1,22 @@
-SUBDIRS = lib
+bin_PROGRAMS = gnome-sudoku
 
-#################################################################
+gnome_sudoku_SOURCES = \
+	gnome-sudoku.vala \
+	sudoku-game.vala \
+	sudoku-view.vala
 
-## Executable
-bin_SCRIPTS = gnome-sudoku
-CLEANFILES  = gnome-sudoku gnome-sudoku.in
+gnome_sudoku_CFLAGS = \
+	$(GTK_CFLAGS) \
+	$(GMODULE_CFLAGS) \
+	$(WARN_CFLAGS)
 
-gnome-sudoku: gnome-sudoku.in
-	$(AM_V_GEN) cp gnome-sudoku.in $@ && chmod u+x $@
+gnome_sudoku_LDADD = \
+	$(GTK_LIBS) \
+	$(GMODULE_LIBS)
 
--include $(top_srcdir)/git.mk
+gnome_sudoku_VALAFLAGS = \
+    --pkg gtk+-3.0 \
+    --pkg gmodule-2.0
+
+DISTCLEANFILES = \
+	Makefile.in
diff --git a/gnome-sudoku/src/gnome-sudoku.vala b/gnome-sudoku/src/gnome-sudoku.vala
new file mode 100644
index 0000000..b849b2a
--- /dev/null
+++ b/gnome-sudoku/src/gnome-sudoku.vala
@@ -0,0 +1,343 @@
+public class Application
+{
+    private Gtk.Builder builder;
+
+    private SudokuGame game;
+
+    private Gtk.Window window;
+    private SudokuView view;
+
+    private Gtk.AboutDialog? about_dialog = null;
+
+    public Application ()
+    {
+        builder = new Gtk.Builder ();
+        try
+        {
+            builder.add_from_file ("data/gnome-sudoku.ui");
+        }
+        catch (GLib.Error e)
+        {
+            GLib.warning ("Could not load UI: %s", e.message);
+        }
+        window = (Gtk.Window) builder.get_object ("sudoku_app");
+        var main_vbox = (Gtk.VBox) builder.get_object ("main_vbox");
+
+        game = new SudokuGame ();
+        game.set_from_string ("---------" +
+                              "-----3-85" +
+                              "--1-2----" +
+                              "---5-7---" +
+                              "--4---1--" +
+                              "-9-------" +
+                              "5------73" +
+                              "--2-1----" +
+                              "----4---9");
+        game.set_from_string ("1.......2.9.4...5...6...7...5.9.3.......7.......85..4.7.....6...3...9.8...2.....1");
+        view = new SudokuView (game);
+        view.show ();
+        main_vbox.pack_start (view);
+        
+        builder.connect_signals (this);
+    }
+    
+    public void start ()
+    {
+        show ();
+    }
+
+    public void show ()
+    {
+        window.show ();
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT new_game_cb", instance_pos = -1)]
+    public void new_game_cb (Gtk.Widget widget)
+    {
+        stdout.printf ("TODO: new game\n");
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT reset_game_cb", instance_pos = -1)]
+    public void reset_game_cb (Gtk.Widget widget)
+    {
+        game.reset ();
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT undo_cb", instance_pos = -1)]
+    public void undo_cb (Gtk.Widget widget)
+    {
+        game.undo ();
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT redo_cb", instance_pos = -1)]
+    public void redo_cb (Gtk.Widget widget)
+    {
+        game.redo ();
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT statistics_cb", instance_pos = -1)]
+    public void statistics_cb (Gtk.Widget widget)
+    {
+        stdout.printf ("TODO: Show statistics\n");
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT print_cb", instance_pos = -1)]
+    public void print_cb (Gtk.Widget widget)
+    {
+        stdout.printf ("TODO: Print\n");    
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT print_multiple_cb", instance_pos = -1)]
+    public void print_multiple_cb (Gtk.Widget widget)
+    {
+        stdout.printf ("TODO: Print multiple\n");
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT quit_cb", instance_pos = -1)]
+    public void quit_cb (Gtk.Widget widget)
+    {
+        Gtk.main_quit ();
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT toggle_fullscreen_cb", instance_pos = -1)]
+    public void toggle_fullscreen_cb (Gtk.Widget widget)
+    {
+        stdout.printf ("TODO: Toggle fullscreen\n");
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT toggle_toolbar_cb", instance_pos = -1)]
+    public void toggle_toolbar_cb (Gtk.Widget widget)
+    {
+        stdout.printf ("TODO: Toggle toolbar\n");
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT toggle_highlighter_cb", instance_pos = -1)]
+    public void toggle_highlighter_cb (Gtk.Widget widget)
+    {
+        view.show_highlights = !view.show_highlights;
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT toggle_hints_cb", instance_pos = -1)]
+    public void toggle_hints_cb (Gtk.Widget widget)
+    {
+        view.show_hints = !view.show_hints;
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT toggle_warnings_cb", instance_pos = -1)]
+    public void toggle_warnings_cb (Gtk.Widget widget)
+    {
+        view.show_warnings = !view.show_warnings;    
+    }
+
+    private bool row_has_value (int row, int value)
+    {
+        for (var col = 0; col < 9; col++)
+        {
+            if (game.cells[row, col].value == value)
+                return true;
+        }
+        return false;
+    }
+
+    private int row_count_possibilities (int row, int value, out int col_match)
+    {
+        int n = 0;
+        for (var col = 0; col < 9; col++)
+        {
+            if (game.cells[row, col].value == 0 && game.cells[row, col].can_be (value))
+            {
+                col_match = col;
+                n++;
+            }
+        }
+        return n;
+    }
+
+    private bool col_has_value (int col, int value)
+    {
+        for (var row = 0; row < 9; row++)
+        {
+            if (game.cells[row, col].value == value)
+                return true;
+        }
+        return false;
+    }
+
+    private int col_count_possibilities (int col, int value, out int row_match)
+    {
+        int n = 0;
+        for (var row = 0; row < 9; row++)
+        {
+            if (game.cells[row, col].value == 0 && game.cells[row, col].can_be (value))
+            {
+                row_match = row;
+                n++;
+            }
+        }
+        return n;
+    }
+
+    private bool cell_has_value (int row, int col, int value)
+    {
+        for (var r = 0; r < 3; r++)
+            for (var c = 0; c < 3; c++)
+            {
+                if (game.cells[row*3+r, col*3+c].value == value)
+                    return true;
+            }
+        return false;
+    }
+
+    private int cell_count_possibilities (int row, int col, int value, out int match_row, out int match_col)
+    {
+        int n = 0;
+        for (var r = 0; r < 3; r++)
+            for (var c = 0; c < 3; c++)
+            {
+                var cell = game.cells[row*3+r, col*3+c];
+                if (cell.value == 0 && cell.can_be (value))
+                {
+                    match_row = row*3+r;
+                    match_col = col*3+c;
+                    n++;
+                }
+            }
+        return n;
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT hint_cb", instance_pos = -1)]
+    public void hint_cb (Gtk.Widget widget)
+    {
+        stdout.printf ("TODO: Show hint\n");
+
+        // TEMP: Fill any square with only one possible value
+        for (int col = 0; col < 9; col++)
+            for (int row = 0; row < 9; row++)
+            {
+                var cell = game.cells[row, col];
+                if (cell.value != 0 || cell.n_possibilities != 1)
+                    continue;
+                for (int value = 1; value <= 9; value++)
+                    if (cell.can_be (value))
+                    {
+                        cell.value = value;
+                        return;
+                    }
+            }
+
+        for (int value = 1; value < 9; value++)
+        {
+            for (int row = 0; row < 9; row++)
+            {
+                int col = 0;
+                if (!row_has_value (row, value) && row_count_possibilities (row, value, out col) == 1)
+                {
+                    game.cells[row, col].value = value;
+                    return;
+                }
+            }
+            for (int col = 0; col < 9; col++)
+            {
+                int row = 0;
+                if (!col_has_value (col, value) && col_count_possibilities (col, value, out row) == 1)
+                {
+                    game.cells[row, col].value = value;
+                    return;
+                }
+            }
+            for (int r = 0; r < 3; r++)
+            {
+                for (int c = 0; c < 3; c++)
+                {
+                    int row = 0, col = 0;
+                    if (!cell_has_value (r, c, value) && cell_count_possibilities (r, c, value, out row, out col) == 1)
+                    {
+                        game.cells[row, col].value = value;
+                        return;
+                    }
+                }
+            }
+        }
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT clear_top_notes_cb", instance_pos = -1)]
+    public void clear_top_notes_cb (Gtk.Widget widget)
+    {
+        view.clear_top_notes ();
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT clear_bottom_notes_cb", instance_pos = -1)]
+    public void clear_bottom_notes_cb (Gtk.Widget widget)
+    {
+        view.clear_bottom_notes ();
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT toggle_tracker_cb", instance_pos = -1)]
+    public void toggle_tracker_cb (Gtk.Widget widget)
+    {
+        stdout.printf ("TODO: Toggle tracker\n");
+    }
+
+    [CCode (cname = "G_MODULE_EXPORT help_cb", instance_pos = -1)]
+    public void help_cb (Gtk.Widget widget)
+    {
+        try
+        {
+            Gtk.show_uri (window.get_screen (), "ghelp:gnome-sudoku", Gtk.get_current_event_time ());
+        }
+        catch (GLib.Error e)
+        {
+            GLib.warning ("Unable to open help: %s", e.message);
+        }
+    }
+
+    private const string[] authors = { "Robert Ancell <robert ancell gmail com>" };
+    private const string[] artists = { "" };
+
+    [CCode (cname = "G_MODULE_EXPORT about_cb", instance_pos = -1)]
+    public void about_cb (Gtk.Widget widget)
+    {
+        if (about_dialog != null)
+        {
+            about_dialog.present ();
+            return;
+        }
+
+        about_dialog = new Gtk.AboutDialog ();
+        about_dialog.transient_for = window;
+        about_dialog.name = "gnome-sudoku";
+        about_dialog.version = "TEST";
+        about_dialog.copyright = "Copyright 2010";
+        about_dialog.license = "LICENSE";
+        about_dialog.wrap_license = true;
+        about_dialog.comments = "Description";
+        about_dialog.authors = authors;
+        about_dialog.artists = artists;
+        about_dialog.translator_credits = "";
+        about_dialog.website = "http://example.com";;
+        about_dialog.logo_icon_name = "gnome-sudoku";
+        about_dialog.response.connect (about_response_cb);
+        about_dialog.show ();
+    }
+
+    private void about_response_cb (int response_id)
+    {
+        about_dialog.destroy ();
+        about_dialog = null;
+    }
+}
+
+class GlChess
+{
+    public static int main (string[] args)
+    {
+        Gtk.init (ref args);
+
+        Application app = new Application ();
+        app.start ();
+
+        Gtk.main ();
+
+        return 0;
+    }
+}
diff --git a/gnome-sudoku/src/sudoku-game.vala b/gnome-sudoku/src/sudoku-game.vala
new file mode 100644
index 0000000..24eecc8
--- /dev/null
+++ b/gnome-sudoku/src/sudoku-game.vala
@@ -0,0 +1,147 @@
+public class SudokuCell
+{
+    public int row;
+    public int col;
+
+    public bool possible_values[9];
+
+    public int n_possibilities
+    {
+        get
+        {
+            int n = 0;
+            for (int i = 1; i <= 9; i++)
+                if (possible_values[i-1])
+                    n++;
+            return n;
+        }
+    }
+
+    public bool can_be (int value)
+    {
+        return possible_values[value-1];
+    }
+
+    private int _value = 0;
+    public int value
+    {
+        set
+        {
+            if (is_fixed)
+                return;
+            if (_value == value)
+                return;
+            _value = value;
+            value_changed ();
+        }
+        get { return _value; }
+    }
+
+    public bool _is_fixed = false;
+    public bool is_fixed
+    {
+       set
+       {
+          _is_fixed = value;
+          value_changed ();
+       }
+       get { return _is_fixed; }
+    }
+
+    public signal void value_changed ();
+    
+    public SudokuCell (int row, int col)
+    {
+        this.row = row;
+        this.col = col;
+        for (var i = 0; i < 8; i++)
+            possible_values[i] = true;
+    }
+}
+
+public class SudokuGame
+{
+    public SudokuCell[,] cells;
+    
+    public signal void cell_changed (SudokuCell cell);
+
+    public SudokuGame ()
+    {
+        cells = new SudokuCell[9,9];
+        for (int row = 0; row < 9; row++)
+            for (int col = 0; col < 9; col++)
+            {
+                var cell = new SudokuCell (row, col);
+                cells[row, col] = cell;
+                cell.value_changed.connect (cell_changed_cb);
+            }
+    }
+
+    public SudokuGame.from_string (string game)
+    {
+        this ();
+        set_from_string (game);
+    }
+    
+    public void set_from_string (string game)
+    {
+        assert (game.length == 81);
+        for (var i = 0; i < game.length; i++)
+        {
+            var col = i % 9;
+            var row = i / 9;
+            var digit = 0;
+            var is_fixed = false;
+
+            if (game[i] >= '1' && game[i] <= '9')
+            {
+                digit = (int) game[i] - '0';
+                is_fixed = true;
+            }
+
+            var cell = cells[row, col];
+            cell.is_fixed = false;
+            cell.value = digit;
+            cell.is_fixed = is_fixed;
+        }
+    }
+
+    public void undo ()
+    {
+        stdout.printf ("TODO: undo\n");    
+    }
+
+    public void redo ()
+    {
+        stdout.printf ("TODO: redo\n");    
+    }
+
+    public void reset ()
+    {
+        stdout.printf ("TODO: reset\n");
+    }
+
+    private void cell_changed_cb (SudokuCell cell)
+    {
+        /* Blank out adjacent squares */
+        if (cell.value > 0)
+        {
+            for (int row = 0; row < 9; row++)
+            {
+                for (int col = 0; col < 9; col++)
+                {
+                    if (row == cell.row && col == cell.col)
+                        continue;
+                    if (row == cell.row ||
+                        col == cell.col ||
+                        (row % 3 == cell.row % 3 && col % 3 == cell.col % 3))
+                    {
+                        cells[row, col].possible_values[cell.value-1] = false;
+                    }
+                }
+            }
+        }
+
+        cell_changed (cell);
+    }
+}
diff --git a/gnome-sudoku/src/sudoku-view.vala b/gnome-sudoku/src/sudoku-view.vala
new file mode 100644
index 0000000..89ed19d
--- /dev/null
+++ b/gnome-sudoku/src/sudoku-view.vala
@@ -0,0 +1,278 @@
+private class SudokuCellView : Gtk.DrawingArea
+{
+    private Pango.Layout layout;
+    
+    private Gtk.Window? popup = null;
+
+    private SudokuCell _cell;
+    public SudokuCell cell
+    {
+        set
+        {
+            _cell = value;
+            _cell.value_changed.connect (value_changed_cb);
+            value_changed_cb (value);
+        }
+        get { return _cell; }
+    }
+
+    private string _text;
+    public string text
+    {
+        set
+        {
+            _text = value;
+            layout = create_pango_layout (_text);
+            layout.set_font_description (style.font_desc);
+            queue_draw ();
+        }
+        get { return _text; }
+    }
+    
+    public int value
+    {
+        set
+        {
+            if (value == 0)
+                text = "";
+            else
+                text = "%d".printf (value);
+        }
+    }
+
+    public SudokuCellView ()
+    {
+        can_focus = true;
+        style.font_desc.set_size (Pango.SCALE * 13);
+        text = "";
+        events = Gdk.EventMask.EXPOSURE_MASK | Gdk.EventMask.BUTTON_PRESS_MASK | Gdk.EventMask.KEY_PRESS_MASK;
+        focus_out_event.connect (focus_out_cb);
+    }
+
+    public override void get_preferred_width (out int minimal_width, out int natural_width)
+    {
+        int width, height, side;
+        layout.get_size (out width, out height);
+        side = width > height ? width : height;
+        minimal_width = natural_width = side / Pango.SCALE;
+    }
+
+    public override void get_preferred_height (out int minimal_height, out int natural_height)
+    {
+        int width, height, side;
+        layout.get_size (out width, out height);
+        side = width > height ? width : height;
+        minimal_height = natural_height = side / Pango.SCALE;
+    }
+
+    public override bool button_press_event (Gdk.EventButton event)
+    {
+        if (event.button != 1)
+            return false;
+
+        if (!is_focus)
+        {
+            grab_focus ();
+            return true;
+        }
+
+        if (event.y / get_allocated_height () < 0.25)
+            stdout.printf("upper notes\n");
+        else if (event.y / get_allocated_height () > 0.75)
+            stdout.printf("lower notes\n");
+        else
+            show_number_picker ();
+
+        return true;
+    }
+
+    private void show_number_picker ()
+    {
+        if (popup != null)
+            return;
+
+        popup = new Gtk.Window (Gtk.WindowType.POPUP);
+
+        var table = new Gtk.Table (3, 3, false);
+        for (int col = 0; col < 3; col++)
+            for (int row = 0; row < 3; row++)
+            {
+                int n = col + row * 3 + 1;
+
+                var button = new Gtk.Button ();
+                button.show ();
+
+                var label = new Gtk.Label ("<span size=\"x-small\">%d</span>".printf (n));
+                label.use_markup = true;
+                table.attach_defaults (button, col, col+1, row, row+1);
+                button.add (label);
+                label.show ();
+                
+                button.clicked.connect (picker_button_cb);
+
+                if (n == 5)
+                    button.grab_focus ();
+            }
+        table.show ();
+        popup.add (table);
+
+        int x, y, width, height;
+        get_window ().get_origin (out x, out y);
+        popup.get_size (out width, out height);
+        popup.move (x - (width - get_allocated_width ()) / 2, y - (height - get_allocated_height ()) / 2);
+        popup.show ();
+    }
+
+    private void hide_number_picker ()
+    {
+        if (popup == null)
+            return;
+        popup.destroy ();
+        popup = null;
+    }
+
+    private void picker_button_cb (Gtk.Button button)
+    {
+        hide_number_picker ();
+    }
+
+    private bool focus_out_cb (Gtk.Widget widget, Gdk.EventFocus event)
+    {
+        if (popup != null)
+            hide_number_picker ();
+        return false;
+    }
+
+    public override bool key_release_event (Gdk.EventKey event)
+    {
+        // FIXME: Can't find vala bindings to Gdk keyvals...
+
+        if (event.keyval >= 49 /* 1 */ && event.keyval <= 58 /* 9 */)
+        {
+            cell.value = (int)event.keyval - 48;
+            return true;
+        }
+
+        if (event.keyval == 48 || event.keyval == 65288 /* backspace */ || event.keyval == 65535 /* delete */)
+        {
+            cell.value = 0;
+            return true;
+        }
+        
+        if (event.keyval == 32 /* space */ || event.keyval == 65293 /* enter */)
+        {
+            show_number_picker ();
+            return true;
+        }
+
+        return false;
+    }
+
+    public override bool draw (Cairo.Context c)
+    {
+        if (is_focus)
+            Gdk.cairo_set_source_color (c, style.base[Gtk.StateType.SELECTED]);
+        else if (cell.is_fixed)
+            c.set_source_rgb (0.8, 0.8, 0.8);
+        else
+            c.set_source_rgb (1.0, 1.0, 1.0);
+        c.rectangle (0, 0, get_allocated_width (), get_allocated_height ());
+        c.fill ();
+
+        int glyph_width, glyph_height;
+        layout.get_pixel_size (out glyph_width, out glyph_height);
+        if (is_focus)
+            Gdk.cairo_set_source_color (c, style.text[Gtk.StateType.SELECTED]);
+        else
+            Gdk.cairo_set_source_color (c, style.text[Gtk.StateType.NORMAL]);
+
+        int width, height;
+        layout.get_size (out width, out height);
+
+        double scale = (double) get_allocated_width () / width;
+        c.move_to ((get_allocated_width () - glyph_width * scale) / 2, (get_allocated_height () - glyph_height * scale) / 2);
+        c.scale (scale, scale);
+        Pango.cairo_update_layout (c, layout);
+        Pango.cairo_show_layout (c, layout);
+
+        return false;
+    }
+
+    private void value_changed_cb (SudokuCell cell)
+    {
+        value = cell.value;
+        can_focus = !cell.is_fixed;
+    }
+}
+
+public class SudokuView : Gtk.AspectFrame
+{
+    private SudokuGame game;
+    private SudokuCellView[,] cells;
+
+    public SudokuView (SudokuGame game)
+    {
+        this.game = game;
+
+        shadow_type = Gtk.ShadowType.NONE;
+        
+        /* Use an EventBox to be able to set background */
+        var box = new Gtk.EventBox ();
+        box.modify_bg (Gtk.StateType.NORMAL, box.style.black);
+        add (box);
+        box.show ();
+
+        var table = new Gtk.Table (9, 9, true);
+        table.row_spacing = 1;
+        table.column_spacing = 1;
+        table.set_row_spacing (2, 2);
+        table.set_row_spacing (5, 2);
+        table.set_col_spacing (2, 2);
+        table.set_col_spacing (5, 2);
+        table.border_width = 2;
+
+        cells = new SudokuCellView[9,9];
+        for (int row = 0; row < 9; row++)
+            for (int col = 0; col < 9; col++)
+            {
+                var cell = new SudokuCellView ();
+                cells[row, col] = cell;
+                cell.cell = game.cells[row, col];
+                cell.show ();
+                table.attach_defaults (cell, col, col+1, row, row+1);
+            }
+        box.add (table);
+        table.show ();
+    }
+
+    private bool _show_highlights = false;
+    public bool show_highlights
+    {
+        get { return _show_highlights; }
+        set { _show_highlights = value; }
+    }
+
+    private bool _show_hints = false;
+    public bool show_hints
+    {
+        get { return _show_hints; }
+        set { _show_hints = value; }
+    }
+
+    private bool _show_warnings = false;
+    public bool show_warnings
+    {
+        get { return _show_warnings; }
+        set { _show_warnings = value; }
+    }
+
+    public void clear_top_notes ()
+    {
+        stdout.printf ("TODO: Clear top notes\n");
+    }
+
+    public void clear_bottom_notes ()
+    {
+        stdout.printf ("TODO: Clear bottom notes\n");
+    }
+}



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