Commit 239fc76b authored by Arnaud B.'s avatar Arnaud B.

Introduce ThemeManager.

With a bit of cleaning
also in Scorebox code.
parent fc0f0f6b
......@@ -87,7 +87,8 @@ private class FourInARow : Gtk.Application
[CCode (notify = false)] internal int keypress_right { private get; internal set; }
[CCode (notify = false)] internal int keypress_left { private get; internal set; }
[CCode (notify = false)] internal bool sound_on { private get; internal set; }
private uint8 theme_id;
private ThemeManager theme_manager;
private static string? level = null;
private static int size = 7;
......@@ -223,24 +224,27 @@ private class FourInARow : Gtk.Application
if (settings.get_boolean ("sound"))
init_sound ();
settings.bind ("key-drop", this, "keypress-drop", SettingsBindFlags.GET | SettingsBindFlags.NO_SENSITIVITY);
settings.bind ("key-right", this, "keypress-right", SettingsBindFlags.GET | SettingsBindFlags.NO_SENSITIVITY);
settings.bind ("key-left", this, "keypress-left", SettingsBindFlags.GET | SettingsBindFlags.NO_SENSITIVITY);
settings.bind ("sound", this, "sound-on", SettingsBindFlags.GET | SettingsBindFlags.NO_SENSITIVITY);
settings.bind ("key-drop", this, "keypress-drop", SettingsBindFlags.GET | SettingsBindFlags.NO_SENSITIVITY);
settings.bind ("key-right", this, "keypress-right", SettingsBindFlags.GET | SettingsBindFlags.NO_SENSITIVITY);
settings.bind ("key-left", this, "keypress-left", SettingsBindFlags.GET | SettingsBindFlags.NO_SENSITIVITY);
settings.bind ("sound", this, "sound-on", SettingsBindFlags.GET | SettingsBindFlags.NO_SENSITIVITY);
theme_manager = new ThemeManager ((uint8) size);
settings.bind ("theme-id", theme_manager, "theme-id", SettingsBindFlags.GET | SettingsBindFlags.NO_SENSITIVITY);
/* UI parts */
new_game_screen = new NewGameScreen ();
new_game_screen.show ();
game_board_view = new GameBoardView (game_board, settings.get_int ("theme-id"));
settings.bind ("theme-id", game_board_view, "theme-id", SettingsBindFlags.GET | SettingsBindFlags.NO_SENSITIVITY);
game_board_view = new GameBoardView (game_board, theme_manager);
game_board_view.show ();
GLib.Menu app_menu = new GLib.Menu ();
GLib.Menu appearance_menu = new GLib.Menu ();
for (uint8 i = 0; i < theme.length; i++) // TODO default theme
appearance_menu.append (theme_get_title (i), @"app.theme-id($i)");
string [] themes = theme_manager.get_themes ();
for (uint8 i = 0; i < themes.length; i++) // TODO default theme
appearance_menu.append (themes [i], @"app.theme-id($i)");
appearance_menu.freeze ();
GLib.Menu section = new GLib.Menu ();
......@@ -284,14 +288,11 @@ private class FourInARow : Gtk.Application
history_button_1,
history_button_2);
scorebox = new Scorebox (window, this);
settings.bind ("theme-id", scorebox, "theme-id", SettingsBindFlags.GET | SettingsBindFlags.NO_SENSITIVITY);
scorebox = new Scorebox (window, this, theme_manager);
settings.changed ["theme-id"].connect (() => {
scorebox.update (score, one_player_game);
theme_id = (uint8) settings.get_int ("theme-id");
prompt_player ();
});
theme_id = (uint8) settings.get_int ("theme-id");
add_actions ();
......@@ -580,11 +581,11 @@ private class FourInARow : Gtk.Application
{
string who;
if (gameover)
who = player == HUMAN ? theme_get_player_win (Player.HUMAN, theme_id)
: theme_get_player_win (Player.OPPONENT, theme_id);
who = player == HUMAN ? theme_manager.get_player_win (Player.HUMAN)
: theme_manager.get_player_win (Player.OPPONENT);
else
who = player == HUMAN ? theme_get_player_turn (Player.HUMAN, theme_id)
: theme_get_player_turn (Player.OPPONENT, theme_id);
who = player == HUMAN ? theme_manager.get_player_turn (Player.HUMAN)
: theme_manager.get_player_turn (Player.OPPONENT);
set_status_message (_(who));
}
......
......@@ -29,22 +29,12 @@ private class GameBoardView : Gtk.DrawingArea
PLAYER2_CURSOR;
}
[CCode (notify = false)] public Board game_board { private get; protected construct; }
[CCode (notify = false)] public Board game_board { private get; protected construct; }
[CCode (notify = false)] public ThemeManager theme_manager { private get; protected construct; }
private int _theme_id = 0;
[CCode (notify = false)] public int theme_id
internal GameBoardView (Board game_board, ThemeManager theme_manager)
{
private get { return _theme_id; }
internal construct set
{
_theme_id = value;
change_theme ();
}
}
internal GameBoardView (Board game_board, int theme_id)
{
Object (game_board: game_board, theme_id: theme_id);
Object (game_board: game_board, theme_manager: theme_manager);
}
construct
......@@ -52,7 +42,7 @@ private class GameBoardView : Gtk.DrawingArea
events = Gdk.EventMask.EXPOSURE_MASK
| Gdk.EventMask.BUTTON_PRESS_MASK
| Gdk.EventMask.BUTTON_RELEASE_MASK;
load_pixmaps ();
theme_manager.theme_changed.connect (refresh_pixmaps);
}
/*\
......@@ -160,7 +150,7 @@ private class GameBoardView : Gtk.DrawingArea
const double dashes [] = { 4.0, 4.0 };
Gdk.RGBA color = Gdk.RGBA ();
color.parse (theme [theme_id].grid_color);
color.parse (theme_manager.get_grid_color ());
Gdk.cairo_set_source_rgba (cr, color);
cr.set_operator (Cairo.Operator.SOURCE);
cr.set_line_width (1.0);
......@@ -193,20 +183,10 @@ private class GameBoardView : Gtk.DrawingArea
* * pixmaps
\*/
/* unscaled pixbufs */
private Gdk.Pixbuf pb_tileset_raw;
private Gdk.Pixbuf pb_bground_raw;
/* scaled pixbufs */
private Gdk.Pixbuf pb_tileset;
private Gdk.Pixbuf pb_bground;
private inline void change_theme ()
{
load_pixmaps ();
refresh_pixmaps ();
}
private void refresh_pixmaps ()
{
if (tile_size == 0) // happens at game start
......@@ -214,12 +194,12 @@ private class GameBoardView : Gtk.DrawingArea
Gdk.Pixbuf? tmp_pixbuf;
tmp_pixbuf = pb_tileset_raw.scale_simple (tile_size * 6, tile_size, Gdk.InterpType.BILINEAR);
tmp_pixbuf = theme_manager.pb_tileset_raw.scale_simple (tile_size * 6, tile_size, Gdk.InterpType.BILINEAR);
if (tmp_pixbuf == null)
assert_not_reached ();
pb_tileset = (!) tmp_pixbuf;
tmp_pixbuf = pb_bground_raw.scale_simple (board_size, board_size, Gdk.InterpType.BILINEAR);
tmp_pixbuf = theme_manager.pb_bground_raw.scale_simple (board_size, board_size, Gdk.InterpType.BILINEAR);
if (tmp_pixbuf == null)
assert_not_reached ();
pb_bground = (!) tmp_pixbuf;
......@@ -227,48 +207,6 @@ private class GameBoardView : Gtk.DrawingArea
queue_draw ();
}
private void load_pixmaps ()
{
load_image (theme [theme_id].fname_tileset, out pb_tileset_raw);
if (theme [theme_id].fname_bground != null)
load_image ((!) theme [theme_id].fname_bground, out pb_bground_raw);
else
create_background ();
}
private static void load_image (string image_name, out Gdk.Pixbuf pixbuf)
{
string image_resource = "/org/gnome/Four-in-a-row/images/" + image_name;
try
{
pixbuf = new Gdk.Pixbuf.from_resource (image_resource);
}
catch (Error e)
{
critical (e.message);
assert_not_reached ();
}
}
private inline void create_background ()
{
int raw_tile_size = pb_tileset_raw.get_height ();
pb_bground_raw = new Gdk.Pixbuf (Gdk.Colorspace.RGB, /* alpha */ true, /* bits per sample */ 8, raw_tile_size * /* BOARD_COLUMNS */ game_board.size, raw_tile_size * /* BOARD_ROWS_PLUS_ONE */ game_board.size);
for (int i = 0; i < /* BOARD_COLUMNS */ game_board.size; i++)
{
pb_tileset_raw.copy_area (raw_tile_size * 3, 0,
raw_tile_size, raw_tile_size,
pb_bground_raw,
i * raw_tile_size, 0);
for (int j = 1; j < /* BOARD_ROWS_PLUS_ONE */ game_board.size; j++)
pb_tileset_raw.copy_area (raw_tile_size * 2, 0,
raw_tile_size, raw_tile_size,
pb_bground_raw,
i * raw_tile_size, j * raw_tile_size);
}
}
/*\
* * mouse play
\*/
......
......@@ -22,7 +22,7 @@ using Gtk;
private class Scorebox : Dialog
{
[CCode (notify = false)] internal int theme_id { private get; internal set; }
[CCode (notify = false)] public ThemeManager theme_manager { private get; protected construct; }
private Label label_name_top;
private Label label_score_top;
......@@ -31,65 +31,54 @@ private class Scorebox : Dialog
// no change to the draw name line
private Label label_score_end;
internal Scorebox(Window parent, FourInARow application)
internal Scorebox (Window parent, FourInARow application, ThemeManager theme_manager)
{
/* Translators: title of the Scores dialog; plural noun */
Object (title: _("Scores"),
use_header_bar: 1,
use_header_bar: /* true */ 1,
destroy_with_parent: true,
resizable: false,
border_width: 5,
application: application);
get_content_area ().spacing = 2;
set_transient_for (parent);
modal = true;
Grid grid, grid2;
application: application,
transient_for: parent,
modal: true,
theme_manager: theme_manager);
}
grid = new Grid ();
construct
{
Grid grid = new Grid ();
grid.halign = Align.CENTER;
grid.row_spacing = 6;
grid.orientation = Orientation.VERTICAL;
grid.border_width = 5;
get_content_area ().pack_start (grid);
grid2 = new Grid ();
grid.add (grid2);
grid2.column_spacing = 6;
grid.row_spacing = 2;
grid.column_spacing = 6;
grid.border_width = 10;
label_name_top = new Label (null);
grid2.attach (label_name_top, 0, 0, 1, 1);
label_name_top.set_xalign (0);
label_name_top.set_yalign (0.5f);
grid.attach (label_name_top, 0, 0, 1, 1);
label_name_top.halign = Align.START;
label_score_top = new Label (null);
grid2.attach (label_score_top, 1, 0, 1, 1);
label_score_top.set_xalign (0);
label_score_top.set_yalign (0.5f);
grid.attach (label_score_top, 1, 0, 1, 1);
label_score_top.halign = Align.END;
label_name_mid = new Label (null);
grid2.attach (label_name_mid, 0, 1, 1, 1);
label_name_mid.set_xalign (0);
label_name_mid.set_yalign (0.5f);
grid.attach (label_name_mid, 0, 1, 1, 1);
label_name_mid.halign = Align.START;
label_score_mid = new Label (null);
grid2.attach (label_score_mid, 1, 1, 1, 1);
label_score_mid.set_xalign (0);
label_score_mid.set_yalign (0.5f);
grid.attach (label_score_mid, 1, 1, 1, 1);
label_score_mid.halign = Align.END;
/* Translators: in the Scores dialog, label of the line where is indicated the number of tie games */
Label label_name_end = new Label (_("Drawn:"));
grid2.attach (label_name_end, 0, 2, 1, 1);
label_name_end.set_xalign (0);
label_name_end.set_yalign (0.5f);
grid.attach (label_name_end, 0, 2, 1, 1);
label_name_end.halign = Align.START;
label_score_end = new Label (null);
grid2.attach (label_score_end, 1, 2, 1, 1);
label_score_end.set_xalign (0);
label_score_end.set_yalign (0.5f);
grid.attach (label_score_end, 1, 2, 1, 1);
label_score_end.halign = Align.END;
grid.show_all ();
get_content_area ().pack_start (grid);
}
/**
......@@ -109,7 +98,7 @@ private class Scorebox : Dialog
/* Translators: in the Scores dialog, label of the line where is indicated the number of games won by the computer player */
label_name_mid.set_text (_("Me:"));
label_score_top.label = scores [Player.HUMAN].to_string ();
label_score_top.label = scores [Player.HUMAN ].to_string ();
label_score_mid.label = scores [Player.OPPONENT].to_string ();
}
else
......@@ -121,26 +110,26 @@ private class Scorebox : Dialog
label_name_mid.set_text (_("You:"));
label_score_top.label = scores [Player.OPPONENT].to_string ();
label_score_mid.label = scores [Player.HUMAN].to_string ();
label_score_mid.label = scores [Player.HUMAN ].to_string ();
}
}
else
{
if (scores [Player.HUMAN] >= scores [Player.OPPONENT])
{
label_name_top.label = theme_get_player (Player.HUMAN, (uint8) theme_id, /* with colon */ true);
label_name_mid.label = theme_get_player (Player.OPPONENT, (uint8) theme_id, /* with colon */ true);
label_name_top.label = theme_manager.get_player (Player.HUMAN, /* with colon */ true);
label_name_mid.label = theme_manager.get_player (Player.OPPONENT, /* with colon */ true);
label_score_top.label = scores [Player.HUMAN].to_string ();
label_score_top.label = scores [Player.HUMAN ].to_string ();
label_score_mid.label = scores [Player.OPPONENT].to_string ();
}
else
{
label_name_top.label = theme_get_player (Player.OPPONENT, (uint8) theme_id, /* with colon */ true);
label_name_mid.label = theme_get_player (Player.HUMAN, (uint8) theme_id, /* with colon */ true);
label_name_top.label = theme_manager.get_player (Player.OPPONENT, /* with colon */ true);
label_name_mid.label = theme_manager.get_player (Player.HUMAN, /* with colon */ true);
label_score_top.label = scores [Player.OPPONENT].to_string ();
label_score_mid.label = scores [Player.HUMAN].to_string ();
label_score_mid.label = scores [Player.HUMAN ].to_string ();
}
}
label_score_end.label = scores [Player.NOBODY].to_string ();
......
......@@ -18,122 +18,207 @@
with GNOME Four-in-a-row. If not, see <https://www.gnu.org/licenses/>.
*/
private struct Theme
private class ThemeManager : Object
{
public string title;
public string fname_tileset;
public string? fname_bground;
public string grid_color;
public string player1;
public string player2;
public string player1_with_colon;
public string player2_with_colon;
public string player1_win;
public string player2_win;
public string player1_turn;
public string player2_turn;
}
internal signal void theme_changed ();
private bool theme_set = false;
private int _theme_id;
[CCode (notify = false)] public int theme_id
{
private get { if (!theme_set) assert_not_reached (); return _theme_id; }
internal set { _theme_id = value; theme_set = true; load_pixmaps (); theme_changed (); }
}
/*
* Needed to force vala to include headers in the correct order.
* See https://gitlab.gnome.org/GNOME/vala/issues/98
* Cannot reproduce 08/2019, but the bug is not closed (2/2).
*/
private const string theme_gettext_package = GETTEXT_PACKAGE;
[CCode (notify = false)] public uint8 board_size { private get; internal construct; }
private static string theme_get_title (uint8 id)
{
return _(theme [id].title); // FIXME this gettext call feels horrible 1/5
}
internal ThemeManager (uint8 size)
{
Object (board_size: size);
}
private static string theme_get_player_turn (Player who, uint8 theme_id)
{
if (who == Player.HUMAN)
return theme [theme_id].player1_turn;
else
return theme [theme_id].player2_turn;
}
/*\
* * getting theme strings
\*/
private static string theme_get_player_win (Player who, uint8 theme_id)
{
if (who == Player.HUMAN)
return theme [theme_id].player1_win;
else
return theme [theme_id].player2_win;
}
private static string theme_get_player (Player who, uint8 theme_id, bool with_colon)
{
if (with_colon)
internal string get_player_turn (Player who)
{
if (who == Player.HUMAN)
return _(theme [theme_id].player1_with_colon); // FIXME this gettext call feels horrible 2/5
return theme [theme_id].player1_turn;
else
return _(theme [theme_id].player2_with_colon); // FIXME this gettext call feels horrible 3/5
return theme [theme_id].player2_turn;
}
else
internal string get_player_win (Player who)
{
if (who == Player.HUMAN)
return _(theme [theme_id].player1); // FIXME this gettext call feels horrible 4/5
return theme [theme_id].player1_win;
else
return _(theme [theme_id].player2); // FIXME this gettext call feels horrible 5/5
return theme [theme_id].player2_win;
}
}
private const Theme theme [] = {
internal string get_player (Player who, bool with_colon)
{
if (with_colon)
{
if (who == Player.HUMAN)
return _(theme [theme_id].player1_with_colon); // FIXME this gettext call feels horrible 2/5
else
return _(theme [theme_id].player2_with_colon); // FIXME this gettext call feels horrible 3/5
}
else
{
if (who == Player.HUMAN)
return _(theme [theme_id].player1); // FIXME this gettext call feels horrible 4/5
else
return _(theme [theme_id].player2); // FIXME this gettext call feels horrible 5/5
}
}
internal string get_grid_color ()
{
return theme [theme_id].grid_color;
}
/*\
* * loading or creating pixmaps
\*/
private bool pixmaps_loaded = false;
[CCode (notify = false)] internal Gdk.Pixbuf pb_tileset_raw { internal get { if (!pixmaps_loaded) assert_not_reached (); return _pb_tileset_raw; }}
[CCode (notify = false)] internal Gdk.Pixbuf pb_bground_raw { internal get { if (!pixmaps_loaded) assert_not_reached (); return _pb_bground_raw; }}
private Gdk.Pixbuf _pb_tileset_raw;
private Gdk.Pixbuf _pb_bground_raw;
private void load_pixmaps ()
{
/* Translators: name of a black-on-white theme, for helping people with visual misabilities */
N_("High Contrast"),
"tileset_50x50_hcontrast.svg",
null,
"#000000",
N_("Circle"), N_("Cross"),
N_("Circle:"), N_("Cross:"),
N_("Circle wins!"), N_("Cross wins!"),
N_("Circle’s turn"), N_("Cross’s turn")
},
load_image (theme [theme_id].fname_tileset, out _pb_tileset_raw);
if (theme [theme_id].fname_bground != null)
load_image ((!) theme [theme_id].fname_bground, out _pb_bground_raw);
else
create_background ();
pixmaps_loaded = true;
}
private static void load_image (string image_name, out Gdk.Pixbuf pixbuf)
{
/* Translators: name of a white-on-black theme, for helping people with visual misabilities */
N_("High Contrast Inverse"),
"tileset_50x50_hcinverse.svg",
null,
"#FFFFFF",
N_("Circle"), N_("Cross"),
N_("Circle:"), N_("Cross:"),
N_("Circle wins!"), N_("Cross wins!"),
N_("Circle’s turn"), N_("Cross’s turn")
},
string image_resource = "/org/gnome/Four-in-a-row/images/" + image_name;
try
{
pixbuf = new Gdk.Pixbuf.from_resource (image_resource);
}
catch (Error e)
{
critical (e.message);
assert_not_reached ();
}
}
private inline void create_background ()
{
/* Translators: name of a red-versus-green theme */
N_("Red and Green Marbles"),
"tileset_50x50_faenza-glines-icon1.svg",
"bg_toplight.png",
"#727F8C",
N_("Red"), N_("Green"),
N_("Red:"), N_("Green:"),
N_("Red wins!"), N_("Green wins!"),
N_("Red’s turn"), N_("Green’s turn")
},
int raw_tile_size = _pb_tileset_raw.get_height ();
_pb_bground_raw = new Gdk.Pixbuf (Gdk.Colorspace.RGB, /* alpha */ true, /* bits per sample */ 8, raw_tile_size * /* BOARD_COLUMNS */ board_size, raw_tile_size * /* BOARD_ROWS_PLUS_ONE */ board_size);
for (int i = 0; i < /* BOARD_COLUMNS */ board_size; i++)
{
_pb_tileset_raw.copy_area (raw_tile_size * 3, 0,
raw_tile_size, raw_tile_size,
_pb_bground_raw,
i * raw_tile_size, 0);
for (int j = 1; j < /* BOARD_ROWS_PLUS_ONE */ board_size; j++)
_pb_tileset_raw.copy_area (raw_tile_size * 2, 0,
raw_tile_size, raw_tile_size,
_pb_bground_raw,
i * raw_tile_size, j * raw_tile_size);
}
}
/*\
* * themes
\*/
internal string [] get_themes ()
{
/* Translators: name of a blue-versus-red theme */
N_("Blue and Red Marbles"),
"tileset_50x50_faenza-glines-icon2.svg",
"bg_toplight.png",
"#727F8C",
N_("Blue"), N_("Red"),
N_("Blue:"), N_("Red:"),
N_("Blue wins!"), N_("Red wins!"),
N_("Blue’s turn"), N_("Red’s turn")
},
string [] themes = {};
for (uint8 i = 0; i < theme.length; i++)
themes += _(theme [i].title); // FIXME this gettext call feels horrible 1/5
return themes;
}
private struct Theme
{
/* Translators: name of a red-versus-green theme with drawing on the tiles */
N_("Stars and Rings"),
"tileset_50x50_faenza-gnect-icon.svg",
"bg_toplight.png",
"#727F8C",
N_("Red"), N_("Green"),
N_("Red:"), N_("Green:"),
N_("Red wins!"), N_("Green wins!"),
N_("Red’s turn"), N_("Green’s turn")
public string title;
public string fname_tileset;
public string? fname_bground;
public string grid_color;
public string player1;
public string player2;
public string player1_with_colon;
public string player2_with_colon;
public string player1_win;
public string player2_win;
public string player1_turn;
public string player2_turn;
}
};
private const Theme theme [] = {
{
/* Translators: name of a black-on-white theme, for helping people with visual misabilities */
N_("High Contrast"),
"tileset_50x50_hcontrast.svg",
null,
"#000000",
N_("Circle"), N_("Cross"),
N_("Circle:"), N_("Cross:"),
N_("Circle wins!"), N_("Cross wins!"),
N_("Circle’s turn"), N_("Cross’s turn")
},
{
/* Translators: name of a white-on-black theme, for helping people with visual misabilities */
N_("High Contrast Inverse"),
"tileset_50x50_hcinverse.svg",
null,
"#FFFFFF",
N_("Circle"), N_("Cross"),
N_("Circle:"), N_("Cross:"),
N_("Circle wins!"), N_("Cross wins!"),
N_("Circle’s turn"), N_("Cross’s turn")
},
{
/* Translators: name of a red-versus-green theme */
N_("Red and Green Marbles"),
"tileset_50x50_faenza-glines-icon1.svg",
"bg_toplight.png",
"#727F8C",
N_("Red"), N_("Green"),
N_("Red:"), N_("Green:"),
N_("Red wins!"), N_("Green wins!"),
N_("Red’s turn"), N_("Green’s turn")
},
{
/* Translators: name of a blue-versus-red theme */
N_("Blue and Red Marbles"),
"tileset_50x50_faenza-glines-icon2.svg",
"bg_toplight.png",
"#727F8C",
N_("Blue"), N_("Red"),
N_("Blue:"), N_("Red:"),
N_("Blue wins!"), N_("Red wins!"),
N_("Blue’s turn"), N_("Red’s turn")
},
{
/* Translators: name of a red-versus-green theme with drawing on the tiles */
N_("Stars and Rings"),
"tileset_50x50_faenza-gnect-icon.svg",
"bg_toplight.png",
"#727F8C",
N_("Red"), N_("Green"),
N_("Red:"), N_("Green:"),
N_("Red wins!"), N_("Green wins!"),
N_("Red’s turn"), N_("Green’s turn")
}
};
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment