[four-in-a-row: 9/13] Introduce NewGameScreen.
- From: Arnaud B. <arnaudb src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [four-in-a-row: 9/13] Introduce NewGameScreen.
- Date: Fri, 20 Dec 2019 17:45:03 +0000 (UTC)
commit f2c73c60ab642b869f2bddf89136b15aa2ad7e94
Author: Arnaud Bonatti <arnaud bonatti gmail com>
Date: Wed Dec 18 16:23:15 2019 +0100
Introduce NewGameScreen.
Copied from Iagno 3.34.
data/four-in-a-row.css | 50 ++++-
data/org.gnome.Four-in-a-row.gschema.xml | 3 +
data/ui/adaptative-window.ui | 29 +++
data/ui/fiar-screens.ui | 91 +++++++-
data/ui/four-in-a-row.ui | 20 +-
po/POTFILES.in | 1 +
po/POTFILES.skip | 1 +
src/adaptative-window.vala | 356 +++++++++++++++++++++++++++++++
src/four-in-a-row.gresource.xml | 1 +
src/four-in-a-row.vala | 105 +++++----
src/game-board-view.vala | 2 -
src/game-window.vala | 62 ++----
src/meson.build | 2 +
src/new-game-screen.vala | 149 +++++++++++++
14 files changed, 765 insertions(+), 107 deletions(-)
---
diff --git a/data/four-in-a-row.css b/data/four-in-a-row.css
index c57ab45..84699d2 100644
--- a/data/four-in-a-row.css
+++ b/data/four-in-a-row.css
@@ -25,4 +25,52 @@ GtkButtonBox {
-GtkButtonBox-child-internal-pad-x:0;
}
-.game-box { padding:1.5rem; }
+.extra-thin-window.thin-window button.new-game-button { padding-left:12px; padding-right:12px; transition:
padding 0 ease;
+/* hack: fix the double spacing around the centerwidget box, on extra-thin window */
+ margin-right:-12px; }
+/*\
+* * board generics; TODO move in game-window.css
+\*/
+
+ .game-box { transition:padding 0.3s; padding:1.5rem; }
+ .thin-window .game-box { padding:1.0rem; }
+.extra-thin-window.thin-window .game-box,
+ .flat-window .game-box { padding:0.5rem; }
+.extra-flat-window.flat-window .game-box { padding:0.4rem; }
+
+/*\
+* * start-game button; TODO move in game-window.css
+\*/
+
+ button.start-game-button { margin-top:1.5rem; margin-bottom:0.5rem;
+ transition:margin-top 0 ease, margin-bottom 0 ease; }
+ .flat-window button.start-game-button { margin-top:0.5rem; }
+.extra-flat-window.flat-window button.start-game-button { margin-top: 0rem; margin-bottom:0.4rem; }
+
+.extra-thin-window button.start-game-button { margin-top:1.0rem; }
+
+/*\
+* * options buttons
+\*/
+
+.extra-flat-window button.start-game-button {
+ min-height:2rem;
+}
+ button.start-game-button {
+ min-height:3rem;
+ min-width:11rem;
+
+ transition:min-height 0.3s ease 0.01s;
+}
+
+/*\
+* * labels' tweaks
+\*/
+
+label.bold-label {
+ font-weight: bold;
+}
+
+/*\
+* * the end
+\*/
diff --git a/data/org.gnome.Four-in-a-row.gschema.xml b/data/org.gnome.Four-in-a-row.gschema.xml
index 4d33079..b98552d 100644
--- a/data/org.gnome.Four-in-a-row.gschema.xml
+++ b/data/org.gnome.Four-in-a-row.gschema.xml
@@ -63,6 +63,9 @@
<!-- Translators: description of a settings key, see 'dconf-editor /org/gnome/Four-in-a-row/key-drop'
-->
<description>Key press to drop a marble.</description>
</key>
+ </schema>
+
+ <schema id="org.gnome.Four-in-a-row.Lib" gettext-domain="four-in-a-row">
<key name="window-width" type="i">
<default>675</default>
<!-- Translators: summary of a settings key, see 'dconf-editor /org/gnome/Four-in-a-row/window-width'
-->
diff --git a/data/ui/adaptative-window.ui b/data/ui/adaptative-window.ui
new file mode 100644
index 0000000..83ff550
--- /dev/null
+++ b/data/ui/adaptative-window.ui
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ This file is part of GNOME Four-in-a-row.
+
+ Copyright © 2019 Arnaud Bonatti
+
+ GNOME Four-in-a-row 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 Four-in-a-row 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 Four-in-a-row. If not, see <https://www.gnu.org/licenses/>.
+-->
+<interface>
+ <requires lib="gtk+" version="3.12"/>
+ <template class="AdaptativeWindow" parent="GtkApplicationWindow">
+ <property name="height-request">284</property> <!-- 288px max for Purism Librem 5 landscape, for 720px
width; update gschema also -->
+ <property name="width-request">490</property> <!-- 350</property> <! - 360px max for Purism Librem 5
portrait, for 648px height; update gschema also -->
+ <signal name="window-state-event" handler="on_window_state_event"/>
+ <signal name="size-allocate" handler="on_size_allocate"/>
+ <signal name="destroy" handler="on_destroy"/>
+ </template>
+</interface>
diff --git a/data/ui/fiar-screens.ui b/data/ui/fiar-screens.ui
index 6c6de7b..3a599cd 100644
--- a/data/ui/fiar-screens.ui
+++ b/data/ui/fiar-screens.ui
@@ -19,17 +19,85 @@
-->
<interface>
<requires lib="gtk+" version="3.12"/>
- <object class="GtkBox" id="new-game-screen">
+ <template class="NewGameScreen" parent="GtkBox">
<property name="orientation">vertical</property>
<property name="visible">True</property>
<property name="homogeneous">True</property>
<property name="valign">fill</property>
<property name="spacing">18</property>
- <property name="margin-bottom">25</property><!-- TODO better -->
- <property name="height-request">263</property>
- <property name="width-request">400</property>
+ <property name="margin-bottom">22</property><!-- TODO better -->
+ <property name="margin-top">4</property>
<child>
- <object class="GtkBox">
+ <object class="GtkBox" id="infos_section">
+ <property name="orientation">vertical</property>
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="halign">start</property>
+ <!-- Translators: when configuring a new game, on a thin window, header of the row for choosing
the number of players -->
+ <property name="label" translatable="yes">Game type</property>
+ <style>
+ <class name="bold-label"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="vexpand">True</property>
+ <property name="homogeneous">True</property>
+ <property name="spacing">0</property>
+ <property name="orientation">vertical</property>
+ <style>
+ <class name="linked"/>
+ </style>
+ <child>
+ <object class="GtkModelButton">
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ <!-- Translators: when configuring a new game, on a thin window, group "Game type", label of
the button to choose to play first (with a mnemonic that appears pressing Alt) -->
+ <property name="text" translatable="yes">Play _first</property>
+ <property name="action-name">app.game-type</property>
+ <property name="action-target">'human'</property>
+ <property name="iconic">True</property>
+ <property name="centered">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkModelButton">
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ <!-- Translators: when configuring a new game, on a thin window, group "Game type", label of
the button to choose to play second (with a mnemonic that appears pressing Alt) -->
+ <property name="text" translatable="yes">Play _second</property>
+ <property name="action-name">app.game-type</property>
+ <property name="action-target">'computer'</property>
+ <property name="iconic">True</property>
+ <property name="centered">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkModelButton">
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ <!-- Translators: when configuring a new game, on a thin window, group "Game type", label of
the button to choose a two-players game (with a mnemonic that appears pressing Alt) -->
+ <property name="text" translatable="yes">_Two players</property>
+ <property name="action-name">app.game-type</property>
+ <property name="action-target">'two'</property>
+ <property name="iconic">True</property>
+ <property name="centered">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox" id="users_section">
<property name="orientation">vertical</property>
<property name="visible">True</property>
<property name="spacing">6</property>
@@ -45,8 +113,9 @@
</object>
</child>
<child>
- <object class="GtkBox">
+ <object class="GtkBox" id="users_box">
<property name="visible">True</property>
+ <property name="vexpand">True</property>
<property name="homogeneous">True</property>
<property name="spacing">12</property>
<child>
@@ -97,8 +166,9 @@
</object>
</child>
<child>
- <object class="GtkBox" id="difficulty-box">
+ <object class="GtkBox" id="level_box">
<property name="visible">True</property>
+ <property name="vexpand">True</property>
<property name="homogeneous">True</property>
<property name="spacing">12</property>
<child>
@@ -145,7 +215,7 @@
</object>
</child>
<child>
- <object class="GtkBox">
+ <object class="GtkBox" id="start_section">
<property name="orientation">vertical</property>
<property name="visible">True</property>
<property name="spacing">6</property>
@@ -161,8 +231,9 @@
</object>
</child>
<child>
- <object class="GtkBox" id="start-box">
+ <object class="GtkBox" id="start_box">
<property name="visible">True</property>
+ <property name="vexpand">True</property>
<property name="homogeneous">True</property>
<property name="spacing">12</property>
<child>
@@ -196,5 +267,5 @@
</child>
</object>
</child>
- </object>
+ </template>
</interface>
diff --git a/data/ui/four-in-a-row.ui b/data/ui/four-in-a-row.ui
index b4a7360..f480687 100644
--- a/data/ui/four-in-a-row.ui
+++ b/data/ui/four-in-a-row.ui
@@ -31,7 +31,7 @@
</item>
</section>
</menu>
- <template class="GameWindow" parent="GtkApplicationWindow">
+ <template class="GameWindow" parent="AdaptativeWindow">
<!-- <initial-focus name="view"/> -->
<child type="titlebar">
<object class="GtkHeaderBar" id="headerbar">
@@ -129,15 +129,16 @@
<property name="visible">True</property>
<property name="homogeneous">True</property>
<child>
- <object class="GtkBox" id="new_game_box">
- <property name="orientation">vertical</property>
+ <object class="GtkScrolledWindow">
<property name="visible">True</property>
- <property name="halign">center</property>
- <property name="valign">center</property>
- <property name="margin">25</property>
- <property name="width-request">350</property>
- <property name="height-request">350</property>
- <property name="spacing">6</property>
+ <child>
+ <object class="GtkBox" id="new_game_box">
+ <property name="orientation">vertical</property>
+ <property name="visible">True</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ </object>
+ </child>
</object>
<packing>
<property name="name">start-box</property>
@@ -147,7 +148,6 @@
<object class="GtkBox" id="game_box">
<property name="visible">True</property>
<property name="orientation">horizontal</property>
- <property name="spacing">25</property>
<style>
<class name="game-box"/>
</style>
diff --git a/po/POTFILES.in b/po/POTFILES.in
index b19cd92..3301afb 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -6,6 +6,7 @@ data/org.gnome.Four-in-a-row.appdata.xml.in
data/org.gnome.Four-in-a-row.desktop.in
data/org.gnome.Four-in-a-row.gschema.xml
src/four-in-a-row.vala
+src/new-game-screen.vala
src/prefs.vala
src/scorebox.vala
src/theme.vala
diff --git a/po/POTFILES.skip b/po/POTFILES.skip
index b54d3e5..d86310f 100644
--- a/po/POTFILES.skip
+++ b/po/POTFILES.skip
@@ -1,4 +1,5 @@
src/four-in-a-row.c
+src/new-game-screen.c
src/prefs.c
src/scorebox.c
src/theme.c
diff --git a/src/adaptative-window.vala b/src/adaptative-window.vala
new file mode 100644
index 0000000..8c632cc
--- /dev/null
+++ b/src/adaptative-window.vala
@@ -0,0 +1,356 @@
+/* -*- Mode: vala; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ This file is part of GNOME Four-in-a-row.
+
+ Copyright © 2019 Arnaud Bonatti
+
+ GNOME Four-in-a-row 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 Four-in-a-row 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 Four-in-a-row. If not, see <https://www.gnu.org/licenses/>.
+*/
+
+using Gtk;
+
+private interface AdaptativeWidget : Object
+{ /*
+ ╎ extra ╎
+ ╎ thin ╎
+ ╶╶╶╶ ┏━━━━━━━┳━━━━━━━┳━━━━━──╴
+ extra ┃ PHONE ┃ PHONE ┃ EXTRA
+ flat ┃ _BOTH ┃ _HZTL ┃ _FLAT
+ ╶╶╶╶ ┣━━━━━━━╋━━━━━━━╋━━━━╾──╴
+ ┃ PHONE ┃ ┃
+ ┃ _VERT ┃ ┃
+ ┣━━━━━━━┫ ┃
+ ┃ EXTRA ┃ QUITE ╿ USUAL
+ ╿ _THIN │ _THIN │ _SIZE
+ ╵ ╵ ╵
+ ╎ quite thin ╎
+ */
+
+ internal enum WindowSize {
+ START_SIZE,
+ USUAL_SIZE,
+ QUITE_THIN,
+ PHONE_VERT,
+ PHONE_HZTL,
+ PHONE_BOTH,
+ EXTRA_THIN,
+ EXTRA_FLAT;
+
+ internal static inline bool is_phone_size (WindowSize window_size)
+ {
+ return (window_size == PHONE_BOTH) || (window_size == PHONE_VERT) || (window_size == PHONE_HZTL);
+ }
+
+ internal static inline bool is_extra_thin (WindowSize window_size)
+ {
+ return (window_size == PHONE_BOTH) || (window_size == PHONE_VERT) || (window_size == EXTRA_THIN);
+ }
+
+ internal static inline bool is_extra_flat (WindowSize window_size)
+ {
+ return (window_size == PHONE_BOTH) || (window_size == PHONE_HZTL) || (window_size == EXTRA_FLAT);
+ }
+
+ internal static inline bool is_quite_thin (WindowSize window_size)
+ {
+ return is_extra_thin (window_size) || (window_size == PHONE_HZTL) || (window_size == QUITE_THIN);
+ }
+ }
+
+ internal abstract void set_window_size (WindowSize new_size);
+}
+
+private const int LARGE_WINDOW_SIZE = 1042;
+
+[GtkTemplate (ui = "/org/gnome/Four-in-a-row/ui/adaptative-window.ui")]
+private abstract class AdaptativeWindow : ApplicationWindow
+{
+ [CCode (notify = false)] public string window_title
+ {
+ protected construct
+ {
+ string? _value = value;
+ if (_value == null)
+ assert_not_reached ();
+
+ title = value;
+ }
+ }
+
+ private StyleContext window_style_context;
+ [CCode (notify = false)] public string specific_css_class_or_empty
+ {
+ protected construct
+ {
+ string? _value = value;
+ if (_value == null)
+ assert_not_reached ();
+
+ window_style_context = get_style_context ();
+ if (value != "")
+ window_style_context.add_class (value);
+ }
+ }
+
+ construct
+ {
+ // window_style_context is created by specific_css_class_or_empty
+ window_style_context.add_class ("startup");
+
+ manage_high_contrast ();
+
+ load_window_state ();
+
+ Timeout.add (300, () => { window_style_context.remove_class ("startup"); return Source.REMOVE; });
+ }
+
+ /*\
+ * * callbacks
+ \*/
+
+ [GtkCallback]
+ private bool on_window_state_event (Widget widget, 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 */
+ bool window_was_fullscreen = window_is_fullscreen;
+ if ((event.changed_mask & Gdk.WindowState.FULLSCREEN) != 0)
+ window_is_fullscreen = (event.new_window_state & Gdk.WindowState.FULLSCREEN) != 0;
+ if (window_was_fullscreen && !window_is_fullscreen)
+ on_unfullscreen ();
+ else if (!window_was_fullscreen && window_is_fullscreen)
+ on_fullscreen ();
+
+ /* tiled: not saved, but should not change saved window size */
+ Gdk.WindowState tiled_state = Gdk.WindowState.TILED
+ | Gdk.WindowState.TOP_TILED
+ | Gdk.WindowState.BOTTOM_TILED
+ | Gdk.WindowState.LEFT_TILED
+ | Gdk.WindowState.RIGHT_TILED;
+ if ((event.changed_mask & tiled_state) != 0)
+ window_is_tiled = (event.new_window_state & tiled_state) != 0;
+
+ return false;
+ }
+ protected abstract void on_fullscreen ();
+ protected abstract void on_unfullscreen ();
+
+ [GtkCallback]
+ private void on_size_allocate (Allocation allocation)
+ {
+ int height = allocation.height;
+ int width = allocation.width;
+
+ update_adaptative_children (ref width, ref height);
+ update_window_state ();
+ }
+
+ [GtkCallback]
+ private void on_destroy ()
+ {
+ before_destroy ();
+ save_window_state ();
+ base.destroy ();
+ }
+
+ protected virtual void before_destroy () {}
+
+ /*\
+ * * adaptative stuff
+ \*/
+
+ private AdaptativeWidget.WindowSize window_size = AdaptativeWidget.WindowSize.START_SIZE;
+
+ private List<AdaptativeWidget> adaptative_children = new List<AdaptativeWidget> ();
+ protected void add_adaptative_child (AdaptativeWidget child)
+ {
+ adaptative_children.append (child);
+ }
+
+ private void update_adaptative_children (ref int width, ref int height)
+ {
+ bool extra_flat = height < 400;
+ bool flat = height < 500;
+
+ if (width < 590)
+ {
+ if (extra_flat) change_window_size (AdaptativeWidget.WindowSize.PHONE_BOTH);
+ else if (height < 787) change_window_size (AdaptativeWidget.WindowSize.PHONE_VERT);
+ else change_window_size (AdaptativeWidget.WindowSize.EXTRA_THIN);
+
+ set_style_classes (/* extra thin */ true, /* thin */ true, /* large */ false,
+ /* extra flat */ extra_flat, /* flat */ flat);
+ }
+ else if (width < 787)
+ {
+ if (extra_flat) change_window_size (AdaptativeWidget.WindowSize.PHONE_HZTL);
+ else change_window_size (AdaptativeWidget.WindowSize.QUITE_THIN);
+
+ set_style_classes (/* extra thin */ false, /* thin */ true, /* large */ false,
+ /* extra flat */ extra_flat, /* flat */ flat);
+ }
+ else
+ {
+ if (extra_flat) change_window_size (AdaptativeWidget.WindowSize.EXTRA_FLAT);
+ else change_window_size (AdaptativeWidget.WindowSize.USUAL_SIZE);
+
+ set_style_classes (/* extra thin */ false, /* thin */ false, /* large */ (width >
LARGE_WINDOW_SIZE),
+ /* extra flat */ extra_flat, /* flat */ flat);
+ }
+ }
+
+ private void change_window_size (AdaptativeWidget.WindowSize new_window_size)
+ {
+ if (window_size == new_window_size)
+ return;
+ window_size = new_window_size;
+ adaptative_children.@foreach ((adaptative_child) => adaptative_child.set_window_size
(new_window_size));
+ }
+
+ /*\
+ * * manage style classes
+ \*/
+
+ private bool has_extra_thin_window_class = false;
+ private bool has_thin_window_class = false;
+ private bool has_large_window_class = false;
+ private bool has_extra_flat_window_class = false;
+ private bool has_flat_window_class = false;
+
+ private void set_style_classes (bool extra_thin_window, bool thin_window, bool large_window,
+ bool extra_flat_window, bool flat_window)
+ {
+ // for width
+ if (has_extra_thin_window_class && !extra_thin_window)
+ set_style_class ("extra-thin-window", false, ref has_extra_thin_window_class);
+ if (has_thin_window_class && !thin_window)
+ set_style_class ("thin-window", false, ref has_thin_window_class);
+
+ if (large_window != has_large_window_class)
+ set_style_class ("large-window", large_window, ref has_large_window_class);
+ if (thin_window != has_thin_window_class)
+ set_style_class ("thin-window", thin_window, ref has_thin_window_class);
+ if (extra_thin_window != has_extra_thin_window_class)
+ set_style_class ("extra-thin-window", extra_thin_window, ref has_extra_thin_window_class);
+
+ // for height
+ if (has_extra_flat_window_class && !extra_flat_window)
+ set_style_class ("extra-flat-window", false, ref has_extra_flat_window_class);
+
+ if (flat_window != has_flat_window_class)
+ set_style_class ("flat-window", flat_window, ref has_flat_window_class);
+ if (extra_flat_window != has_extra_flat_window_class)
+ set_style_class ("extra-flat-window", extra_flat_window, ref has_extra_flat_window_class);
+ }
+
+ private inline void set_style_class (string class_name, bool new_state, ref bool old_state)
+ {
+ old_state = new_state;
+ if (new_state)
+ window_style_context.add_class (class_name);
+ else
+ window_style_context.remove_class (class_name);
+ }
+
+ /*\
+ * * manage window state
+ \*/
+
+ [CCode (notify = false)] public string schema_path
+ {
+ protected construct
+ {
+ string? _value = value;
+ if (_value == null)
+ assert_not_reached ();
+
+ settings = new GLib.Settings.with_path ("org.gnome.Four-in-a-row.Lib", value);
+ }
+ }
+ private GLib.Settings settings;
+
+ private int window_width = 0;
+ private int window_height = 0;
+ private bool window_is_maximized = false;
+ private bool window_is_fullscreen = false;
+ private bool window_is_tiled = false;
+
+ private void load_window_state () // called on construct
+ {
+ if (settings.get_boolean ("window-is-maximized"))
+ maximize ();
+ set_default_size (settings.get_int ("window-width"), settings.get_int ("window-height"));
+ }
+
+ private void update_window_state () // called on size-allocate
+ {
+ if (window_is_maximized || window_is_tiled || window_is_fullscreen)
+ return;
+ int? _window_width = null;
+ int? _window_height = null;
+ get_size (out _window_width, out _window_height);
+ if (_window_width == null || _window_height == null)
+ return;
+ window_width = (!) _window_width;
+ window_height = (!) _window_height;
+ }
+
+ private void save_window_state () // called on destroy
+ {
+ 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 ();
+ }
+
+ /*\
+ * * manage high-constrast
+ \*/
+
+ internal signal void gtk_theme_changed ();
+
+ private void manage_high_contrast ()
+ {
+ Gtk.Settings? nullable_gtk_settings = Gtk.Settings.get_default ();
+ if (nullable_gtk_settings == null)
+ return;
+
+ Gtk.Settings gtk_settings = (!) nullable_gtk_settings;
+ gtk_settings.notify ["gtk-theme-name"].connect (update_highcontrast_state);
+ _update_highcontrast_state (gtk_settings.gtk_theme_name);
+ }
+
+ private void update_highcontrast_state (Object gtk_settings, ParamSpec unused)
+ {
+ _update_highcontrast_state (((Gtk.Settings) gtk_settings).gtk_theme_name);
+ gtk_theme_changed ();
+ }
+
+ private bool highcontrast_state = false;
+ private void _update_highcontrast_state (string theme_name)
+ {
+ bool highcontrast_new_state = "HighContrast" in theme_name;
+ if (highcontrast_new_state == highcontrast_state)
+ return;
+ highcontrast_state = highcontrast_new_state;
+
+ if (highcontrast_new_state)
+ window_style_context.add_class ("hc-theme");
+ else
+ window_style_context.remove_class ("hc-theme");
+ }
+}
diff --git a/src/four-in-a-row.gresource.xml b/src/four-in-a-row.gresource.xml
index 492aeed..2143cd1 100644
--- a/src/four-in-a-row.gresource.xml
+++ b/src/four-in-a-row.gresource.xml
@@ -10,6 +10,7 @@
</gresource>
<gresource prefix="/org/gnome/Four-in-a-row/ui">
<file alias="four-in-a-row.css">../data/four-in-a-row.css</file>
+ <file preprocess="xml-stripblanks" compressed="true"
alias="adaptative-window.ui">../data/ui/adaptative-window.ui</file>
<file preprocess="xml-stripblanks" compressed="true"
alias="fiar-screens.ui">../data/ui/fiar-screens.ui</file>
<file preprocess="xml-stripblanks" compressed="true"
alias="game-window.ui">../data/ui/four-in-a-row.ui</file>
</gresource>
diff --git a/src/four-in-a-row.vala b/src/four-in-a-row.vala
index d5f2a02..d31bac0 100644
--- a/src/four-in-a-row.vala
+++ b/src/four-in-a-row.vala
@@ -77,6 +77,7 @@ private class FourInARow : Gtk.Application
private GameBoardView game_board_view;
private Board game_board;
private GameWindow window;
+ private NewGameScreen new_game_screen;
// game state
private char vstr [53];
@@ -99,6 +100,7 @@ private class FourInARow : Gtk.Application
private const GLib.ActionEntry app_entries [] = // see also add_actions()
{
+ { "game-type", null, "s", "'dark'", change_game_type },
{ "scores", on_game_scores },
{ "quit", on_game_exit },
{ "help", on_help_contents },
@@ -181,11 +183,13 @@ private class FourInARow : Gtk.Application
private inline void add_actions ()
{
- add_action (Prefs.instance.settings.create_action ("sound"));
- add_action (Prefs.instance.settings.create_action ("theme-id"));
- add_action (Prefs.instance.settings.create_action ("num-players"));
- add_action (Prefs.instance.settings.create_action ("first-player"));
- add_action (Prefs.instance.settings.create_action ("opponent"));
+ GLib.Settings settings = Prefs.instance.settings;
+
+ add_action (settings.create_action ("sound"));
+ add_action (settings.create_action ("theme-id"));
+ add_action (settings.create_action ("num-players"));
+ add_action (settings.create_action ("first-player"));
+ add_action (settings.create_action ("opponent"));
set_accels_for_action ("ui.new-game", { "<Primary>n" });
set_accels_for_action ("ui.start-game", { "<Shift><Primary>n" });
@@ -199,6 +203,63 @@ private class FourInARow : Gtk.Application
set_accels_for_action ("app.about", { "<Shift>F1" });
add_action_entries (app_entries, this);
+
+ game_type_action = (SimpleAction) lookup_action ("game-type");
+
+ settings.changed ["first-player"].connect (() => {
+ if (settings.get_int ("num-players") == 2)
+ return;
+ if (settings.get_string ("first-player") == "human")
+ game_type_action.set_state (new Variant.string ("human"));
+ else
+ game_type_action.set_state (new Variant.string ("computer"));
+ });
+
+ settings.changed ["num-players"].connect (() => {
+ bool solo = settings.get_int ("num-players") == 1;
+ new_game_screen.update_sensitivity (solo);
+ reset_score = true;
+ if (!solo)
+ game_type_action.set_state (new Variant.string ("two"));
+ else if (settings.get_string ("first-player") == "human")
+ game_type_action.set_state (new Variant.string ("human"));
+ else
+ game_type_action.set_state (new Variant.string ("computer"));
+ if (solo)
+ last_first_player = PlayerID.NOBODY;
+ });
+ bool solo = settings.get_int ("num-players") == 1;
+ new_game_screen.update_sensitivity (solo);
+
+ if (settings.get_int ("num-players") == 2)
+ game_type_action.set_state (new Variant.string ("two"));
+ else if (settings.get_string ("first-player") == "human")
+ game_type_action.set_state (new Variant.string ("human"));
+ else
+ game_type_action.set_state (new Variant.string ("computer"));
+
+ settings.changed ["opponent"].connect (() => {
+ if (settings.get_int ("num-players") != 1)
+ return;
+ reset_score = true;
+ });
+ }
+
+ private SimpleAction game_type_action;
+ private void change_game_type (SimpleAction action, Variant? gvariant)
+ requires (gvariant != null)
+ {
+ string type = ((!) gvariant).get_string ();
+// game_type_action.set_state ((!) gvariant);
+ switch (type)
+ {
+ case "human" : Prefs.instance.settings.set_int ("num-players", 1);
new_game_screen.update_sensitivity (true);
+ Prefs.instance.settings.set_string ("first-player", "human");
return;
+ case "computer" : Prefs.instance.settings.set_int ("num-players", 1);
new_game_screen.update_sensitivity (true);
+ Prefs.instance.settings.set_string ("first-player", "computer");
return;
+ case "two" : Prefs.instance.settings.set_int ("num-players", 2);
new_game_screen.update_sensitivity (false); return;
+ default: assert_not_reached ();
+ }
}
private inline bool column_clicked_cb (int column)
@@ -277,12 +338,6 @@ private class FourInARow : Gtk.Application
game_reset ();
}
- protected override void shutdown ()
- {
- window.shutdown (Prefs.instance.settings);
- base.shutdown ();
- }
-
private void prompt_player ()
{
bool human = is_player_human ();
@@ -741,7 +796,8 @@ private class FourInARow : Gtk.Application
base.startup ();
/* UI parts */
- Builder builder = new Builder.from_resource ("/org/gnome/Four-in-a-row/ui/fiar-screens.ui");
+ new_game_screen = new NewGameScreen ();
+ new_game_screen.show ();
game_board_view = new GameBoardView (game_board);
game_board_view.show ();
@@ -777,12 +833,9 @@ private class FourInARow : Gtk.Application
/* Window */
window = new GameWindow ("/org/gnome/Four-in-a-row/ui/four-in-a-row.css",
PROGRAM_NAME,
- Prefs.instance.settings.get_int ("window-width"),
- Prefs.instance.settings.get_int ("window-height"),
- Prefs.instance.settings.get_boolean ("window-is-maximized"),
/* start_now */ true,
GameWindowFlags.SHOW_START_BUTTON,
- (Box) builder.get_object ("new-game-screen"),
+ (Box) new_game_screen,
game_board_view,
app_menu);
@@ -790,26 +843,6 @@ private class FourInARow : Gtk.Application
add_actions ();
- Widget level_box = (Widget) (!) builder.get_object ("difficulty-box");
- Widget start_box = (Widget) (!) builder.get_object ("start-box");
- Prefs.instance.settings.changed ["num-players"].connect (() => {
- bool solo = Prefs.instance.settings.get_int ("num-players") == 1;
- level_box.sensitive = solo;
- start_box.sensitive = solo;
- reset_score = true;
- if (solo)
- last_first_player = PlayerID.NOBODY;
- });
- bool solo = Prefs.instance.settings.get_int ("num-players") == 1;
- level_box.sensitive = solo;
- start_box.sensitive = solo;
-
- Prefs.instance.settings.changed ["opponent"].connect (() => {
- if (Prefs.instance.settings.get_int ("num-players") != 1)
- return;
- reset_score = true;
- });
-
/* various */
game_board_view.column_clicked.connect (column_clicked_cb);
window.key_press_event.connect (on_key_press);
diff --git a/src/game-board-view.vala b/src/game-board-view.vala
index 1f4e71c..59d80e1 100644
--- a/src/game-board-view.vala
+++ b/src/game-board-view.vala
@@ -31,8 +31,6 @@ private class GameBoardView : Gtk.DrawingArea {
private Board game_board;
internal GameBoardView(Board game_board) {
- /* set a min size to avoid pathological behavior of gtk when scaling down */
- set_size_request(350, 350);
halign = Gtk.Align.FILL;
valign = Gtk.Align.FILL;
diff --git a/src/game-window.vala b/src/game-window.vala
index bf9b5fd..f1f5df9 100644
--- a/src/game-window.vala
+++ b/src/game-window.vala
@@ -29,7 +29,7 @@ private enum GameWindowFlags {
}
[GtkTemplate (ui = "/org/gnome/Four-in-a-row/ui/game-window.ui")]
-private class GameWindow : ApplicationWindow
+private class GameWindow : AdaptativeWindow
{
/* settings */
private bool window_is_tiled;
@@ -66,8 +66,12 @@ private class GameWindow : ApplicationWindow
// internal signal void redo ();
internal signal void hint ();
- internal GameWindow (string? css_resource, string name, int width, int height, bool maximized, bool
start_now, GameWindowFlags flags, Box new_game_screen, Widget _view, GLib.Menu app_menu)
+ internal GameWindow (string? css_resource, string name, bool start_now, GameWindowFlags flags, Box
new_game_screen, Widget _view, GLib.Menu app_menu)
{
+ Object (window_title: name,
+ specific_css_class_or_empty: "",
+ schema_path: "/org/gnome/Four-in-a-row/");
+
if (css_resource != null)
{
CssProvider css_provider = new CssProvider ();
@@ -86,21 +90,16 @@ private class GameWindow : ApplicationWindow
headerbar.set_title (name);
info_button.set_menu_model (app_menu);
- set_default_size (width, height);
- if (maximized)
- maximize ();
-
- size_allocate.connect (size_allocate_cb);
- window_state_event.connect (window_state_event_cb);
-
/* add widgets */
new_game_box.pack_start (new_game_screen, true, true, 0);
+ add_adaptative_child ((AdaptativeWidget) new_game_screen);
if (GameWindowFlags.SHOW_START_BUTTON in flags)
{
/* Translators: when configuring a new game, label of the blue Start button (with a mnemonic
that appears pressing Alt) */
Button _start_game_button = new Button.with_mnemonic (_("_Start Game"));
- _start_game_button.width_request = 222;
- _start_game_button.height_request = 60;
+// _start_game_button.width_request = 222;
+// _start_game_button.height_request = 60;
+ _start_game_button.get_style_context ().add_class ("start-game-button");
_start_game_button.halign = Align.CENTER;
_start_game_button.set_action_name ("ui.start-game");
/* Translators: when configuring a new game, tooltip text of the blue Start button */
@@ -168,47 +167,14 @@ private class GameWindow : ApplicationWindow
* * Window events
\*/
- private void size_allocate_cb ()
- {
- if (window_is_maximized || window_is_tiled || window_is_fullscreen)
- return;
- get_size (out window_width, out window_height);
- }
-
- private bool window_state_event_cb (Gdk.EventWindowState event)
+ protected override void on_fullscreen ()
{
- if ((event.changed_mask & Gdk.WindowState.MAXIMIZED) != 0)
- window_is_maximized = (event.new_window_state & Gdk.WindowState.MAXIMIZED) != 0;
-
- /* fullscreen: saved as maximized */
- bool window_was_fullscreen = window_is_fullscreen;
- if ((event.changed_mask & Gdk.WindowState.FULLSCREEN) != 0)
- window_is_fullscreen = (event.new_window_state & Gdk.WindowState.FULLSCREEN) != 0;
- if (window_was_fullscreen && !window_is_fullscreen)
- unfullscreen_button.hide ();
- else if (!window_was_fullscreen && window_is_fullscreen)
- unfullscreen_button.show ();
-
- /* tiled: not saved, but should not change saved window size */
- Gdk.WindowState tiled_state = Gdk.WindowState.TILED
- | Gdk.WindowState.TOP_TILED
- | Gdk.WindowState.BOTTOM_TILED
- | Gdk.WindowState.LEFT_TILED
- | Gdk.WindowState.RIGHT_TILED;
- if ((event.changed_mask & tiled_state) != 0)
- window_is_tiled = (event.new_window_state & tiled_state) != 0;
-
- return false;
+ unfullscreen_button.show ();
}
- internal void shutdown (GLib.Settings settings)
+ protected override void on_unfullscreen ()
{
- 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 ();
- destroy ();
+ unfullscreen_button.hide ();
}
/*\
diff --git a/src/meson.build b/src/meson.build
index 9744346..dbb2617 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -18,11 +18,13 @@ test('four-in-a-row-tests',
resources = gnome.compile_resources (meson.project_name(), 'four-in-a-row.gresource.xml')
sources = files(
+ 'adaptative-window.vala',
'ai.vala',
'four-in-a-row.vala',
'game-board-view.vala',
'game-board.vala',
'game-window.vala',
+ 'new-game-screen.vala',
'prefs.vala',
'scorebox.vala',
'theme.vala',
diff --git a/src/new-game-screen.vala b/src/new-game-screen.vala
new file mode 100644
index 0000000..2c9f94f
--- /dev/null
+++ b/src/new-game-screen.vala
@@ -0,0 +1,149 @@
+/* -*- Mode: vala; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ This file is part of GNOME Four-in-a-row.
+
+ Copyright 2010-2013 Robert Ancell
+ Copyright 2013-2014 Michael Catanzaro
+ Copyright 2014-2019 Arnaud Bonatti
+
+ GNOME Four-in-a-row 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 Four-in-a-row 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 Four-in-a-row. If not, see <https://www.gnu.org/licenses/>.
+*/
+
+using Gtk;
+
+[GtkTemplate (ui = "/org/gnome/Four-in-a-row/ui/fiar-screens.ui")]
+private class NewGameScreen : Box, AdaptativeWidget
+{
+ [GtkChild] private Box infos_section;
+ [GtkChild] private Box users_section;
+ [GtkChild] private Box start_section;
+
+ [GtkChild] private Box users_box;
+ [GtkChild] private Box level_box;
+ [GtkChild] private Box start_box;
+
+ internal void update_sensitivity (bool new_sensitivity)
+ {
+ level_box.sensitive = new_sensitivity;
+ start_box.sensitive = new_sensitivity;
+ }
+
+ private bool quite_thin = false;
+ private bool extra_thin = true; // extra_thin && !quite_thin is impossible, so it will not return in
next method the first time
+ private bool extra_flat = false;
+ private void set_window_size (AdaptativeWidget.WindowSize new_size)
+ {
+ bool _quite_thin = WindowSize.is_quite_thin (new_size);
+ bool _extra_thin = WindowSize.is_extra_thin (new_size);
+ bool _extra_flat = WindowSize.is_extra_flat (new_size);
+
+ if ((_quite_thin == quite_thin)
+ && (_extra_thin == extra_thin)
+ && (_extra_flat == extra_flat))
+ return;
+ quite_thin = _quite_thin;
+ extra_thin = _extra_thin;
+ extra_flat = _extra_flat;
+
+ if (extra_thin)
+ {
+ set_orientation (Orientation.VERTICAL);
+ spacing = 18;
+ homogeneous = false;
+ height_request = 360;
+ width_request = 250;
+ margin_bottom = 22;
+
+ users_section.hide ();
+ start_section.hide ();
+ infos_section.show ();
+
+ level_box.set_orientation (Orientation.VERTICAL);
+
+ users_box.set_spacing (0);
+ level_box.set_spacing (0);
+ start_box.set_spacing (0);
+
+ users_box.get_style_context ().add_class ("linked");
+ level_box.get_style_context ().add_class ("linked");
+ start_box.get_style_context ().add_class ("linked");
+ }
+ else if (extra_flat)
+ {
+ set_orientation (Orientation.HORIZONTAL);
+ homogeneous = true;
+ height_request = 113;
+ margin_bottom = 6;
+ if (quite_thin)
+ {
+ spacing = 21;
+ width_request = 420;
+ }
+ else
+ {
+ spacing = 24;
+ width_request = 450;
+ }
+
+ users_section.hide ();
+ start_section.hide ();
+ infos_section.show ();
+
+ level_box.set_orientation (Orientation.VERTICAL);
+
+ users_box.set_spacing (0);
+ level_box.set_spacing (0);
+ start_box.set_spacing (0);
+
+ users_box.get_style_context ().add_class ("linked");
+ level_box.get_style_context ().add_class ("linked");
+ start_box.get_style_context ().add_class ("linked");
+ }
+ else
+ {
+ set_orientation (Orientation.VERTICAL);
+ spacing = 18;
+ height_request = 263;
+ int boxes_spacing;
+ if (quite_thin)
+ {
+ boxes_spacing = 10;
+ width_request = 380;
+ }
+ else
+ {
+ boxes_spacing = 12;
+ width_request = 400;
+ }
+ margin_bottom = 22;
+
+ infos_section.hide ();
+ users_section.show ();
+ start_section.show ();
+
+ level_box.set_orientation (Orientation.HORIZONTAL);
+
+ users_box.get_style_context ().remove_class ("linked");
+ level_box.get_style_context ().remove_class ("linked");
+ start_box.get_style_context ().remove_class ("linked");
+
+ users_box.set_spacing (boxes_spacing);
+ level_box.set_spacing (boxes_spacing);
+ start_box.set_spacing (boxes_spacing);
+
+ homogeneous = true;
+ }
+ queue_allocate ();
+ }
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]