[four-in-a-row] HistoryButton DrawingArea.



commit d045a3852d6c6cacb2097ca104a522f547895905
Author: Arnaud Bonatti <arnaud bonatti gmail com>
Date:   Thu Jan 9 23:09:38 2020 +0100

    HistoryButton DrawingArea.

 data/ui/history-button.ui |  22 ++++++++
 src/four-in-a-row.vala    |  54 +++++++++++++------
 src/history-button.vala   | 133 ++++++++++++++++++++++++++++++++++++++++++++--
 3 files changed, 188 insertions(+), 21 deletions(-)
---
diff --git a/data/ui/history-button.ui b/data/ui/history-button.ui
index d63632d..8a53ae0 100644
--- a/data/ui/history-button.ui
+++ b/data/ui/history-button.ui
@@ -24,5 +24,27 @@
     <property name="valign">center</property>
     <property name="can-focus">True</property>
     <property name="focus-on-click">False</property>
+    <property name="width-request">56</property>
+    <child>
+      <object class="GtkStack" id="stack">
+        <property name="visible">True</property>
+        <property name="visible-child">drawing</property>
+        <child>
+          <object class="GtkDrawingArea" id="drawing">
+            <property name="visible">True</property>
+          </object>
+        </child>
+        <child>
+          <object class="GtkLabel">
+            <property name="visible">True</property>
+            <!-- Translators: label of the game status button (in the headerbar, next to the hamburger 
button); please keep the string as small as possible (3~5 characters) -->
+            <property name="label" translatable="yes">End!</property>
+          </object>
+          <packing>
+            <property name="name">label</property>
+          </packing>
+        </child>
+      </object>
+    </child>
   </template>
 </interface>
diff --git a/src/four-in-a-row.vala b/src/four-in-a-row.vala
index c3b6d1b..d6e8e8f 100644
--- a/src/four-in-a-row.vala
+++ b/src/four-in-a-row.vala
@@ -56,8 +56,8 @@ private class FourInARow : Gtk.Application
     private GameBoardView game_board_view;
     private GameWindow window;
     private NewGameScreen new_game_screen;
-    private MenuButton history_button_1;
-    private MenuButton history_button_2;
+    private HistoryButton history_button_1;
+    private HistoryButton history_button_2;
 
     // game state
     private string vstr;
@@ -268,8 +268,8 @@ private class FourInARow : Gtk.Application
         app_menu.freeze ();
 
         generate_game_menu ();
-        history_button_1 = new HistoryButton (ref game_menu, /* direction: down */ false);
-        history_button_2 = new HistoryButton (ref game_menu, /* direction: up  */  true);
+        history_button_1 = new HistoryButton (ref game_menu, theme_manager);
+        history_button_2 = new HistoryButton (ref game_menu, theme_manager);
 
         /* Window */
         window = new GameWindow ("/org/gnome/Four-in-a-row/ui/four-in-a-row.css",
@@ -279,8 +279,8 @@ private class FourInARow : Gtk.Application
                                  (Box) new_game_screen,
                                  game_board_view,
                                  app_menu,
-                                 history_button_1,
-                                 history_button_2);
+                                 (MenuButton) history_button_1,
+                                 (MenuButton) history_button_2);
 
         scorebox = new Scorebox (window, this, theme_manager);
 
@@ -544,39 +544,59 @@ private class FourInARow : Gtk.Application
             else
                 /* Translators: text displayed on game end in the headerbar/actionbar, if the game is a tie 
*/
                 set_status_message (_("It’s a draw!"));
+            history_button_1.set_player (Player.NOBODY);
+            history_button_2.set_player (Player.NOBODY);
             return;
         }
 
         if (one_player_game)
         {
-            if (human)
+            if (gameover)
             {
-                if (gameover)
+                history_button_1.set_player (Player.NOBODY);
+                history_button_2.set_player (Player.NOBODY);
+                if (human)
                     /* Translators: text displayed on a one-player game end in the headerbar/actionbar, if 
the human player won */
                     set_status_message (_("You win!"));
                 else
-                    /* Translators: text displayed during a one-player game in the headerbar/actionbar, if 
it is the human player's turn */
-                    set_status_message (_("Your Turn"));
+                    /* Translators: text displayed on a one-player game end in the headerbar/actionbar, if 
the computer player won */
+                    set_status_message (_("I win!"));
             }
             else
             {
-                if (gameover)
-                    /* Translators: text displayed on a one-player game end in the headerbar/actionbar, if 
the computer player won */
-                    set_status_message (_("I win!"));
+                if (human)
+                {
+                    history_button_1.set_player (Player.HUMAN);
+                    history_button_2.set_player (Player.HUMAN);
+                    /* Translators: text displayed during a one-player game in the headerbar/actionbar, if 
it is the human player's turn */
+                    set_status_message (_("Your Turn"));
+                }
                 else
+                {
+                    history_button_1.set_player (Player.OPPONENT);
+                    history_button_2.set_player (Player.OPPONENT);
                     /* Translators: text displayed during a one-player game in the headerbar/actionbar, if 
it is the computer player's turn */
                     set_status_message (_("I’m Thinking…"));
+                }
             }
         }
         else
         {
             string who;
             if (gameover)
-                who = player == HUMAN ? theme_manager.get_player_win (Player.HUMAN)
-                                      : theme_manager.get_player_win (Player.OPPONENT);
+            {
+                history_button_1.set_player (Player.NOBODY);
+                history_button_2.set_player (Player.NOBODY);
+                who = theme_manager.get_player_win (player);
+            }
             else
-                who = player == HUMAN ? theme_manager.get_player_turn (Player.HUMAN)
-                                      : theme_manager.get_player_turn (Player.OPPONENT);
+            {
+                // player can be NOBODY
+                Player current_player = player == HUMAN ? Player.HUMAN : Player.OPPONENT;
+                history_button_1.set_player (current_player);
+                history_button_2.set_player (current_player);
+                who = theme_manager.get_player_turn (current_player);
+            }
 
             set_status_message (_(who));
         }
