[gnome-2048] Introduce GameHeaderBar.
- From: Arnaud B. <arnaudb src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-2048] Introduce GameHeaderBar.
- Date: Sat, 9 Feb 2019 07:54:40 +0000 (UTC)
commit 0b2eb15555570a99ef2cb4cd52948bcbfd84fe59
Author: Arnaud Bonatti <arnaud bonatti gmail com>
Date: Thu Feb 7 18:59:28 2019 +0100
Introduce GameHeaderBar.
data/game-headerbar.ui | 70 +++++++++++
data/mainwindow.ui | 49 +-------
po/POTFILES.in | 2 +
po/POTFILES.skip | 1 +
src/game-headerbar.vala | 181 +++++++++++++++++++++++++++
src/game-window.vala | 174 ++++++-------------------
src/meson.build | 1 +
src/org.gnome.TwentyFortyEight.gresource.xml | 1 +
8 files changed, 292 insertions(+), 187 deletions(-)
---
diff --git a/data/game-headerbar.ui b/data/game-headerbar.ui
new file mode 100644
index 0000000..e01573a
--- /dev/null
+++ b/data/game-headerbar.ui
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ This file is part of GNOME 2048
+
+ GNOME 2048 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 2048 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 2048. If not, see <https://www.gnu.org/licenses/>.
+-->
+<interface>
+ <requires lib="gtk+" version="3.12"/>
+ <template class="GameHeaderBar" parent="GtkHeaderBar">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <!-- Translators: title of the window, displayed in the headerbar -->
+ <property name="title" translatable="yes">GNOME 2048</property>
+ <property name="show-close-button">True</property>
+ <child>
+ <object class="GtkMenuButton" id="_new_game_button">
+ <!-- Translators: button in the headerbar (with a mnemonic that appears pressing Alt) -->
+ <property name="label" translatable="yes">_New Game</property>
+ <property name="visible">True</property>
+ <property name="valign">center</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="use-underline">True</property>
+ <property name="focus-on-click">False</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuButton" id="_hamburger_button">
+ <property name="visible">True</property>
+ <property name="halign">end</property>
+ <property name="valign">center</property>
+ <property name="focus-on-click">False</property>
+ <style>
+ <class name="image-button"/>
+ </style>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="icon-name">open-menu-symbolic</property>
+ <property name="icon-size">1</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="pack-type">end</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="_score">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label">0</property>
+ </object>
+ <packing>
+ <property name="pack-type">end</property>
+ </packing>
+ </child>
+ </template>
+</interface>
diff --git a/data/mainwindow.ui b/data/mainwindow.ui
index 6fe7fd4..18d725f 100644
--- a/data/mainwindow.ui
+++ b/data/mainwindow.ui
@@ -28,55 +28,8 @@
<signal name="size-allocate" handler="size_allocate_cb"/>
<signal name="window-state-event" handler="state_event_cb"/>
<child type="titlebar">
- <object class="GtkHeaderBar" id="_header_bar">
+ <object class="GameHeaderBar" id="_header_bar">
<property name="visible">True</property>
- <property name="can-focus">False</property>
- <!-- Translators: title of the window, displayed in the headerbar -->
- <property name="title" translatable="yes">GNOME 2048</property>
- <property name="show-close-button">True</property>
- <child>
- <object class="GtkMenuButton" id="_new_game_button">
- <!-- Translators: button in the headerbar (with a mnemonic that appears pressing Alt) -->
- <property name="label" translatable="yes">_New Game</property>
- <property name="visible">True</property>
- <property name="valign">center</property>
- <property name="can-focus">True</property>
- <property name="receives-default">True</property>
- <property name="use-underline">True</property>
- <property name="focus-on-click">False</property>
- </object>
- </child>
- <child>
- <object class="GtkMenuButton" id="_hamburger_button">
- <property name="visible">True</property>
- <property name="halign">end</property>
- <property name="valign">center</property>
- <property name="focus-on-click">False</property>
- <style>
- <class name="image-button"/>
- </style>
- <child>
- <object class="GtkImage">
- <property name="visible">True</property>
- <property name="icon-name">open-menu-symbolic</property>
- <property name="icon-size">1</property>
- </object>
- </child>
- </object>
- <packing>
- <property name="pack-type">end</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="_score">
- <property name="visible">True</property>
- <property name="can-focus">False</property>
- <property name="label">0</property>
- </object>
- <packing>
- <property name="pack-type">end</property>
- </packing>
- </child>
</object>
</child>
<child>
diff --git a/po/POTFILES.in b/po/POTFILES.in
index b4aa7de..422667c 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -1,9 +1,11 @@
# List of source files containing translatable strings.
# Please keep this file in alphabetical order.
data/congrats.ui
+data/game-headerbar.ui
data/help-overlay.ui
data/mainwindow.ui
data/org.gnome.TwentyFortyEight.appdata.xml.in
data/org.gnome.TwentyFortyEight.desktop.in
data/org.gnome.TwentyFortyEight.gschema.xml
+src/game-headerbar.vala
src/game-window.vala
diff --git a/po/POTFILES.skip b/po/POTFILES.skip
index a2a2067..67dc020 100644
--- a/po/POTFILES.skip
+++ b/po/POTFILES.skip
@@ -1 +1,2 @@
+src/game-headerbar.c
src/game-window.c
diff --git a/src/game-headerbar.vala b/src/game-headerbar.vala
new file mode 100644
index 0000000..bc076e5
--- /dev/null
+++ b/src/game-headerbar.vala
@@ -0,0 +1,181 @@
+/* Copyright (C) 2014-2015 Juan R. García Blanco <juanrgar gmail com>
+ * Copyright (C) 2016-2019 Arnaud Bonatti <arnaud bonatti gmail com>
+ *
+ * This file is part of GNOME 2048.
+ *
+ * GNOME 2048 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 2048 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 2048; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+using Gtk;
+
+[GtkTemplate (ui = "/org/gnome/TwentyFortyEight/ui/game-headerbar.ui")]
+private class GameHeaderBar : HeaderBar
+{
+ [GtkChild] private Label _score;
+ [GtkChild] private MenuButton _new_game_button;
+ [GtkChild] private MenuButton _hamburger_button;
+
+ /*\
+ * * popovers
+ \*/
+
+ internal signal void popover_closed ();
+
+ construct
+ {
+ _hamburger_button.notify ["active"].connect (test_popover_closed);
+ _new_game_button.notify ["active"].connect (test_popover_closed);
+ }
+
+ private void test_popover_closed ()
+ {
+ if (!has_popover ())
+ popover_closed ();
+ }
+
+ internal bool has_popover ()
+ {
+ return _hamburger_button.active || _new_game_button.active;
+ }
+
+ /*\
+ * * texts
+ \*/
+
+ internal void clear_subtitle ()
+ {
+ set_subtitle (null);
+ set_has_subtitle (false);
+ }
+
+ internal void finished ()
+ {
+ set_has_subtitle (true);
+ /* Translators: subtitle of the headerbar, when the user cannot move anymore */
+ subtitle = _("Game Over");
+ }
+
+ internal void set_score (Object game, ParamSpec unused)
+ {
+ _score.label = ((Game) game).score.to_string ();
+ }
+
+ /*\
+ * * hamburger menu
+ \*/
+
+ internal void _update_hamburger_menu (bool allow_undo)
+ {
+ GLib.Menu menu = new GLib.Menu ();
+
+ if (allow_undo)
+ _append_undo_section (ref menu);
+ _append_scores_section (ref menu);
+ _append_app_actions_section (ref menu);
+
+ menu.freeze ();
+ _hamburger_button.set_menu_model ((MenuModel) menu);
+ }
+
+ private static inline void _append_undo_section (ref GLib.Menu menu)
+ {
+ GLib.Menu section = new GLib.Menu ();
+
+ /* Translators: entry in the hamburger menu, if the "Allow undo" option is set to true */
+ section.append (_("Undo"), "ui.undo");
+
+ section.freeze ();
+ menu.append_section (null, section);
+ }
+
+ private static inline void _append_scores_section (ref GLib.Menu menu)
+ {
+ GLib.Menu section = new GLib.Menu ();
+
+ /* Translators: entry in the hamburger menu; opens a window showing best scores */
+ section.append (_("Scores"), "ui.scores");
+
+ section.freeze ();
+ menu.append_section (null, section);
+ }
+
+ private static inline void _append_app_actions_section (ref GLib.Menu menu)
+ {
+ GLib.Menu section = new GLib.Menu ();
+
+ /* Translators: usual menu entry of the hamburger menu */
+ section.append (_("Keyboard Shortcuts"), "win.show-help-overlay");
+
+ /* Translators: entry in the hamburger menu */
+ section.append (_("About 2048"), "ui.about");
+
+ section.freeze ();
+ menu.append_section (null, section);
+ }
+
+ internal void toggle_hamburger_menu ()
+ {
+ _hamburger_button.active = !_hamburger_button.active;
+ }
+
+ /*\
+ * * new-game menu
+ \*/
+
+ internal void _update_new_game_menu (int rows, int cols)
+ {
+ GLib.Menu menu = new GLib.Menu ();
+
+ /* Translators: on main window, entry of the menu when clicking on the "New Game" button; to change
grid size to 3 × 3 */
+ _append_new_game_item (_("3 × 3"),
+ /* rows */ 3,
+ /* cols */ 3,
+ ref menu);
+
+ /* Translators: on main window, entry of the menu when clicking on the "New Game" button; to change
grid size to 4 × 4 */
+ _append_new_game_item (_("4 × 4"),
+ /* rows */ 4,
+ /* cols */ 4,
+ ref menu);
+
+ /* Translators: on main window, entry of the menu when clicking on the "New Game" button; to change
grid size to 5 × 5 */
+ _append_new_game_item (_("5 × 5"),
+ /* rows */ 5,
+ /* cols */ 5,
+ ref menu);
+
+ bool is_square = rows == cols;
+ bool disallowed_grid = GameWindow.is_disallowed_grid_size (ref rows, ref cols);
+ if (disallowed_grid && !is_square)
+ /* Translators: command-line warning displayed if the user manually sets a invalid grid size */
+ warning (_("Grids of size 1 by 2 are disallowed."));
+
+ if (!disallowed_grid && (!is_square || (is_square && rows != 4 && rows != 3 && rows != 5)))
+ /* Translators: on main window, entry of the menu when clicking on the "New Game" button;
appears only if the user has set rows and cols manually */
+ _append_new_game_item (_("Custom"), /* rows */ rows, /* cols */ cols, ref menu);
+
+ menu.freeze ();
+ _new_game_button.set_menu_model ((MenuModel) menu);
+ }
+ private static void _append_new_game_item (string label, int rows, int cols, ref GLib.Menu menu)
+ {
+ Variant variant = new Variant ("(ii)", rows, cols);
+ menu.append (label, "ui.new-game-sized(" + variant.print (/* annotate types */ true) + ")");
+ }
+
+ internal void toggle_new_game ()
+ {
+ _new_game_button.active = !_new_game_button.active;
+ }
+}
diff --git a/src/game-window.vala b/src/game-window.vala
index b0eb751..3621aa2 100644
--- a/src/game-window.vala
+++ b/src/game-window.vala
@@ -33,10 +33,7 @@ private class GameWindow : ApplicationWindow
private bool _window_maximized;
private bool _window_is_tiled;
- [GtkChild] private HeaderBar _header_bar;
- [GtkChild] private Label _score;
- [GtkChild] private MenuButton _new_game_button;
- [GtkChild] private MenuButton _hamburger_button;
+ [GtkChild] private GameHeaderBar _header_bar;
[GtkChild] private GtkClutter.Embed _embed;
private Game _game;
@@ -95,6 +92,20 @@ private class GameWindow : ApplicationWindow
{ "about", about_cb }
};
+ /*\
+ * * menus
+ \*/
+
+ private void toggle_new_game_cb (/* SimpleAction action, Variant? variant */)
+ {
+ _header_bar.toggle_new_game ();
+ }
+
+ private void toggle_hamburger_menu (/* SimpleAction action, Variant? variant */)
+ {
+ _header_bar.toggle_hamburger_menu ();
+ }
+
/*\
* * game
\*/
@@ -102,13 +113,9 @@ private class GameWindow : ApplicationWindow
private void _init_game ()
{
_game = new Game (ref _settings);
- _game.notify ["score"].connect ((s, p) => {
- _score.label = _game.score.to_string ();
- });
+ _game.notify ["score"].connect (_header_bar.set_score);
_game.finished.connect ((s) => {
- _header_bar.set_has_subtitle (true);
- /* Translators: subtitle of the headerbar, when the user cannot move anymore */
- _header_bar.subtitle = _("Game Over");
+ _header_bar.finished ();
if (!_game_restored)
_show_best_scores ();
@@ -130,19 +137,16 @@ private class GameWindow : ApplicationWindow
if (_settings.get_boolean ("window-maximized"))
maximize ();
- _hamburger_button.notify ["active"].connect (() => {
- if (!_hamburger_button.active)
- _embed.grab_focus ();
- });
+ _header_bar.popover_closed.connect (() => _embed.grab_focus ());
_settings.changed.connect ((settings, key_name) => {
switch (key_name)
{
case "cols":
case "rows":
- _update_new_game_menu ();
+ _header_bar._update_new_game_menu (_settings.get_int ("rows"), _settings.get_int
("cols"));
return;
case "allow-undo":
- _update_hamburger_menu ();
+ _header_bar._update_hamburger_menu (_settings.get_boolean ("allow-undo"));
_game.load_settings (ref _settings);
return;
case "allow-undo-max":
@@ -151,8 +155,8 @@ private class GameWindow : ApplicationWindow
return;
}
});
- _update_new_game_menu ();
- _update_hamburger_menu ();
+ _header_bar._update_new_game_menu (_settings.get_int ("rows"), _settings.get_int ("cols"));
+ _header_bar._update_hamburger_menu (_settings.get_boolean ("allow-undo"));
_game.load_settings (ref _settings);
_game.view = _embed.get_stage ();
@@ -166,78 +170,22 @@ private class GameWindow : ApplicationWindow
}
/*\
- * * hamburger menu (and undo action) callbacks
+ * * undo action
\*/
- private void _update_hamburger_menu ()
- {
- GLib.Menu menu = new GLib.Menu ();
-
- if (_settings.get_boolean ("allow-undo"))
- _append_undo_section (ref menu);
- _append_scores_section (ref menu);
- _append_app_actions_section (ref menu);
-
- menu.freeze ();
- _hamburger_button.set_menu_model ((MenuModel) menu);
- }
-
- private static inline void _append_undo_section (ref GLib.Menu menu)
- {
- GLib.Menu section = new GLib.Menu ();
-
- /* Translators: entry in the hamburger menu, if the "Allow undo" option is set to true */
- section.append (_("Undo"), "ui.undo");
-
- section.freeze ();
- menu.append_section (null, section);
- }
-
- private static inline void _append_scores_section (ref GLib.Menu menu)
- {
- GLib.Menu section = new GLib.Menu ();
-
- /* Translators: entry in the hamburger menu; opens a window showing best scores */
- section.append (_("Scores"), "ui.scores");
-
- section.freeze ();
- menu.append_section (null, section);
- }
-
- private static inline void _append_app_actions_section (ref GLib.Menu menu)
- {
- GLib.Menu section = new GLib.Menu ();
-
- /* Translators: usual menu entry of the hamburger menu */
- section.append (_("Keyboard Shortcuts"), "win.show-help-overlay");
-
- /* Translators: entry in the hamburger menu */
- section.append (_("About 2048"), "ui.about");
-
- section.freeze ();
- menu.append_section (null, section);
- }
-
- private void toggle_hamburger_menu (/* SimpleAction action, Variant? variant */)
- {
- _hamburger_button.active = !_hamburger_button.active;
- }
-
private void undo_cb (/* SimpleAction action, Variant? variant */)
{
if (!_settings.get_boolean ("allow-undo")) // for the keyboard shortcut
return;
- _header_bar.set_subtitle (null);
- _header_bar.set_has_subtitle (false);
+ _header_bar.clear_subtitle ();
_game.undo ();
}
private void new_game_cb (/* SimpleAction action, Variant? variant */)
{
- _header_bar.set_subtitle (null);
- _header_bar.set_has_subtitle (false);
+ _header_bar.clear_subtitle ();
_game_restored = false;
_game.new_game (ref _settings);
@@ -245,11 +193,6 @@ private class GameWindow : ApplicationWindow
_embed.grab_focus ();
}
- private void toggle_new_game_cb (/* SimpleAction action, Variant? variant */)
- {
- _new_game_button.active = !_new_game_button.active;
- }
-
private void new_game_sized_cb (SimpleAction action, Variant? variant)
requires (variant != null)
{
@@ -288,62 +231,6 @@ private class GameWindow : ApplicationWindow
null);
}
- /*\
- * * new-game menu
- \*/
-
- private void _update_new_game_menu ()
- {
- GLib.Menu menu = new GLib.Menu ();
-
- /* Translators: on main window, entry of the menu when clicking on the "New Game" button; to change
grid size to 3 × 3 */
- _append_new_game_item (_("3 × 3"),
- /* rows */ 3,
- /* cols */ 3,
- ref menu);
-
- /* Translators: on main window, entry of the menu when clicking on the "New Game" button; to change
grid size to 4 × 4 */
- _append_new_game_item (_("4 × 4"),
- /* rows */ 4,
- /* cols */ 4,
- ref menu);
-
- /* Translators: on main window, entry of the menu when clicking on the "New Game" button; to change
grid size to 5 × 5 */
- _append_new_game_item (_("5 × 5"),
- /* rows */ 5,
- /* cols */ 5,
- ref menu);
-
- int rows = _settings.get_int ("rows");
- int cols = _settings.get_int ("cols");
- bool is_square = rows == cols;
- bool disallowed_grid = is_disallowed_grid_size (ref rows, ref cols);
- if (disallowed_grid && !is_square)
- /* Translators: command-line warning displayed if the user manually sets a invalid grid size */
- warning (_("Grids of size 1 by 2 are disallowed."));
-
- if (!disallowed_grid && (!is_square || (is_square && rows != 4 && rows != 3 && rows != 5)))
- /* Translators: on main window, entry of the menu when clicking on the "New Game" button;
appears only if the user has set rows and cols manually */
- _append_new_game_item (_("Custom"), /* rows */ rows, /* cols */ cols, ref menu);
-
- menu.freeze ();
- _new_game_button.set_menu_model ((MenuModel) menu);
- }
- private static void _append_new_game_item (string label, int rows, int cols, ref GLib.Menu menu)
- {
- Variant variant = new Variant ("(ii)", rows, cols);
- menu.append (label, "ui.new-game-sized(" + variant.print (/* annotate types */ true) + ")");
- }
-
- internal static bool is_disallowed_grid_size (ref int rows, ref int cols)
- requires (rows >= 1)
- requires (rows <= 9)
- requires (cols >= 1)
- requires (cols <= 9)
- {
- return (rows == 1 && cols == 1) || (rows == 1 && cols == 2) || (rows == 2 && cols == 1);
- }
-
/*\
* * window management callbacks
\*/
@@ -356,7 +243,7 @@ private class GameWindow : ApplicationWindow
[GtkCallback]
private bool key_press_event_cb (Widget widget, Gdk.EventKey event)
{
- if (_hamburger_button.active || (((Window) widget).focus_visible && !_embed.is_focus))
+ if (_header_bar.has_popover () || (((Window) widget).focus_visible && !_embed.is_focus))
return false;
if (_game.cannot_move ())
return false;
@@ -525,6 +412,15 @@ private class GameWindow : ApplicationWindow
});
}
+ internal static bool is_disallowed_grid_size (ref int rows, ref int cols)
+ requires (rows >= 1)
+ requires (rows <= 9)
+ requires (cols >= 1)
+ requires (cols <= 9)
+ {
+ return (rows == 1 && cols == 1) || (rows == 1 && cols == 2) || (rows == 2 && cols == 1);
+ }
+
/*\
* * gesture
\*/
diff --git a/src/meson.build b/src/meson.build
index 83d3302..d378c6b 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -8,6 +8,7 @@ gnome_2048_sources = [
'application.vala',
'config.vapi',
'game.vala',
+ 'game-headerbar.vala',
'game-window.vala',
'grid.vala',
'view.vala',
diff --git a/src/org.gnome.TwentyFortyEight.gresource.xml b/src/org.gnome.TwentyFortyEight.gresource.xml
index fbb336b..b2cf713 100644
--- a/src/org.gnome.TwentyFortyEight.gresource.xml
+++ b/src/org.gnome.TwentyFortyEight.gresource.xml
@@ -2,6 +2,7 @@
<gresources>
<gresource prefix="/org/gnome/TwentyFortyEight/ui">
<file preprocess="xml-stripblanks" alias="congrats.ui">../data/congrats.ui</file>
+ <file preprocess="xml-stripblanks" alias="game-headerbar.ui">../data/game-headerbar.ui</file>
<file preprocess="xml-stripblanks" alias="game-window.ui">../data/mainwindow.ui</file>
<!-- file>data/style.css</file -->
</gresource>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]