[gnome-tetravex] Introduce new theme.



commit f5f3e3ddbe0caecbc6998dbc23aa5dc4bf1f2228
Author: Arnaud B <arnaud bonatti gmail com>
Date:   Wed Oct 9 01:15:01 2019 +0000

    Introduce new theme.
    
    Welcome NeoRetro. The old theme
    is kept available as Nostalgia.
    
    Initial work on #3.

 data/org.gnome.Tetravex.gschema.xml      |   6 +
 po/POTFILES.in                           |   3 +-
 po/POTFILES.skip                         |   3 +-
 src/app-menu.ui                          |  18 ++
 src/gnome-tetravex.vala                  |  42 ++-
 src/meson.build                          |  41 +--
 src/puzzle-view.vala                     |  21 +-
 src/theme-neoretro.vala                  | 441 +++++++++++++++++++++++++++++++
 src/{theme.vala => theme-nostalgia.vala} | 179 +++++++------
 9 files changed, 630 insertions(+), 124 deletions(-)
---
diff --git a/data/org.gnome.Tetravex.gschema.xml b/data/org.gnome.Tetravex.gschema.xml
index b7138af..6d62baf 100644
--- a/data/org.gnome.Tetravex.gschema.xml
+++ b/data/org.gnome.Tetravex.gschema.xml
@@ -31,6 +31,12 @@
       <!-- Translators: description of a settings key, see 'dconf-editor 
/org/gnome/Tetravex/mouse-forward-buttons' -->
       <description>For users which have a mouse with “Forward” and “Back” buttons, this key will set which 
button activates the “Redo” command. Possible values range between 6 and 14.</description>
     </key>
+    <key name="theme" type="s">
+      <default>'neoretro'</default>
+      <!-- Translators: summary of a settings key, see 'dconf-editor /org/gnome/Tetravex/theme' -->
+      <summary>Theme</summary>
+      <!-- TODO add description, see Reversi -->
+    </key>
     <key name="window-width" type="i">
       <default>600</default>
       <!-- Translators: summary of a settings key, see 'dconf-editor /org/gnome/Tetravex/window-width' -->
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 634ef6a..21ac813 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -10,4 +10,5 @@ src/help-overlay.ui
 src/puzzle.vala
 src/puzzle-view.vala
 src/score-dialog.vala
-src/theme.vala
+src/theme-neoretro.vala
+src/theme-nostalgia.vala
diff --git a/po/POTFILES.skip b/po/POTFILES.skip
index 61008a4..98bc2e7 100644
--- a/po/POTFILES.skip
+++ b/po/POTFILES.skip
@@ -2,4 +2,5 @@ src/gnome-tetravex.c
 src/puzzle.c
 src/puzzle-view.c
 src/score-dialog.c
-src/theme.c
+src/theme-neoretro.c
+src/theme-nostalgia.c
diff --git a/src/app-menu.ui b/src/app-menu.ui
index 84f95e4..b96b4ef 100644
--- a/src/app-menu.ui
+++ b/src/app-menu.ui
@@ -11,6 +11,24 @@
         <attribute name="label" translatable="yes">_Scores</attribute>
         <attribute name="action">app.scores</attribute>
       </item>
+      <submenu>
+        <!-- Translators: entry of the hamburger menu (with a mnemonic that appears when pressing Alt); 
displays allows to change the theme -->
+        <attribute name="label" translatable="yes">A_ppearance</attribute>
+        <section>
+          <item>
+            <!-- Translators: entry of the Appearance submenu of the hamburger menu (with a mnemonic that 
appears when pressing Alt); set theme to NeoRetro; other possible theme is _Nostalgia -->
+            <attribute name="label" translatable="yes">Neo_Retro</attribute>
+            <attribute name="action">app.theme</attribute>
+            <attribute name="target">neoretro</attribute>
+          </item>
+          <item>
+            <!-- Translators: entry of the Appearance submenu of the hamburger menu (with a mnemonic that 
appears when pressing Alt); set theme to Nostalgia; other possible theme is Neo_Retro -->
+            <attribute name="label" translatable="yes">_Nostalgia</attribute>
+            <attribute name="action">app.theme</attribute>
+            <attribute name="target">nostalgia</attribute>
+          </item>
+        </section>
+      </submenu>
     </section>
     <section>
       <submenu>
diff --git a/src/gnome-tetravex.vala b/src/gnome-tetravex.vala
index fd4176a..1252879 100644
--- a/src/gnome-tetravex.vala
+++ b/src/gnome-tetravex.vala
@@ -60,21 +60,21 @@ private class Tetravex : Gtk.Application
 
     private const GLib.ActionEntry[] action_entries =
     {
-        { "new-game",       new_game_cb                                     },
-        { "pause",          pause_cb                                        },
-        { "solve",          solve_cb                                        },
-        { "finish",         finish_cb                                       },
-        { "scores",         scores_cb                                       },
-        { "quit",           quit                                            },
-        { "move-up",        move_up                                         },
-        { "move-down",      move_down                                       },
-        { "move-left",      move_left                                       },
-        { "move-right",     move_right                                      },
-        { "undo",           undo_cb                                         },
-        { "redo",           redo_cb                                         },
-        { "size",           radio_cb,       "s",    "'2'",  size_changed    },
-        { "help",           help_cb                                         },
-        { "about",          about_cb                                        }
+        { "new-game",   new_game_cb },
+        { "pause",      pause_cb    },
+        { "solve",      solve_cb    },
+        { "finish",     finish_cb   },
+        { "scores",     scores_cb   },
+        { "quit",       quit        },
+        { "move-up",    move_up     },
+        { "move-down",  move_down   },
+        { "move-left",  move_left   },
+        { "move-right", move_right  },
+        { "undo",       undo_cb     },
+        { "redo",       redo_cb     },
+        { "size",       null,       "s",    "'2'",  size_changed    },
+        { "help",       help_cb     },
+        { "about",      about_cb    }
     };
 
     private static int main (string[] args)