diff --git a/src/history-button.vala b/src/history-button.vala
index fa5ec0e..693c27c 100644
--- a/src/history-button.vala
+++ b/src/history-button.vala
@@ -23,14 +23,139 @@ using Gtk;
 [GtkTemplate (ui = "/org/gnome/Four-in-a-row/ui/history-button.ui")]
 private class HistoryButton : MenuButton, AdaptativeWidget
 {
-    internal HistoryButton (ref GLib.Menu menu, bool invert_arrow)
+    [CCode (notify = false)] public ThemeManager theme_manager { private get; protected construct; }
+
+    [GtkChild] private Stack stack;
+    [GtkChild] private DrawingArea drawing;
+
+    internal HistoryButton (ref GLib.Menu menu, ThemeManager theme_manager)
+    {
+        Object (menu_model: menu, theme_manager: theme_manager);
+    }
+
+    construct
     {
-        set_menu_model (menu);
-        if (invert_arrow)
-            set_direction (ArrowType.UP);
+        drawing.configure_event.connect (configure_drawing);
+        drawing.draw.connect (update_drawing);
+        theme_manager.theme_changed.connect (() => {
+                if (!drawing_configured)
+                    return;
+                init_pixbuf ();
+                if (current_player != Player.NOBODY)
+                    drawing.queue_draw ();
+            });
     }
 
     protected override void set_window_size (AdaptativeWidget.WindowSize new_size)
     {
     }
+
+    internal void set_player (Player player)
+    {
+        current_player = player;
+        if (player == Player.NOBODY)
+            stack.set_visible_child_name ("label");
+        else
+        {
+            stack.set_visible_child (drawing);
+            drawing.queue_draw ();
+        }
+    }
+
+    /*\
+    * * drawing
+    \*/
+
+    private bool drawing_configured = false;
+    private int drawing_height      = int.MIN;
+    private int drawing_width       = int.MIN;
+    private int pixbuf_size         = int.MIN;
+    private double arrow_half_width = - double.MAX;
+    private int board_x             = int.MIN;
+    private int board_y             = int.MIN;
+    private const int pixbuf_margin = 1;
+
+    private Gdk.Pixbuf tileset_pixbuf;
+
+    private bool configure_drawing ()
+    {
+        int height          = drawing.get_allocated_height ();
+        int width           = drawing.get_allocated_width ();
+        int new_height      = (int) double.min (height, width / 2.0);
+
+        bool refresh_pixbuf = drawing_height != new_height;
+        drawing_height      = new_height;
+        pixbuf_size         = drawing_height - 2 * pixbuf_margin;
+        if (refresh_pixbuf)
+            init_pixbuf ();
+        arrow_half_width    = pixbuf_size / 4.0;
+
+        bool vertical_fill  = height == new_height;
+        drawing_width       =  vertical_fill ? (int) (new_height * 2.0) : width;
+        board_x             =  vertical_fill ? (int) ((width  - drawing_width)  / 2.0) : 0;
+        board_y             = !vertical_fill ? (int) ((height - drawing_height) / 2.0) : 0;
+
+        drawing_configured  = true;
+        return true;
+    }
+    private void init_pixbuf ()
+    {
+        Gdk.Pixbuf? tmp_pixbuf = theme_manager.pb_tileset_raw.scale_simple (pixbuf_size * 6, pixbuf_size, 
Gdk.InterpType.BILINEAR);
+        if (tmp_pixbuf == null)
+            assert_not_reached ();
+        tileset_pixbuf = (!) tmp_pixbuf;
+    }
+
+    private bool update_drawing (Cairo.Context cr)
+    {
+        if (!drawing_configured)
+            return false;
+
+        draw_arrow (cr);
+        draw_piece (cr);
+        return true;
+    }
+
+    private const double arrow_margin_top = 3.0;
+    private void draw_arrow (Cairo.Context cr)
+    {
+        cr.save ();
+
+        cr.set_line_cap (Cairo.LineCap.ROUND);
+        cr.set_line_join (Cairo.LineJoin.ROUND);
+
+        cr.set_source_rgba (/* red */ 0.5, /* green */ 0.5, /* blue */ 0.5, 1.0);
+        cr.set_line_width (/* looks good */ 2.0);
+
+        cr.translate (board_x, board_y);
+        cr.move_to (      arrow_half_width, arrow_margin_top);
+        cr.line_to (3.0 * arrow_half_width, drawing_height / 2.0);
+        cr.line_to (      arrow_half_width, drawing_height - arrow_margin_top);
+        cr.stroke ();
+
+        cr.restore ();
+    }
+
+    private Player current_player = Player.NOBODY;
+    private void draw_piece (Cairo.Context cr)
+    {
+        int offset;
+        switch (current_player)
+        {
+            case Player.HUMAN   : offset = 0;               break;
+            case Player.OPPONENT: offset = pixbuf_size;     break;
+            case Player.NOBODY  : offset = pixbuf_size * 2; break;
+            default: assert_not_reached ();
+        }
+
+        cr.save ();
+        int x = board_x + drawing_width - pixbuf_margin - pixbuf_size;
+        int y = board_y + pixbuf_margin;
+        Gdk.cairo_set_source_pixbuf (cr, tileset_pixbuf, x - offset, y);
+        cr.rectangle (x, y, pixbuf_size, pixbuf_size);
+
+        cr.clip ();
+        cr.paint ();
+        cr.restore ();
+    }
 }


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