[gnome-sudoku/mcatanzaro/composite-templates: 1/2] Create a SudokuWindow template
- From: Michael Catanzaro <mcatanzaro src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-sudoku/mcatanzaro/composite-templates: 1/2] Create a SudokuWindow template
- Date: Sat, 26 Dec 2020 20:13:24 +0000 (UTC)
commit 4c6370eeaac23dc12dfe6e7cf33b858d283cbc4b
Author: Michael Catanzaro <mcatanzaro gnome org>
Date: Sat Dec 26 13:59:04 2020 -0600
Create a SudokuWindow template
This is nicer than old-style use of GtkBuilder to build the UI. It also
simplifies gnome-sudoku.vala by moving much of its logic into the new
SudokuWindow class.
data/gnome-sudoku.gresource.xml | 4 +-
data/{gnome-sudoku.ui => sudoku-window.ui} | 246 ++++++++++----------
po/POTFILES.in | 3 +-
src/gnome-sudoku.vala | 360 +++++++----------------------
src/meson.build | 1 +
src/sudoku-window.vala | 267 +++++++++++++++++++++
6 files changed, 474 insertions(+), 407 deletions(-)
---
diff --git a/data/gnome-sudoku.gresource.xml b/data/gnome-sudoku.gresource.xml
index 24b72226..45996e39 100644
--- a/data/gnome-sudoku.gresource.xml
+++ b/data/gnome-sudoku.gresource.xml
@@ -2,7 +2,7 @@
<gresources>
<gresource prefix="/org/gnome/Sudoku/ui">
<file alias="gnome-sudoku.css">gnome-sudoku.css</file>
- <file preprocess="xml-stripblanks" alias="gnome-sudoku.ui">gnome-sudoku.ui</file>
- <file preprocess="xml-stripblanks" alias="print-dialog.ui">print-dialog.ui</file>
+ <file preprocess="xml-stripblanks">sudoku-window.ui</file>
+ <file preprocess="xml-stripblanks">print-dialog.ui</file>
</gresource>
</gresources>
diff --git a/data/gnome-sudoku.ui b/data/sudoku-window.ui
similarity index 81%
rename from data/gnome-sudoku.ui
rename to data/sudoku-window.ui
index 88b2fb9d..6b11bc81 100644
--- a/data/gnome-sudoku.ui
+++ b/data/sudoku-window.ui
@@ -1,126 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<!-- interface-requires gtk+ 3.10 -->
- <object class="GtkHeaderBar" id="headerbar">
- <property name="visible">True</property>
- <property name="can-focus">False</property>
- <property name="title" translatable="yes">Sudoku</property>
- <property name="show-close-button">True</property>
- <child>
- <object class="GtkBox" id="undo_redo_box">
- <property name="visible">True</property>
- <property name="can-focus">False</property>
- <property name="homogeneous">True</property>
- <style>
- <class name="raised"/>
- <class name="linked"/>
- </style>
- <child>
- <object class="GtkButton">
- <property name="visible">True</property>
- <property name="sensitive">False</property>
- <property name="valign">center</property>
- <property name="tooltip-text" translatable="yes">Undo your last action</property>
- <property name="can-focus">True</property>
- <property name="focus-on-click">False</property>
- <property name="action-name">app.undo</property>
- <style>
- <class name="image-button"/>
- </style>
- <child>
- <object class="GtkImage">
- <property name="icon-name">edit-undo-symbolic</property>
- <property name="visible">True</property>
- <property name="icon-size">1</property>
- </object>
- </child>
- </object>
- </child>
- <child>
- <object class="GtkButton">
- <property name="visible">True</property>
- <property name="sensitive">False</property>
- <property name="valign">center</property>
- <property name="tooltip-text" translatable="yes">Redo your last action</property>
- <property name="can-focus">True</property>
- <property name="focus-on-click">False</property>
- <property name="action-name">app.redo</property>
- <style>
- <class name="image-button"/>
- </style>
- <child>
- <object class="GtkImage">
- <property name="icon-name">edit-redo-symbolic</property>
- <property name="visible">True</property>
- <property name="icon-size">1</property>
- </object>
- </child>
- </object>
- </child>
- </object>
- </child>
- <child>
- <object class="GtkMenuButton">
- <property name="visible">True</property>
- <property name="menu-model">primary-menu</property>
- <child>
- <object class="GtkImage">
- <property name="visible">True</property>
- <property name="halign">center</property>
- <property name="icon-name">open-menu-symbolic</property>
- </object>
- </child>
- </object>
- <packing>
- <property name="pack-type">end</property>
- </packing>
- </child>
- <child>
- <object class="GtkBox">
- <property name="visible">True</property>
- <property name="can-focus">False</property>
- <property name="spacing">6</property>
- <child>
- <object class="GtkImage" id="clock_image">
- <property name="visible">True</property>
- <property name="can-focus">False</property>
- <property name="icon-name">preferences-system-time-symbolic</property>
- <property name="icon-size">1</property>
- </object>
- </child>
- <child>
- <object class="GtkLabel" id="clock_label">
- <property name="visible">True</property>
- <property name="can-focus">False</property>
- <property name="halign">center</property>
- </object>
- </child>
- </object>
- <packing>
- <property name="pack-type">end</property>
- </packing>
- </child>
- <child>
- <object class="GtkButton" id="back_button">
- <property name="visible">False</property>
- <property name="halign">center</property>
- <property name="valign">center</property>
- <property name="tooltip-text" translatable="yes">Go back to the current game</property>
- <property name="use-underline">True</property>
- <property name="action-name">app.back</property>
- <style>
- <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>
- </object>
<menu id="primary-menu">
<section>
<submenu>
@@ -158,8 +38,130 @@
</item>
</section>
</menu>
- <object class="GtkApplicationWindow" id="sudoku_app">
+ <template class="SudokuWindow" parent="GtkApplicationWindow">
<property name="title" translatable="yes">Sudoku</property>
+ <child type="titlebar">
+ <object class="GtkHeaderBar" id="headerbar">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="title" translatable="yes">Sudoku</property>
+ <property name="show-close-button">True</property>
+ <child>
+ <object class="GtkBox" id="undo_redo_box">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="homogeneous">True</property>
+ <style>
+ <class name="raised"/>
+ <class name="linked"/>
+ </style>
+ <child>
+ <object class="GtkButton">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="valign">center</property>
+ <property name="tooltip-text" translatable="yes">Undo your last action</property>
+ <property name="can-focus">True</property>
+ <property name="focus-on-click">False</property>
+ <property name="action-name">app.undo</property>
+ <style>
+ <class name="image-button"/>
+ </style>
+ <child>
+ <object class="GtkImage">
+ <property name="icon-name">edit-undo-symbolic</property>
+ <property name="visible">True</property>
+ <property name="icon-size">1</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="valign">center</property>
+ <property name="tooltip-text" translatable="yes">Redo your last action</property>
+ <property name="can-focus">True</property>
+ <property name="focus-on-click">False</property>
+ <property name="action-name">app.redo</property>
+ <style>
+ <class name="image-button"/>
+ </style>
+ <child>
+ <object class="GtkImage">
+ <property name="icon-name">edit-redo-symbolic</property>
+ <property name="visible">True</property>
+ <property name="icon-size">1</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuButton">
+ <property name="visible">True</property>
+ <property name="menu-model">primary-menu</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="halign">center</property>
+ <property name="icon-name">open-menu-symbolic</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="pack-type">end</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkImage" id="clock_image">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">preferences-system-time-symbolic</property>
+ <property name="icon-size">1</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="clock_label">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="halign">center</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="pack-type">end</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="back_button">
+ <property name="visible">False</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="tooltip-text" translatable="yes">Go back to the current game</property>
+ <property name="use-underline">True</property>
+ <property name="action-name">app.back</property>
+ <style>
+ <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>
+ </object>
+ </child>
<child>
<object class="GtkBox"> <!-- vbox -->
<property name="orientation">vertical</property>
@@ -419,5 +421,5 @@
</child>
</object> <!-- End of vbox -->
</child>
- </object> <!-- End of sudoku_app -->
+ </template> <!-- End of SudokuWindow -->
</interface>
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 958133aa..9cc341dd 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -1,6 +1,6 @@
# List of source files containing translatable strings.
# Please keep this file in alphabetical order.
-data/gnome-sudoku.ui
+data/sudoku-window.ui
data/org.gnome.Sudoku.appdata.xml.in
data/org.gnome.Sudoku.desktop.in
data/org.gnome.Sudoku.gschema.xml
@@ -11,3 +11,4 @@ src/gnome-sudoku.vala
src/number-picker.vala
src/sudoku-printer.vala
src/sudoku-view.vala
+src/sudoku-window.vala
diff --git a/src/gnome-sudoku.vala b/src/gnome-sudoku.vala
index 51a77ca3..5b0ed27d 100644
--- a/src/gnome-sudoku.vala
+++ b/src/gnome-sudoku.vala
@@ -24,38 +24,16 @@ using Gtk;
public class Sudoku : Gtk.Application
{
private GLib.Settings settings;
- private bool window_is_maximized;
- private bool window_is_fullscreen;
- private bool window_is_tiled;
- private int window_width;
- private int window_height;
- private Button play_custom_game_button;
- private Button play_pause_button;
- private Label play_pause_label;
- private Label clock_label;
- private Image clock_image;
-
- private ApplicationWindow window;
-
- private SudokuGame? game;
- private SudokuView? view;
-
- private HeaderBar headerbar;
- private Hdy.Squeezer main_squeezer;
- private Box start_box;
- private Box start_box_s;
- private AspectFrame frame_v;
- private AspectFrame frame_h;
- private Box game_box; // Holds the view
- private ButtonBox controls_box;
-
- private Box undo_redo_box;
- private Button back_button;
- private SudokuSaver saver;
+ private SudokuWindow window;
+ private SudokuGame? game = null;
+
+ private SudokuView? view
+ {
+ get { return window.view; }
+ }
- private AspectFrame previous_layout;
- private Orientation main_squeezer_orientation;
+ private SudokuSaver saver;
private SimpleAction undo_action;
private SimpleAction redo_action;
@@ -69,8 +47,6 @@ public class Sudoku : Gtk.Application
private bool show_possibilities = false;
private GameMode current_game_mode = GameMode.PLAY;
- private const int board_size = 140;
-
private const GLib.ActionEntry action_entries[] =
{
{"new-game", new_game_cb },
@@ -160,38 +136,6 @@ public class Sudoku : Gtk.Application
set_accels_for_action ("app.redo", {"<Primary><Shift>z"});
set_accels_for_action ("app.help", {"F1"});
- Window.set_default_icon_name ("org.gnome.Sudoku");
-
- var builder = new Builder.from_resource ("/org/gnome/Sudoku/ui/gnome-sudoku.ui");
-
- window = (ApplicationWindow) builder.get_object ("sudoku_app");
- window.size_allocate.connect (size_allocate_cb);
- window.window_state_event.connect (window_state_event_cb);
- window.set_default_size (settings.get_int ("window-width"), settings.get_int ("window-height"));
- if (settings.get_boolean ("window-is-maximized"))
- window.maximize ();
-
- add_window (window);
-
- headerbar = (HeaderBar) builder.get_object ("headerbar");
- main_squeezer = (Hdy.Squeezer) builder.get_object ("main_squeezer");
- main_squeezer.draw.connect (draw_cb);
-
- start_box = (Box) builder.get_object ("start_box");
- start_box_s = (Box) builder.get_object ("start_box_s");
-
- frame_h = (AspectFrame) builder.get_object ("frame_h");
- frame_v = (AspectFrame) builder.get_object ("frame_v");
- game_box = (Box) builder.get_object ("game_box");
- controls_box = (ButtonBox) builder.get_object ("controls_box");
- undo_redo_box = (Box) builder.get_object ("undo_redo_box");
- back_button = (Button) builder.get_object ("back_button");
- clock_label = (Label) builder.get_object ("clock_label");
- clock_image = (Image) builder.get_object ("clock_image");
- play_custom_game_button = (Button) builder.get_object ("play_custom_game_button");
- play_pause_button = (Button) builder.get_object ("play_pause_button");
- play_pause_label = (Label) builder.get_object ("play_pause_label");
-
undo_action = (SimpleAction) lookup_action ("undo");
redo_action = (SimpleAction) lookup_action ("redo");
new_game_action = (SimpleAction) lookup_action ("new-game");
@@ -201,8 +145,10 @@ public class Sudoku : Gtk.Application
pause_action = (SimpleAction) lookup_action ("pause");
play_custom_game_action = (SimpleAction) lookup_action ("play-custom-game");
- window.set_titlebar (headerbar);
- prepare_layout ();
+ Window.set_default_icon_name ("org.gnome.Sudoku");
+
+ window = new SudokuWindow (settings);
+ add_window (window);
saver = new SudokuSaver ();
var savegame = saver.get_savedgame ();
@@ -243,69 +189,14 @@ public class Sudoku : Gtk.Application
}
}
- /* Save window state */
- settings.delay ();
- settings.set_int ("window-width", window_width);
- settings.set_int ("window-height", window_height);
- settings.set_boolean ("window-is-maximized", window_is_maximized || window_is_fullscreen);
- settings.apply ();
-
base.shutdown ();
}
- private void size_allocate_cb (Allocation allocation)
- {
- int width, height;
- window.get_size (out width, out height);
- update_layout (width, height);
- if (window_is_maximized || window_is_fullscreen || window_is_tiled)
- return;
- window_width = width;
- window_height = height;
- }
-
- private void update_layout (int width, int height)
- {
- main_squeezer_orientation = height > width ? Orientation.HORIZONTAL : Orientation.VERTICAL;
- frame_h.ratio = height < 350 ? 1.9f : 1.4f;
- apply_main_squeezer_orientation ();
- }
-
- private void apply_main_squeezer_orientation ()
- {
- var child = main_squeezer.visible_child;
- if (child == start_box || child == start_box_s)
- main_squeezer.orientation = main_squeezer_orientation;
- else
- main_squeezer.orientation = Orientation.HORIZONTAL;
- }
-
- private const Gdk.WindowState tiled_state = Gdk.WindowState.TILED
- | Gdk.WindowState.TOP_TILED
- | Gdk.WindowState.BOTTOM_TILED
- | Gdk.WindowState.LEFT_TILED
- | Gdk.WindowState.RIGHT_TILED;
- private bool window_state_event_cb (Gdk.EventWindowState event)
- {
- if ((event.changed_mask & Gdk.WindowState.MAXIMIZED) != 0)
- window_is_maximized = (event.new_window_state & Gdk.WindowState.MAXIMIZED) != 0;
-
- /* fullscreen: saved as maximized */
- if ((event.changed_mask & Gdk.WindowState.FULLSCREEN) != 0)
- window_is_fullscreen = (event.new_window_state & Gdk.WindowState.FULLSCREEN) != 0;
-
- /* We don’t save this state, but track it for saving size allocation */
- if ((event.changed_mask & tiled_state) != 0)
- window_is_tiled = (event.new_window_state & tiled_state) != 0;
-
- return false;
- }
-
private void paused_changed_cb ()
{
if (game.paused)
{
- display_unpause_button ();
+ window.display_unpause_button ();
clear_action.set_enabled (false);
undo_action.set_enabled (false);
redo_action.set_enabled (false);
@@ -313,7 +204,7 @@ public class Sudoku : Gtk.Application
}
else if (game.get_total_time_played () > 0)
{
- display_pause_button ();
+ window.display_pause_button ();
clear_action.set_enabled (!game.is_empty ());
undo_action.set_enabled (!game.is_undostack_null ());
redo_action.set_enabled (!game.is_redostack_null ());
@@ -364,28 +255,44 @@ public class Sudoku : Gtk.Application
game.stop_clock ();
}
- private void tick_cb ()
+ private void cell_changed_cb ()
{
- var elapsed_time = (int) game.get_total_time_played ();
- var hours = elapsed_time / 3600;
- var minutes = (elapsed_time - hours * 3600) / 60;
- var seconds = elapsed_time - hours * 3600 - minutes * 60;
- if (hours > 0)
- clock_label.set_text ("%02d∶\xE2\x80\x8E%02d∶\xE2\x80\x8E%02d".printf (hours, minutes, seconds));
- else
- clock_label.set_text ("%02d∶\xE2\x80\x8E%02d".printf (minutes, seconds));
+ undo_action.set_enabled (!game.is_undostack_null ());
+ redo_action.set_enabled (!game.is_redostack_null ());
+ clear_action.set_enabled (!game.is_empty ());
+ play_custom_game_action.set_enabled (!game.is_empty () && !game.board.is_fully_filled ());
}
- private void display_pause_button ()
+ private void board_completed_cb ()
{
- play_pause_button.show ();
- play_pause_label.label = _("_Pause");
- }
+ window.board_completed ();
- private void display_unpause_button ()
- {
- play_pause_button.show ();
- play_pause_label.label = _("_Resume");
+ game.stop_clock ();
+
+ for (var i = 0; i < game.board.rows; i++)
+ for (var j = 0; j < game.board.cols; j++)
+ view.can_focus = false;
+
+ saver.add_game_to_finished (game, true);
+
+ /* Text in dialog that displays when the game is over. */
+ var minutes = int.max (1, (int) game.get_total_time_played () / 60);
+ var time_str = ngettext ("Well done, you completed the puzzle in %d minute!",
+ "Well done, you completed the puzzle in %d minutes!",
+ minutes).printf (minutes);
+ var dialog = new MessageDialog (window, DialogFlags.MODAL, MessageType.INFO, ButtonsType.NONE,
time_str);
+ dialog.add_button (_("_Quit"), ResponseType.REJECT);
+ dialog.add_button (_("Play _Again"), ResponseType.ACCEPT);
+
+ dialog.response.connect ((response_id) => {
+ if (response_id == ResponseType.ACCEPT)
+ show_new_game_screen ();
+ else if (response_id == ResponseType.REJECT)
+ quit ();
+ dialog.destroy ();
+ });
+
+ dialog.show ();
}
private void start_custom_game (SudokuBoard board)
@@ -397,89 +304,40 @@ public class Sudoku : Gtk.Application
private void start_game (SudokuBoard board)
{
- if (view != null)
- game_box.remove (view);
+ if (game != null)
+ {
+ game.paused_changed.disconnect (paused_changed_cb);
+ game.cell_changed.disconnect (cell_changed_cb);
+ game.board.completed.disconnect (board_completed_cb);
+ }
- show_game_view ();
game = new SudokuGame (board);
game.mode = current_game_mode;
- undo_action.set_enabled (false);
- redo_action.set_enabled (false);
- set_headerbar_title ();
- clear_action.set_enabled (!game.is_empty ());
- play_custom_game_action.set_enabled (!game.is_empty ());
-
- game.tick.connect (tick_cb);
game.paused_changed.connect (paused_changed_cb);
- game.start_clock ();
+ game.cell_changed.connect (cell_changed_cb);
- view = new SudokuView (game);
- view.set_size_request (board_size, board_size);
+ window.start_game (game, show_possibilities);
- view.show_possibilities = show_possibilities;
- if (current_game_mode == GameMode.CREATE)
- view.show_warnings = true;
- else
- view.show_warnings = settings.get_boolean ("show-warnings");
- view.highlighter = settings.get_boolean ("highlighter");
-
- view.show ();
- game_box.pack_start (view);
- game_box.child_set_property (view, "position", 0);
- game.cell_changed.connect (() => {
- undo_action.set_enabled (!game.is_undostack_null ());
- redo_action.set_enabled (!game.is_redostack_null ());
- clear_action.set_enabled (!game.is_empty ());
- play_custom_game_action.set_enabled (!game.is_empty () && !game.board.is_fully_filled ());
- });
-
- if (current_game_mode == GameMode.CREATE)
- return;
-
- game.board.completed.connect (() => {
- play_custom_game_button.visible = false;
- game.stop_clock ();
-
- for (var i = 0; i < game.board.rows; i++)
- for (var j = 0; j < game.board.cols; j++)
- view.can_focus = false;
-
- saver.add_game_to_finished (game, true);
-
- /* Text in dialog that displays when the game is over. */
- var minutes = int.max (1, (int) game.get_total_time_played () / 60);
- var time_str = ngettext ("Well done, you completed the puzzle in %d minute!",
- "Well done, you completed the puzzle in %d minutes!",
- minutes).printf (minutes);
- var dialog = new MessageDialog (window, DialogFlags.MODAL, MessageType.INFO, ButtonsType.NONE,
time_str);
-
- dialog.add_button (_("_Quit"), ResponseType.REJECT);
- dialog.add_button (_("Play _Again"), ResponseType.ACCEPT);
+ print_action.set_enabled (true);
+ undo_action.set_enabled (false);
+ redo_action.set_enabled (false);
- dialog.response.connect ((response_id) => {
- if (response_id == ResponseType.ACCEPT)
- show_new_game_screen ();
- else if (response_id == ResponseType.REJECT)
- quit ();
- dialog.destroy ();
- });
+ clear_action.set_enabled (!game.is_empty ());
+ play_custom_game_action.set_enabled (!game.is_empty ());
- dialog.show ();
- });
+ if (current_game_mode != GameMode.CREATE)
+ game.board.completed.connect (board_completed_cb);
}
private void show_new_game_screen ()
{
- set_board_visible (false);
- back_button.visible = game != null;
- undo_redo_box.visible = false;
- headerbar.title = _("Select Difficulty");
print_action.set_enabled (false);
- clock_label.hide ();
- clock_image.hide ();
+
if (game != null)
game.stop_clock ();
+
+ window.show_new_game_screen ();
}
private void new_game_cb ()
@@ -505,20 +363,19 @@ public class Sudoku : Gtk.Application
private void start_game_cb (SimpleAction action, Variant? difficulty)
{
+ window.will_start_game ();
+ current_game_mode = GameMode.PLAY;
+
// Since we cannot have enums in .ui file, the 'action-target' property
// of new game buttons in data/gnome-sudoku.ui
// has been set to integers corresponding to the enums.
// Following line converts those ints to their DifficultyCategory
var selected_difficulty = (DifficultyCategory) difficulty.get_int32 ();
- back_button.sensitive = false;
- current_game_mode = GameMode.PLAY;
-
SudokuGenerator.generate_boards_async.begin (1, selected_difficulty, null, (obj, res) => {
try
{
var gen_boards = SudokuGenerator.generate_boards_async.end (res);
- back_button.sensitive = true;
start_game (gen_boards[0]);
}
catch (Error e)
@@ -546,49 +403,16 @@ public class Sudoku : Gtk.Application
dialog.show ();
}
- private void show_game_view ()
- {
- set_board_visible (true);
- back_button.visible = false;
- undo_redo_box.visible = true;
- print_action.set_enabled (true);
- clock_label.show ();
- clock_image.show ();
-
- if (game != null)
- game.resume_clock ();
-
- if (current_game_mode == GameMode.PLAY)
- {
- play_custom_game_button.visible = false;
- play_pause_button.visible = true;
- }
- else
- {
- clock_label.hide ();
- clock_image.hide ();
- play_custom_game_button.visible = true;
- play_pause_button.visible = false;
- }
- }
-
- private void set_headerbar_title ()
- {
- if (current_game_mode == GameMode.PLAY)
- headerbar.title = game.board.difficulty_category.to_string ();
- else
- headerbar.title = _("Create Puzzle");
- }
-
private void back_cb ()
{
- show_game_view ();
- set_headerbar_title ();
+ window.show_game_view ();
+
+ print_action.set_enabled (true);
}
private void undo_cb ()
{
- if (!is_board_visible ())
+ if (!window.is_board_visible ())
return;
game.undo ();
undo_action.set_enabled (!game.is_undostack_null ());
@@ -598,7 +422,7 @@ public class Sudoku : Gtk.Application
private void redo_cb ()
{
- if (!is_board_visible ())
+ if (!window.is_board_visible ())
return;
game.redo ();
redo_action.set_enabled (!game.is_redostack_null ());
@@ -608,7 +432,7 @@ public class Sudoku : Gtk.Application
private void print_cb ()
{
- if (!is_board_visible ())
+ if (!window.is_board_visible ())
return;
print_action.set_enabled (false);
print_multiple_action.set_enabled (false);
@@ -628,7 +452,7 @@ public class Sudoku : Gtk.Application
print_multiple_action.set_enabled (false);
var print_dialog = new PrintDialog (saver, window);
print_dialog.destroy.connect (() => {
- this.print_action.set_enabled (is_board_visible ());
+ this.print_action.set_enabled (window.is_board_visible ());
this.print_multiple_action.set_enabled (true);
});
print_dialog.run ();
@@ -672,23 +496,8 @@ public class Sudoku : Gtk.Application
);
}
- private void prepare_layout ()
- {
- previous_layout = frame_h;
-
- var main_squeezer_m = main_squeezer.margin;
- var game_box_s = game_box.spacing;
- var controls_box_s = controls_box.spacing;
- const int BUTTON_W = 120;
- const int BUTTON_H = 60;
-
- var spacing = 2 * game_box_s + 2 * main_squeezer_m;
- var board_and_spacing = board_size + spacing;
- var board_with_buttons = board_and_spacing + game_box_s + 2 * controls_box_s;
- frame_h.width_request = board_with_buttons + BUTTON_W;
- frame_v.height_request = board_and_spacing + 3 * BUTTON_H + 4 * controls_box_s;
- }
-
+#if 0
+ // Unused?
private bool draw_cb ()
{
return check_layout_change ();
@@ -723,20 +532,7 @@ public class Sudoku : Gtk.Application
new_layout.add (game_box);
previous_layout = new_layout;
}
-
- private void set_board_visible (bool value)
- {
- start_box.visible = !value;
- start_box_s.visible = !value;
- frame_h.visible = value;
- frame_v.visible = value;
- apply_main_squeezer_orientation ();
- }
-
- private bool is_board_visible ()
- {
- return frame_h.visible;
- }
+#endif
public static int main (string[] args)
{
diff --git a/src/meson.build b/src/meson.build
index a81994e7..9cf093ce 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -11,6 +11,7 @@ gnome_sudoku_sources = [
'print-dialog.vala',
'sudoku-printer.vala',
'sudoku-view.vala',
+ 'sudoku-window.vala',
resources
]
diff --git a/src/sudoku-window.vala b/src/sudoku-window.vala
new file mode 100644
index 00000000..10615856
--- /dev/null
+++ b/src/sudoku-window.vala
@@ -0,0 +1,267 @@
+/* -*- Mode: vala; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * Copyright © 2014 Parin Porecha
+ * Copyright © 2014, 2020 Michael Catanzaro
+ *
+ * This file is part of GNOME Sudoku.
+ *
+ * GNOME Sudoku is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GNOME Sudoku is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNOME Sudoku. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+using Gtk;
+
+[GtkTemplate (ui = "/org/gnome/Sudoku/ui/sudoku-window.ui")]
+public class SudokuWindow : ApplicationWindow
+{
+ [GtkChild] private HeaderBar headerbar;
+ [GtkChild] private Hdy.Squeezer main_squeezer;
+ [GtkChild] private Box start_box;
+ [GtkChild] private Box start_box_s;
+ [GtkChild] private AspectFrame frame_v;
+ [GtkChild] private AspectFrame frame_h;
+ [GtkChild] private Box game_box; // Holds the view
+ [GtkChild] private ButtonBox controls_box;
+
+ [GtkChild] private Box undo_redo_box;
+ [GtkChild] private Button back_button;
+
+ [GtkChild] private Label clock_label;
+ [GtkChild] private Image clock_image;
+
+ [GtkChild] private Button play_custom_game_button;
+ [GtkChild] private Button play_pause_button;
+ [GtkChild] private Label play_pause_label;
+
+ private bool window_is_maximized;
+ private bool window_is_fullscreen;
+ private bool window_is_tiled;
+ private int window_width;
+ private int window_height;
+
+ private GLib.Settings settings;
+
+ public SudokuView? view { get; private set; }
+
+ private SudokuGame? game = null;
+
+ private AspectFrame previous_layout;
+ private Orientation main_squeezer_orientation;
+
+ private const int board_size = 140;
+
+ public SudokuWindow (GLib.Settings settings)
+ {
+ this.settings = settings;
+
+ set_default_size (settings.get_int ("window-width"), settings.get_int ("window-height"));
+ if (settings.get_boolean ("window-is-maximized"))
+ maximize ();
+
+ previous_layout = frame_h;
+
+ const int BUTTON_W = 120;
+ const int BUTTON_H = 60;
+ var spacing = 2 * game_box.spacing + 2 * main_squeezer.margin;
+ var board_and_spacing = board_size + spacing;
+ var board_with_buttons = board_and_spacing + game_box.spacing + 2 * controls_box.spacing;
+ frame_h.width_request = board_with_buttons + BUTTON_W;
+ frame_v.height_request = board_and_spacing + 3 * BUTTON_H + 4 * controls_box.spacing;
+ }
+
+ ~SudokuWindow ()
+ {
+ /* Save window state */
+ settings.delay ();
+ settings.set_int ("window-width", window_width);
+ settings.set_int ("window-height", window_height);
+ settings.set_boolean ("window-is-maximized", window_is_maximized || window_is_fullscreen);
+ settings.apply ();
+ }
+
+ public override void size_allocate (Allocation allocation)
+ {
+ base.size_allocate (allocation);
+
+ int width, height;
+ get_size (out width, out height);
+ update_layout (width, height);
+
+ if (window_is_maximized || window_is_fullscreen || window_is_tiled)
+ return;
+
+ window_width = width;
+ window_height = height;
+ }
+
+ private const Gdk.WindowState tiled_state = Gdk.WindowState.TILED
+ | Gdk.WindowState.TOP_TILED
+ | Gdk.WindowState.BOTTOM_TILED
+ | Gdk.WindowState.LEFT_TILED
+ | Gdk.WindowState.RIGHT_TILED;
+
+ public override bool window_state_event (Gdk.EventWindowState event)
+ {
+ if ((event.changed_mask & Gdk.WindowState.MAXIMIZED) != 0)
+ window_is_maximized = (event.new_window_state & Gdk.WindowState.MAXIMIZED) != 0;
+
+ /* fullscreen: saved as maximized */
+ if ((event.changed_mask & Gdk.WindowState.FULLSCREEN) != 0)
+ window_is_fullscreen = (event.new_window_state & Gdk.WindowState.FULLSCREEN) != 0;
+
+ /* We don’t save this state, but track it for saving size allocation */
+ if ((event.changed_mask & tiled_state) != 0)
+ window_is_tiled = (event.new_window_state & tiled_state) != 0;
+
+ return base.window_state_event (event);
+ }
+
+ private void update_layout (int width, int height)
+ {
+ main_squeezer_orientation = height > width ? Orientation.HORIZONTAL : Orientation.VERTICAL;
+ frame_h.ratio = height < 350 ? 1.9f : 1.4f;
+ apply_main_squeezer_orientation ();
+ }
+
+ private void apply_main_squeezer_orientation ()
+ {
+ var child = main_squeezer.visible_child;
+ if (child == start_box || child == start_box_s)
+ main_squeezer.orientation = main_squeezer_orientation;
+ else
+ main_squeezer.orientation = Orientation.HORIZONTAL;
+ }
+
+ public void will_start_game ()
+ {
+ back_button.sensitive = false;
+ }
+
+ public void start_game (SudokuGame game, bool show_possibilities)
+ {
+ if (this.game != null)
+ this.game.tick.disconnect (tick_cb);
+ this.game = game;
+ game.tick.connect (tick_cb);
+ game.start_clock ();
+
+ if (view != null)
+ game_box.remove (view);
+
+ show_game_view ();
+
+ view = new SudokuView (game);
+ view.set_size_request (board_size, board_size);
+
+ view.show_possibilities = show_possibilities;
+ if (game.mode == GameMode.CREATE)
+ view.show_warnings = true;
+ else
+ view.show_warnings = settings.get_boolean ("show-warnings");
+ view.highlighter = settings.get_boolean ("highlighter");
+
+ view.show ();
+ game_box.pack_start (view);
+ game_box.child_set_property (view, "position", 0);
+
+ back_button.sensitive = true;
+ }
+
+ public void show_new_game_screen ()
+ {
+ headerbar.title = _("Select Difficulty");
+ set_board_visible (false);
+ back_button.visible = game != null;
+ undo_redo_box.visible = false;
+ clock_label.visible = false;
+ clock_image.visible = false;
+ }
+
+ public void set_board_visible (bool visible)
+ {
+ start_box.visible = !visible;
+ start_box_s.visible = !visible;
+ frame_h.visible = visible;
+ frame_v.visible = visible;
+ apply_main_squeezer_orientation ();
+ }
+
+ public bool is_board_visible ()
+ {
+ return frame_h.visible;
+ }
+
+ public void show_game_view ()
+ requires (game != null)
+ {
+ set_board_visible (true);
+ back_button.visible = false;
+ undo_redo_box.visible = true;
+
+ clock_label.visible = true;
+ clock_image.visible = true;
+
+ if (game.mode == GameMode.PLAY)
+ {
+ play_custom_game_button.visible = false;
+ play_pause_button.visible = true;
+ }
+ else
+ {
+ clock_label.visible = false;
+ clock_image.visible = false;
+ play_custom_game_button.visible = true;
+ play_pause_button.visible = false;
+ }
+
+ set_headerbar_title ();
+ }
+
+ public void board_completed ()
+ {
+ play_custom_game_button.visible = false;
+ }
+
+ public void set_headerbar_title ()
+ requires (game != null)
+ {
+ if (game.mode == GameMode.PLAY)
+ headerbar.title = game.board.difficulty_category.to_string ();
+ else
+ headerbar.title = _("Create Puzzle");
+ }
+
+ public void display_pause_button ()
+ {
+ play_pause_button.show ();
+ play_pause_label.label = _("_Pause");
+ }
+
+ public void display_unpause_button ()
+ {
+ play_pause_button.show ();
+ play_pause_label.label = _("_Resume");
+ }
+
+ private void tick_cb ()
+ {
+ var elapsed_time = (int) game.get_total_time_played ();
+ var hours = elapsed_time / 3600;
+ var minutes = (elapsed_time - hours * 3600) / 60;
+ var seconds = elapsed_time - hours * 3600 - minutes * 60;
+ if (hours > 0)
+ clock_label.set_text ("%02d∶\xE2\x80\x8E%02d∶\xE2\x80\x8E%02d".printf (hours, minutes, seconds));
+ else
+ clock_label.set_text ("%02d∶\xE2\x80\x8E%02d".printf (minutes, seconds));
+ }
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]