@@ -102,7 +102,11 @@ private class Tetravex : Gtk.Application
         Environment.set_application_name (PROGRAM_NAME);
         Window.set_default_icon_name ("org.gnome.Tetravex");
 
+        settings = new GLib.Settings ("org.gnome.Tetravex");
+
         add_action_entries (action_entries, this);
+        add_action (settings.create_action ("theme"));
+
         set_accels_for_action ("app.solve",         {        "<Primary>h"       });
         set_accels_for_action ("app.scores",        {        "<Primary>i"       });
         set_accels_for_action ("app.new-game",      {        "<Primary>n"       });
@@ -119,8 +123,6 @@ private class Tetravex : Gtk.Application
 
         Builder builder = new Builder.from_resource ("/org/gnome/Tetravex/gnome-tetravex.ui");
 
-        settings = new GLib.Settings ("org.gnome.Tetravex");
-
         history = new History (Path.build_filename (Environment.get_user_data_dir (), "gnome-tetravex", 
"history"));
 
         window = (ApplicationWindow) builder.get_object ("gnome-tetravex-window");
@@ -172,6 +174,7 @@ private class Tetravex : Gtk.Application
         view.hexpand = true;
         view.vexpand = true;
         view.button_release_event.connect (view_button_release_event);
+        settings.bind ("theme", view, "theme-id", SettingsBindFlags.GET | SettingsBindFlags.NO_SENSITIVITY);
         grid.attach (view, 0, 0, 3, 1);
 
         settings.bind ("mouse-use-extra-buttons",   view,
@@ -624,11 +627,6 @@ private class Tetravex : Gtk.Application
         play_pause_stack.set_visible_child_name (puzzle.paused ? "play" : "pause");
     }
 
