[four-in-a-row] Introduce ThemeManager.



commit 239fc76be0a24f5335a7bf10db4ca20c7353ed3b
Author: Arnaud Bonatti <arnaud bonatti gmail com>
Date:   Wed Jan 8 17:48:35 2020 +0100

    Introduce ThemeManager.
    
    With a bit of cleaning
    also in Scorebox code.

 src/four-in-a-row.vala   |  35 +++---
 src/game-board-view.vala |  78 ++-----------
 src/scorebox.vala        |  81 ++++++--------
 src/theme.vala           | 283 ++++++++++++++++++++++++++++++-----------------
 4 files changed, 245 insertions(+), 232 deletions(-)
---
diff --git a/src/four-in-a-row.vala b/src/four-in-a-row.vala
index cdac0e9..32970e5 100644
--- a/src/four-in-a-row.vala
+++ b/src/four-in-a-row.vala
@@ -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));
         }
diff --git a/src/game-board-view.vala b/src/game-board-view.vala
index d234a52..3ef433a 100644
--- a/src/game-board-view.vala
+++ b/src/game-board-view.vala
@@ -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
     \*/
diff --git a/src/scorebox.vala b/src/scorebox.vala
index a34b627..f25a49c 100644
--- a/src/scorebox.vala
+++ b/src/scorebox.vala
@@ -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 ();
diff --git a/src/theme.vala b/src/theme.vala
index 2c29474..9fda5a5 100644
--- a/src/theme.vala
+++ b/src/theme.vala
@@ -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")
+        }
+    };
+}


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