-    private void radio_cb (SimpleAction action, Variant? parameter)
-    {
-        action.change_state (parameter);
-    }
-
     private bool on_key_press_event (Widget widget, Gdk.EventKey event)
     {
         string name = (!) (Gdk.keyval_name (event.keyval) ?? "");
diff --git a/src/meson.build b/src/meson.build
index 5aaf72b..e9cb467 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -2,20 +2,27 @@ resources = gnome.compile_resources ('resources', 'gnome-tetravex.gresource.xml'
                                      source_dir: '.',
                                      c_name: 'resources')
 
-gnome_tetravex = executable ('gnome-tetravex',
-                             [ 'config.vapi',
-                               'gnome-tetravex.vala',
-                               'history.vala',
-                               'puzzle.vala',
-                               'puzzle-view.vala',
-                               'score-dialog.vala',
-                               'theme.vala'] + resources,
-                             dependencies: [ glib_dep,
-                                             gtk_dep,
-                                             libm_dep ],
-                             vala_args: [ '--pkg=posix',
-                                          '--enable-experimental-non-null' ],
-                             c_args: [ '-DVERSION="@0@"'.format (meson.project_version ()),
-                                       '-DGETTEXT_PACKAGE="gnome-tetravex"',
-                                       '-DLOCALEDIR="@0@"'.format (localedir) ],
-                             install: true )
+sources = files (
+    'config.vapi',
+    'gnome-tetravex.vala',
+    'history.vala',
+    'puzzle.vala',
+    'puzzle-view.vala',
+    'score-dialog.vala',
+    'theme-neoretro.vala',
+    'theme-nostalgia.vala'
+)
+
+gnome_tetravex = executable (
+    'gnome-tetravex',
+     sources + resources,
+     dependencies: [ glib_dep,
+                     gtk_dep,
+                     libm_dep ],
+     vala_args: [ '--pkg=posix',
+                  '--enable-experimental-non-null' ],
+     c_args: [ '-DVERSION="@0@"'.format (meson.project_version ()),
+               '-DGETTEXT_PACKAGE="gnome-tetravex"',
+               '-DLOCALEDIR="@0@"'.format (localedir) ],
+     install: true
+ )
diff --git a/src/puzzle-view.vala b/src/puzzle-view.vala
index da187c3..7a52cf2 100644
--- a/src/puzzle-view.vala
+++ b/src/puzzle-view.vala
@@ -9,6 +9,15 @@
  * license.
  */
 
+private abstract class Theme : Object
+{
+    internal abstract void configure (uint size);
+    internal abstract void draw_arrow (Cairo.Context context);
+    internal abstract void draw_socket (Cairo.Context context);
+    internal abstract void draw_paused_tile (Cairo.Context context);
+    internal abstract void draw_tile (Cairo.Context context, Tile tile);
+}
+
 private class PuzzleView : Gtk.DrawingArea
 {
     private class TileImage : Object
@@ -89,7 +98,17 @@ private class PuzzleView : Gtk.DrawingArea
     }
 
     /* Theme */
-    private Theme theme = new Theme ();
+    private Theme theme;
+    [CCode (notify = true)] public string theme_id
+    {
+        internal set
+        {
+            if (value != "nostalgia") // including "value == neoretro"
+                { theme = new NeoRetroTheme ();  if (tilesize != 0) theme.configure (tilesize); queue_draw 
(); return; }
+            else
+                { theme = new NostalgiaTheme (); if (tilesize != 0) theme.configure (tilesize); queue_draw 
(); return; }
+        }
+    }
 
     /* Tile being controlled by the mouse */
     private TileImage? selected_tile = null;
diff --git a/src/theme-neoretro.vala b/src/theme-neoretro.vala
new file mode 100644
index 0000000..069cf22
--- /dev/null
+++ b/src/theme-neoretro.vala
@@ -0,0 +1,441 @@
+/* -*- Mode: vala; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * Copyright (C) 2019 Arnaud Bonatti
+ *
+ * This program 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 2 of the License, or (at your option) any later
+ * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
+ * license.
+ */
+
+private class NeoRetroTheme : Theme
+{
+    /*\
+    * * colors arrays
+    \*/
+
+    private Cairo.Pattern tile_colors_h [10];
+    private Cairo.Pattern tile_colors_v [10];
+
+    private unowned Cairo.Pattern text_colors [10];
+    private Cairo.Pattern black_text_color = new Cairo.Pattern.rgb (0.0, 0.0, 0.0);
+    private Cairo.Pattern white_text_color = new Cairo.Pattern.rgb (1.0, 1.0, 1.0);
+
+    private Cairo.Pattern paused_color_h;
+    private Cairo.Pattern paused_color_v;
+
+    construct                         // white text //  L    H    V
+    {                                               //          +45
+        make_color_pattern (0, "000000", true  );   //  0           // dark
+        make_color_pattern (1, "850023", true  );   // 20   75   10 // red
+        make_color_pattern (2, "e26e1e", false );   // 60   75   55 // orange
+        make_color_pattern (3, "cccc24", false );   // 80   75  100 // yellow
+        make_color_pattern (4, "00c656", false );   // 70   75  145 // light green
+        make_color_pattern (5, "005c59", true  );   // 30   75  190 // dark green
+        make_color_pattern (6, "008de0", false );   // 50   75  235 // light blue
+        make_color_pattern (7, "001d87", true  );   // 10   75  280 // dark blue
+        make_color_pattern (8, "a021a6", true  );   // 40   75  325 // purple
+        make_color_pattern (9, "e2e2e2", false );   // 90           // white
+
+        paused_color_h = make_h_color_pattern ("CCCCCC");
+        paused_color_v = make_v_color_pattern ("CCCCCC");
+    }
+
+    private void make_color_pattern (uint position, string color, bool white_text)
+    {
+        tile_colors_h [position] = make_h_color_pattern (color);
+        tile_colors_v [position] = make_v_color_pattern (color);
+
+        if (white_text)
+            text_colors [position] = white_text_color;
+        else
+            text_colors [position] = black_text_color;
+    }
+
+    private static Cairo.Pattern make_h_color_pattern (string color)
+    {
+        double r0 = (hex_value (color [0]) * 16 + hex_value (color [1])) / 255.0;
+        double g0 = (hex_value (color [2]) * 16 + hex_value (color [3])) / 255.0;
+        double b0 = (hex_value (color [4]) * 16 + hex_value (color [5])) / 255.0;
+
+        double r1 = double.min (r0 + 0.10, 1.0);
+        double g1 = double.min (g0 + 0.10, 1.0);
+        double b1 = double.min (b0 + 0.10, 1.0);
+
+        double r2 = double.min (r0 + 0.25, 1.0);
+        double g2 = double.min (g0 + 0.25, 1.0);
+        double b2 = double.min (b0 + 0.25, 1.0);
+
+        double r5 = double.min (r0 + 0.15, 1.0);
+        double g5 = double.min (g0 + 0.15, 1.0);
+        double b5 = double.min (b0 + 0.15, 1.0);
+
+        Cairo.Pattern pattern = new Cairo.Pattern.linear (0.0, 0.0, 0.0, 1.0);
+        pattern.add_color_stop_rgba (0.00,  r2,  g2,  b2, 1.0);
+        pattern.add_color_stop_rgba (0.08,  r1,  g1,  b1, 1.0);
+        pattern.add_color_stop_rgba (0.50,  r5,  g5,  b5, 1.0);
+        pattern.add_color_stop_rgba (0.92,  r1,  g1,  b1, 1.0);
+        pattern.add_color_stop_rgba (1.00,  r0,  g0,  b0, 1.0);
+
+        return pattern;
+    }
+
+    private static Cairo.Pattern make_v_color_pattern (string color)
+    {
+        double r0 = (hex_value (color [0]) * 16.0 + hex_value (color [1]) + 0.02) / 255.0;
+        double g0 = (hex_value (color [2]) * 16.0 + hex_value (color [3]) + 0.02) / 255.0;
+        double b0 = (hex_value (color [4]) * 16.0 + hex_value (color [5]) + 0.02) / 255.0;
+
+        double r1 = double.min (r0 + 0.10, 1.0);
+        double g1 = double.min (g0 + 0.10, 1.0);
+        double b1 = double.min (b0 + 0.10, 1.0);
+
+        double r2 = double.min (r0 + 0.20, 1.0);
+        double g2 = double.min (g0 + 0.20, 1.0);
+        double b2 = double.min (b0 + 0.20, 1.0);
+
+        double r5 = double.min (r0 + 0.15, 1.0);
+        double g5 = double.min (g0 + 0.15, 1.0);
+        double b5 = double.min (b0 + 0.15, 1.0);
+
+        Cairo.Pattern pattern = new Cairo.Pattern.linear (0.0, 0.0, 1.0, 0.0);
+        pattern.add_color_stop_rgba (0.00,  r2,  g2,  b2, 1.0);
+        pattern.add_color_stop_rgba (0.08,  r1,  g1,  b1, 1.0);
+        pattern.add_color_stop_rgba (0.50,  r5,  g5,  b5, 1.0);
+        pattern.add_color_stop_rgba (0.92,  r1,  g1,  b1, 1.0);
+        pattern.add_color_stop_rgba (1.00,  r0,  g0,  b0, 1.0);
+
+        return pattern;
+    }
+
+    private static double hex_value (char c)
+    {
+        if (c >= '0' && c <= '9')
+            return c - '0';
+        else if (c >= 'a' && c <= 'f')
+            return c - 'a' + 10;
+        else if (c >= 'A' && c <= 'F')
+            return c - 'A' + 10;
+        else
+            return 0.0;
+    }
+
+    /*\
+    * * configuring variables
+    \*/
+
+    private uint size = 0;
+
+    /* arrow */
+    private double arrow_half_h;
+    private double neg_arrow_half_h;
+    private double arrow_w;
+    private double arrow_x;
+
+    private double arrow_clip_x;
+    private double arrow_clip_y;
+    private double arrow_clip_w;
+    private double arrow_clip_h;
+
+    /* socket */
+    private uint socket_margin;
+    private int socket_size;
+    private Cairo.MeshPattern socket_pattern;
+    private Cairo.Matrix matrix;                // also used for tile
+
+    /* tile only */
+    private uint tile_margin;
+    private int tile_size;
+    private double half_tile_size;
+
+    /* numbers */
+    private double font_size;
+    private double north_number_y;
+    private double south_number_y;
+    private double  east_number_x;
+    private double  west_number_x;
+
+    internal override void configure (uint new_size)
+    {
+        if (size != 0 && size == new_size)
+            return;
+
+        /* arrow */
+        arrow_half_h = new_size * 0.5;
+        neg_arrow_half_h = -arrow_half_h;
+        arrow_w = new_size * PuzzleView.gap_factor * 0.5;
+        arrow_x = (new_size * PuzzleView.gap_factor - arrow_w) * 0.5;
+
+        arrow_clip_x = -arrow_x;
+        arrow_clip_y = -new_size;
+        arrow_clip_w = 2.0 * arrow_x + arrow_w;
+        arrow_clip_h = 2.0 * new_size;
+
+        /* socket and tile */
+        matrix = Cairo.Matrix.identity ();
+        matrix.scale (1.0 / new_size, 1.0 / new_size);
+
+        /* socket */
+        socket_margin = uint.min ((uint) (new_size * 0.05), 2);
+        socket_size = (int) new_size - (int) socket_margin * 2;
+
+        socket_pattern = new Cairo.MeshPattern ();
+        socket_pattern.begin_patch ();
+        socket_pattern.move_to (0.0, 0.0);
+        socket_pattern.line_to (1.0, 0.0);
+        socket_pattern.line_to (1.0, 1.0);
+        socket_pattern.line_to (0.0, 1.0);
+        socket_pattern.set_corner_color_rgba (0, 0.3, 0.3, 0.3, 0.3);
+        socket_pattern.set_corner_color_rgba (1, 0.4, 0.4, 0.4, 0.3);
+        socket_pattern.set_corner_color_rgba (2, 0.7, 0.7, 0.7, 0.3);
+        socket_pattern.set_corner_color_rgba (3, 0.6, 0.6, 0.6, 0.3);
+        socket_pattern.end_patch ();
+        socket_pattern.set_matrix (matrix);
+
+        /* tile */
+        tile_margin = uint.min ((uint) (new_size * 0.05), 2) - 1;
+        tile_size = (int) new_size - (int) tile_margin * 2;
+        half_tile_size = new_size * 0.5;
+
+        /* numbers */
+        font_size = new_size * 4.0 / 19.0;
+        north_number_y = new_size *  4.0 / 18.0;
+        south_number_y = new_size * 14.0 / 18.0;
+         east_number_x = new_size * 15.0 / 19.0;
+         west_number_x = new_size *  4.0 / 19.0;
+
+        /* end */
+        size = new_size;
+    }
+
+    /*\
+    * * drawing arrow
+    \*/
+
+    internal override void draw_arrow (Cairo.Context context)
+    {
+        context.translate (arrow_x, 0.0);
+
+        /*\
+         *  To ease the drawing, we base the arrow on a simple shape. We clip
+         *  the exterior of this shape, by clipping a large rectangle around,
+         *  and excluding the shape. Then we stroke the shape, only drawing a
+         *  border at its exterior; two times, the first a bit larger, making
+         *  a border. Then, we reset the exterior clip, we clip the shape for
+         *  real (its interior), and we fill it (two times) with same colors.
+        \*/
+
+        /* clipping exterior */
+
+        context.rectangle (arrow_clip_x, arrow_clip_y, arrow_clip_w, arrow_clip_h);
+
+        context.move_to (arrow_w, arrow_half_h);
+        context.line_to (0.0, 0.0);
+        context.line_to (arrow_w, neg_arrow_half_h);
+        context.curve_to (0.0,  10.0,               // Bézier control point for origin
+                          0.0, -10.0,               // Bézier control point for destination
+                          arrow_w, arrow_half_h);   // destination
+
+        context.clip ();
+
+        /* drawing exterior border */
+
+        context.move_to (arrow_w, arrow_half_h);
+        context.line_to (0.0, 0.0);
+        context.line_to (arrow_w, neg_arrow_half_h);
+        context.curve_to (0.0,  10.0,               // Bézier control point for origin
+                          0.0, -10.0,               // Bézier control point for destination
+                          arrow_w, arrow_half_h);   // destination
+
+        context.set_line_join (Cairo.LineJoin.ROUND);
+        context.set_line_cap (Cairo.LineCap.ROUND);
+
+        context.set_line_width (14.0);
+        context.set_source_rgba (0.4, 0.4, 0.4, 0.3);   // fill color 1, including border
+        context.stroke_preserve ();
+
+        context.set_line_width (12.0);
+        context.set_source_rgba (1.0, 1.0, 1.0, 0.1);   // fill color 2
+        context.stroke_preserve ();
+
+        /* filling interior */
+
+        context.reset_clip ();  // forget the border clip
+        context.clip ();       // clip to the current path
+
+        context.set_source_rgba (0.4, 0.4, 0.4, 0.3);   // fill color 1
+        context.fill_preserve ();
+
+        context.set_source_rgba (1.0, 1.0, 1.0, 0.1);   // fill color 2
+        context.fill ();
+    }
+
+    /*\
+    * * drawing sockets
+    \*/
+
+    internal override void draw_socket (Cairo.Context context)
+    {
+        context.save ();
+
+        context.set_source (socket_pattern);
+
+        rounded_square (context,
+          /* x and y */ socket_margin, socket_margin,
+          /* size    */ socket_size,
+          /* radius  */ 8);
+        context.fill_preserve ();
+
+        context.set_line_width (1.0);
+        context.set_source_rgba (0.4, 0.4, 0.4, 0.3);
+        context.stroke ();
+
+        context.restore ();
+    }
+
+    /*\
+    * * drawing tiles
+    \*/
+
+    internal override void draw_paused_tile (Cairo.Context context)
+    {
+        draw_tile_background (context, paused_color_h, paused_color_v, paused_color_h, paused_color_v);
+    }
+
+    internal override void draw_tile (Cairo.Context context, Tile tile)
+    {
+        tile_colors_h [tile.north].set_matrix (matrix);
+        tile_colors_h [tile.east ].set_matrix (matrix);
+        tile_colors_h [tile.south].set_matrix (matrix);
+        tile_colors_h [tile.west ].set_matrix (matrix);
+        tile_colors_v [tile.north].set_matrix (matrix);
+        tile_colors_v [tile.east ].set_matrix (matrix);
+        tile_colors_v [tile.south].set_matrix (matrix);
+        tile_colors_v [tile.west ].set_matrix (matrix);
+
+        draw_tile_background (context, tile_colors_h [tile.north], tile_colors_v [tile.east], tile_colors_h 
[tile.south], tile_colors_v [tile.west]);
+
+        context.select_font_face ("Sans", Cairo.FontSlant.NORMAL, Cairo.FontWeight.BOLD);
+        context.set_font_size (font_size);
+        draw_number (context, text_colors [tile.north], half_tile_size, north_number_y, tile.north);
+        draw_number (context, text_colors [tile.south], half_tile_size, south_number_y, tile.south);
+        draw_number (context, text_colors [tile.east ], east_number_x , half_tile_size, tile.east);
+        draw_number (context, text_colors [tile.west ], west_number_x , half_tile_size, tile.west);
+    }
+
+    private void draw_tile_background (Cairo.Context context, Cairo.Pattern north_color, Cairo.Pattern 
east_color, Cairo.Pattern south_color, Cairo.Pattern west_color)
+    {
+        context.save ();
+
+        /* Only write in a rounded square */
+        rounded_square (context,
+          /* x and y */ tile_margin, tile_margin,
+          /* size    */ tile_size,
+          /* radius  */ 8);
+        context.clip_preserve ();
+
+        /* North */
+        context.save ();
+
+        // fill all the clip, part of it will be rewritten after */
+
+        context.set_source (north_color);
+        context.fill ();
+
+        context.restore ();
+
+        /* South */
+        context.save ();
+
+        context.rectangle (0.0, half_tile_size, size, half_tile_size);
+
+        context.set_source (south_color);
+        context.fill ();
+
+        context.restore ();
+
+        /* East */
+        context.save ();
+
+        context.move_to (size, 0.0);
+        context.line_to (size, size);
+        context.line_to (half_tile_size, half_tile_size);
+        context.close_path ();
+
+        context.set_source (east_color);
+        context.fill ();
+
+        context.restore ();
+
+        /* West */
+        context.save ();
+
+        context.move_to (0.0, 0.0);
+        context.line_to (0.0, size);
+        context.line_to (half_tile_size, half_tile_size);
+        context.close_path ();
+
+        context.set_source (west_color);
+        context.fill ();
+
+        context.restore ();
+
+        /* Draw outline and diagonal lines */
+        context.reset_clip ();
+        context.set_line_width (1.5);
+        rounded_square (context,
+          /* x and y */ tile_margin, tile_margin,
+          /* size    */ tile_size,
+          /* radius  */ 8);
+
+        context.set_source_rgba (0.4, 0.4, 0.4, 0.4);
+        context.stroke_preserve ();
+        context.clip ();
+
+        context.move_to (0.0, 0.0);
+        context.line_to (size, size);
+        context.move_to (0.0, size);
+        context.line_to (size, 0.0);
+        context.stroke ();
+
+        context.restore ();
+    }
+
+    private static void draw_number (Cairo.Context context, Cairo.Pattern text_color, double x, double y, 
uint8 number)
+    {
+        context.set_source (text_color);
+
+        string text = "%hu".printf (number);
+        Cairo.TextExtents extents;
+        context.text_extents (text, out extents);
+        context.move_to (x - extents.width / 2.0, y + extents.height / 2.0);
+        context.show_text (text);
+    }
+
+    /*\
+    * * drawing utilities
+    \*/
+
+    private const double HALF_PI = Math.PI_2;
+    private static void rounded_square (Cairo.Context context, double x, double y, int size, double 
radius_percent)
+    {
+        if (radius_percent <= 0.0)
+            assert_not_reached ();  // could be replaced by drawing a rectangle, but not used here
+
+        if (radius_percent > 50.0)
+            radius_percent = 50.0;
+        double radius_arc = radius_percent * size / 100.0;
+        double x1 = x + radius_arc;
+        double y1 = y + radius_arc;
+        double x2 = x + size - radius_arc;
+        double y2 = y + size - radius_arc;
+
+        context.move_to (x, y1);
+        context.arc (x1, y1, radius_arc,  Math.PI, -HALF_PI);
+        context.arc (x2, y1, radius_arc, -HALF_PI,      0.0);
+        context.arc (x2, y2, radius_arc,      0.0,  HALF_PI);
+        context.arc (x1, y2, radius_arc,  HALF_PI,  Math.PI);
+        context.close_path ();
+    }
+}
diff --git a/src/theme.vala b/src/theme-nostalgia.vala
similarity index 65%
rename from src/theme.vala
rename to src/theme-nostalgia.vala
index 95a8784..9a16d39 100644
--- a/src/theme.vala
+++ b/src/theme-nostalgia.vala
@@ -9,7 +9,7 @@
  * license.
  */
 
-private class Theme : Object
+private class NostalgiaTheme : Theme
 {
     /*\
     * * colors arrays
@@ -17,40 +17,43 @@ private class Theme : Object
 
     private Cairo.Pattern tile_colors [10];
     private Cairo.Pattern paused_color;
-    private Cairo.Pattern text_colors [10];
+
+    private unowned Cairo.Pattern text_colors [10];
+    private Cairo.Pattern black_text_color = new Cairo.Pattern.rgb (0, 0, 0);
+    private Cairo.Pattern white_text_color = new Cairo.Pattern.rgb (1, 1, 1);
 
     construct
     {
-        tile_colors [0] = make_color_pattern ("#000000");
-        tile_colors [1] = make_color_pattern ("#C17D11");
-        tile_colors [2] = make_color_pattern ("#CC0000");
-        tile_colors [3] = make_color_pattern ("#F57900");
-        tile_colors [4] = make_color_pattern ("#EDD400");
-        tile_colors [5] = make_color_pattern ("#73D216");
-        tile_colors [6] = make_color_pattern ("#3465A4");
-        tile_colors [7] = make_color_pattern ("#75507B");
-        tile_colors [8] = make_color_pattern ("#BABDB6");
-        tile_colors [9] = make_color_pattern ("#FFFFFF");
-
-        paused_color = make_color_pattern ("#CCCCCC");
-
-        text_colors [0] = new Cairo.Pattern.rgb (1, 1, 1);
-        text_colors [1] = new Cairo.Pattern.rgb (1, 1, 1);
-        text_colors [2] = new Cairo.Pattern.rgb (1, 1, 1);
-        text_colors [3] = new Cairo.Pattern.rgb (1, 1, 1);
-        text_colors [4] = new Cairo.Pattern.rgb (0, 0, 0);
-        text_colors [5] = new Cairo.Pattern.rgb (0, 0, 0);
-        text_colors [6] = new Cairo.Pattern.rgb (1, 1, 1);
-        text_colors [7] = new Cairo.Pattern.rgb (1, 1, 1);
-        text_colors [8] = new Cairo.Pattern.rgb (0, 0, 0);
-        text_colors [9] = new Cairo.Pattern.rgb (0, 0, 0);
+        tile_colors [0] = make_color_pattern ("000000");
+        tile_colors [1] = make_color_pattern ("C17D11");
+        tile_colors [2] = make_color_pattern ("CC0000");
+        tile_colors [3] = make_color_pattern ("F57900");
+        tile_colors [4] = make_color_pattern ("EDD400");
+        tile_colors [5] = make_color_pattern ("73D216");
+        tile_colors [6] = make_color_pattern ("3465A4");
+        tile_colors [7] = make_color_pattern ("75507B");
+        tile_colors [8] = make_color_pattern ("BABDB6");
+        tile_colors [9] = make_color_pattern ("FFFFFF");
+
+        paused_color = make_color_pattern ("CCCCCC");
+
+        text_colors [0] = white_text_color;
+        text_colors [1] = white_text_color;
+        text_colors [2] = white_text_color;
+        text_colors [3] = white_text_color;
+        text_colors [4] = black_text_color;
+        text_colors [5] = black_text_color;
+        text_colors [6] = white_text_color;
+        text_colors [7] = white_text_color;
+        text_colors [8] = black_text_color;
+        text_colors [9] = black_text_color;
     }
 
     private static Cairo.Pattern make_color_pattern (string color)
     {
-        double r = (hex_value (color [1]) * 16 + hex_value (color [2])) / 255.0;
-        double g = (hex_value (color [3]) * 16 + hex_value (color [4])) / 255.0;
-        double b = (hex_value (color [5]) * 16 + hex_value (color [6])) / 255.0;
+        double r = (hex_value (color [0]) * 16.0 + hex_value (color [1])) / 255.0;
+        double g = (hex_value (color [2]) * 16.0 + hex_value (color [3])) / 255.0;
+        double b = (hex_value (color [4]) * 16.0 + hex_value (color [5])) / 255.0;
         return new Cairo.Pattern.rgb (r, g, b);
     }
 
@@ -63,7 +66,7 @@ private class Theme : Object
         else if (c >= 'A' && c <= 'F')
             return c - 'A' + 10;
         else
-            return 0;
+            return 0.0;
     }
 
     /*\
@@ -97,7 +100,14 @@ private class Theme : Object
     private double half_tile_size_plus_dy;
     private double size_minus_one;
 
-    internal void configure (uint new_size)
+    /* numbers */
+    private double font_size;
+    private double north_number_y;
+    private double south_number_y;
+    private double  east_number_x;
+    private double  west_number_x;
+
+    internal override void configure (uint new_size)
     {
         if (size != 0 && size == new_size)
             return;
@@ -127,6 +137,13 @@ private class Theme : Object
         half_tile_size_plus_dy = half_tile_size + tile_dy;
         size_minus_one = (double) (new_size - 1);
 
+        /* numbers */
+        font_size = new_size / 3.5;
+        north_number_y = new_size       / 5.0;
+        south_number_y = new_size * 4.0 / 5.0;
+         east_number_x = south_number_y;
+         west_number_x = north_number_y;
+
         /* end */
         size = new_size;
     }
@@ -135,16 +152,16 @@ private class Theme : Object
     * * drawing arrow
     \*/
 
-    internal void draw_arrow (Cairo.Context context)
+    internal override void draw_arrow (Cairo.Context context)
     {
         context.translate (arrow_x, 0.0);
 
         /* Background */
-        context.move_to (0, 0);
+        context.move_to (0.0, 0.0);
         context.line_to (arrow_w, arrow_half_h);
         context.line_to (arrow_w, neg_arrow_half_h);
         context.close_path ();
-        context.set_source_rgba (0, 0, 0, 0.125);
+        context.set_source_rgba (0.0, 0.0, 0.0, 0.125);
         context.fill ();
 
         /* Arrow highlight */
@@ -153,18 +170,18 @@ private class Theme : Object
         context.line_to (arrow_w_minus_depth, arrow_dy);
         context.line_to (arrow_w_minus_depth, neg_arrow_dy);
         context.close_path ();
-        context.set_source_rgba (1, 1, 1, 0.125);
+        context.set_source_rgba (1.0, 1.0, 1.0, 0.125);
         context.fill ();
 
         /* Arrow shadow */
         context.move_to (arrow_w, neg_arrow_half_h);
-        context.line_to (0, 0);
+        context.line_to (0.0, 0.0);
         context.line_to (arrow_w, arrow_half_h);
         context.line_to (arrow_w_minus_depth, arrow_dy);
-        context.line_to (arrow_dx, 0);
+        context.line_to (arrow_dx, 0.0);
         context.line_to (arrow_w_minus_depth, neg_arrow_dy);
         context.close_path ();
-        context.set_source_rgba (0, 0, 0, 0.25);
+        context.set_source_rgba (0.0, 0.0, 0.0, 0.25);
         context.fill ();
     }
 
@@ -172,33 +189,33 @@ private class Theme : Object
     * * drawing sockets
     \*/
 
-    internal void draw_socket (Cairo.Context context)
+    internal override void draw_socket (Cairo.Context context)
     {
         /* Background */
         context.rectangle (tile_depth, tile_depth, size_minus_two_tile_depths, size_minus_two_tile_depths);
-        context.set_source_rgba (0, 0, 0, 0.125);
+        context.set_source_rgba (0.0, 0.0, 0.0, 0.125);
         context.fill ();
 
         /* Shadow */
-        context.move_to (size, 0);
-        context.line_to (0, 0);
-        context.line_to (0, size);
+        context.move_to (size, 0.0);
+        context.line_to (0.0, 0.0);
+        context.line_to (0.0, size);
         context.line_to (tile_depth, size_minus_tile_depth);
         context.line_to (tile_depth, tile_depth);
         context.line_to (size_minus_tile_depth, tile_depth);
         context.close_path ();
-        context.set_source_rgba (0, 0, 0, 0.25);
+        context.set_source_rgba (0.0, 0.0, 0.0, 0.25);
         context.fill ();
 
         /* Highlight */
-        context.move_to (0, size);
+        context.move_to (0.0, size);
         context.line_to (size, size);
-        context.line_to (size, 0);
+        context.line_to (size, 0.0);
         context.line_to (size_minus_tile_depth, tile_depth);
         context.line_to (size_minus_tile_depth, size_minus_tile_depth);
         context.line_to (tile_depth, size_minus_tile_depth);
         context.close_path ();
-        context.set_source_rgba (1, 1, 1, 0.125);
+        context.set_source_rgba (1.0, 1.0, 1.0, 0.125);
         context.fill ();
     }
 
@@ -206,81 +223,77 @@ private class Theme : Object
     * * drawing tiles
     \*/
 
-    internal void draw_paused_tile (Cairo.Context context)
+    internal override void draw_paused_tile (Cairo.Context context)
     {
         draw_tile_background (context, paused_color, paused_color, paused_color, paused_color);
     }
 
-    internal void draw_tile (Cairo.Context context, Tile tile)
+    internal override void draw_tile (Cairo.Context context, Tile tile)
     {
         draw_tile_background (context, tile_colors [tile.north], tile_colors [tile.east], tile_colors 
[tile.south], tile_colors [tile.west]);
 
         context.select_font_face ("Sans", Cairo.FontSlant.NORMAL, Cairo.FontWeight.BOLD);
-        context.set_font_size (size / 3.5);
-        context.set_source (text_colors [tile.north]);
-        draw_number (context, half_tile_size, size / 5, tile.north);
-        context.set_source (text_colors [tile.south]);
-        draw_number (context, half_tile_size, size * 4 / 5, tile.south);
-        context.set_source (text_colors [tile.east]);
-        draw_number (context, size * 4 / 5, half_tile_size, tile.east);
-        context.set_source (text_colors [tile.west]);
-        draw_number (context, size / 5, half_tile_size, tile.west);
+        context.set_font_size (font_size);
+        draw_number (context, text_colors [tile.north], half_tile_size, north_number_y, tile.north);
+        draw_number (context, text_colors [tile.south], half_tile_size, south_number_y, tile.south);
+        draw_number (context, text_colors [tile.east ], east_number_x , half_tile_size, tile.east);
+        draw_number (context, text_colors [tile.west ], west_number_x , half_tile_size, tile.west);
     }
 
     private void draw_tile_background (Cairo.Context context, Cairo.Pattern north_color, Cairo.Pattern 
east_color, Cairo.Pattern south_color, Cairo.Pattern west_color)
     {
         /* North */
-        context.rectangle (0, 0, size, half_tile_size);
+        context.rectangle (0.0, 0.0, size, half_tile_size);
         context.set_source (north_color);
         context.fill ();
 
         /* North highlight */
-        context.move_to (0, 0);
-        context.line_to (size, 0);
+        context.move_to (0.0, 0.0);
+        context.line_to (size, 0.0);
         context.line_to (size_minus_tile_dx, tile_depth);
         context.line_to (tile_dx, tile_depth);
         context.line_to (half_tile_size, half_tile_size_minus_dy);
         context.line_to (half_tile_size, half_tile_size);
         context.close_path ();
-        context.set_source_rgba (1, 1, 1, 0.125);
+        context.set_source_rgba (1.0, 1.0, 1.0, 0.125);
         context.fill ();
 
         /* North shadow */
-        context.move_to (size, 0);
+        context.move_to (size, 0.0);
         context.line_to (half_tile_size, half_tile_size);
         context.line_to (half_tile_size, half_tile_size_minus_dy);
         context.line_to (size_minus_tile_dx, tile_depth);
         context.close_path ();
-        context.set_source_rgba (0, 0, 0, 0.25);
+        context.set_source_rgba (0.0, 0.0, 0.0, 0.25);
         context.fill ();
 
         /* South */
-        context.rectangle (0, half_tile_size, size, half_tile_size);
+        context.rectangle (0.0, half_tile_size, size, half_tile_size);
         context.set_source (south_color);
         context.fill ();
 
         /* South highlight */
-        context.move_to (0, size);
+        context.move_to (0.0, size);
         context.line_to (tile_dx, size_minus_tile_depth);
         context.line_to (half_tile_size, half_tile_size_plus_dy);
         context.line_to (half_tile_size, half_tile_size);
         context.close_path ();
-        context.set_source_rgba (1, 1, 1, 0.125);
+        context.set_source_rgba (1.0, 1.0, 1.0, 0.125);
         context.fill ();
 
         /* South shadow */
-        context.move_to (0, size);
+        context.move_to (0.0, size);
         context.line_to (size, size);
         context.line_to (half_tile_size, half_tile_size);
         context.line_to (half_tile_size, half_tile_size_plus_dy);
         context.line_to (size_minus_tile_dx, size_minus_tile_depth);
         context.line_to (tile_dx, size_minus_tile_depth);
         context.close_path ();
-        context.set_source_rgba (0, 0, 0, 0.25);
+        context.set_source_rgba (0.0, 0.0, 0.0, 0.25);
         context.fill ();
 
         /* East */
-        context.move_to (size, 0);
+        context.move_to (size, 0.0);
         context.line_to (size, size);
         context.line_to (half_tile_size, half_tile_size);
         context.close_path ();
@@ -288,51 +301,51 @@ private class Theme : Object
         context.fill ();
 
         /* East highlight */
-        context.move_to (size, 0);
+        context.move_to (size, 0.0);
         context.line_to (half_tile_size, half_tile_size);
         context.line_to (size, size);
         context.line_to (size_minus_tile_depth, size_minus_tile_dx);
         context.line_to (half_tile_size_plus_dy, half_tile_size);
         context.line_to (size_minus_tile_depth, tile_dx);
         context.close_path ();
-        context.set_source_rgba (1, 1, 1, 0.125);
+        context.set_source_rgba (1.0, 1.0, 1.0, 0.125);
         context.fill ();
 
         /* East shadow */
-        context.move_to (size, 0);
+        context.move_to (size, 0.0);
         context.line_to (size, size);
         context.line_to (size_minus_tile_depth, size_minus_tile_dx);
         context.line_to (size_minus_tile_depth, tile_dx);
         context.close_path ();
-        context.set_source_rgba (0, 0, 0, 0.25);
+        context.set_source_rgba (0.0, 0.0, 0.0, 0.25);
         context.fill ();
 
         /* West */
-        context.move_to (0, 0);
-        context.line_to (0, size);
+        context.move_to (0.0, 0.0);
+        context.line_to (0.0, size);
         context.line_to (half_tile_size, half_tile_size);
         context.close_path ();
         context.set_source (west_color);
         context.fill ();
 
         /* West highlight */
-        context.move_to (0, 0);
-        context.line_to (0, size);
+        context.move_to (0.0, 0.0);
+        context.line_to (0.0, size);
         context.line_to (tile_depth, size_minus_tile_dx);
         context.line_to (tile_depth, tile_dx);
         context.close_path ();
-        context.set_source_rgba (1, 1, 1, 0.125);
+        context.set_source_rgba (1.0, 1.0, 1.0, 0.125);
         context.fill ();
 
         /* West shadow */
-        context.move_to (0, 0);
+        context.move_to (0.0, 0.0);
         context.line_to (half_tile_size, half_tile_size);
-        context.line_to (0, size);
+        context.line_to (0.0, size);
         context.line_to (tile_depth, size_minus_tile_dx);
         context.line_to (half_tile_size_minus_dy, half_tile_size);
         context.line_to (tile_depth, tile_dx);
         context.close_path ();
-        context.set_source_rgba (0, 0, 0, 0.25);
+        context.set_source_rgba (0.0, 0.0, 0.0, 0.25);
         context.fill ();
 
         /* Draw outline */
@@ -342,8 +355,10 @@ private class Theme : Object
         context.stroke ();
     }
 
-    private void draw_number (Cairo.Context context, double x, double y, uint8 number)
+    private static void draw_number (Cairo.Context context, Cairo.Pattern text_color, double x, double y, 
uint8 number)
     {
+        context.set_source (text_color);
+
         string text = "%hu".printf (number);
         Cairo.TextExtents extents;
         context.text_extents (text, out extents);



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