[iagno/highlight-on-hover] Highlight on hover.



commit 08e5aed6419266c0a82fe7105c05a58a5a5c8b19
Author: Arnaud Bonatti <arnaud bonatti gmail com>
Date:   Sat Feb 23 18:43:24 2019 +0100

    Highlight on hover.
    
    Inspired by a patch by
    Iulian Radu, issue #5.

 src/game-view.vala | 151 +++++++++++++++++++++++++++++++++++++++++++++--------
 src/iagno.vala     |   6 +--
 2 files changed, 131 insertions(+), 26 deletions(-)
---
diff --git a/src/game-view.vala b/src/game-view.vala
index 1e5a905..e87df37 100644
--- a/src/game-view.vala
+++ b/src/game-view.vala
@@ -67,13 +67,21 @@ private class GameView : Gtk.DrawingArea
     [CCode (notify = false)] private int board_y { private get { return (get_allocated_height () - 
board_size) / 2; }}
 
     /* Keyboard */
-    private bool show_highlight;
-    private bool highlight_set;
-    private uint8 highlight_x;
-    private uint8 highlight_y;
-    private uint8 highlight_state;
+    private bool show_highlight = false;
+    private bool highlight_set = false;
+    private uint8 highlight_x = uint8.MAX;
+    private uint8 highlight_y = uint8.MAX;
+    private uint8 highlight_state = 0;
     private const uint8 HIGHLIGHT_MAX = 5;
 
+    /* Mouse */
+    private bool show_mouse_highlight = false;
+    private bool mouse_position_set = false;
+    private uint8 mouse_highlight_x = uint8.MAX;
+    private uint8 mouse_highlight_y = uint8.MAX;
+    private uint8 mouse_position_x = uint8.MAX;
+    private uint8 mouse_position_y = uint8.MAX;
+
     /* Delay in milliseconds between tile flip frames */
     private const int PIXMAP_FLIP_DELAY = 20;
 
@@ -133,10 +141,19 @@ private class GameView : Gtk.DrawingArea
 
     construct
     {
-        set_events (Gdk.EventMask.EXPOSURE_MASK | Gdk.EventMask.BUTTON_PRESS_MASK | 
Gdk.EventMask.BUTTON_RELEASE_MASK);
+        set_events (Gdk.EventMask.EXPOSURE_MASK
+                  | Gdk.EventMask.BUTTON_PRESS_MASK
+                  | Gdk.EventMask.BUTTON_RELEASE_MASK
+                  | Gdk.EventMask.POINTER_MOTION_MASK);
         set_size_request (350, 350);
     }
 
+    private Iagno iagno_instance;
+    internal GameView (Iagno iagno_instance)
+    {
+        this.iagno_instance = iagno_instance;
+    }
+
     /*\
     * * theme
     \*/
@@ -300,17 +317,21 @@ private class GameView : Gtk.DrawingArea
                 rounded_square (cr, tile_x, tile_y, tile_size, 0, background_radius);
                 cr.fill ();
 
-                if ((highlight_x == x && highlight_y == y)
-                 && (show_highlight || highlight_state != 0)
-                 && !game.is_complete)  // TODO highlight last played tile on game.is_complete, even if it's 
the opponent one...
+                if (!game.is_complete   // TODO highlight last played tile on game.is_complete, even if it's 
the opponent one...
+                 // mouse: show highlight if current tile is the highlighted one (not necessarily the one 
under the mouse)
+                 && (( show_mouse_highlight && !show_highlight && (mouse_highlight_x == x) && 
(mouse_highlight_y == y)
+                   // mouse: do not show highlight if it's computer turn, but decrease its state to 0
+                   && (iagno_instance.player_one == game.current_color || iagno_instance.computer == null))
+                  // keyboard: allow decreasing highlight state after hitting escape
+                  || (!show_mouse_highlight && (show_highlight || highlight_state != 0) && (highlight_x == 
x) && (highlight_y == y))))
                 {
                     /* manage animated highlight */
-                    if (show_highlight && highlight_state != HIGHLIGHT_MAX)
+                    if ((show_highlight || show_mouse_highlight) && highlight_state != HIGHLIGHT_MAX)
                     {
                         highlight_state ++;
                         queue_draw_area (board_x + tile_x, board_y + tile_y, tile_size, tile_size);
                     }
-                    else if (!show_highlight && highlight_state != 0)
+                    else if (!(show_highlight || show_mouse_highlight) && highlight_state != 0)
                         highlight_state = 0;    // TODO highlight_state--; on mouse click, conflict updating 
coords & showing the anim on previous place
 
                     /* draw animated highlight */
@@ -425,6 +446,7 @@ private class GameView : Gtk.DrawingArea
             highlight_x = x;
             highlight_y = y;
         }
+        show_mouse_highlight = false;
 
         update_square (x, y);
     }
@@ -475,6 +497,8 @@ private class GameView : Gtk.DrawingArea
                         else
                         {
                             animate_timeout = 0;
+                            if (!show_highlight)
+                                _motion_notify_event (mouse_position_x, mouse_position_y, /* force redraw */ 
true);
                             return Source.REMOVE;
                         }
                     });
@@ -603,12 +627,61 @@ private class GameView : Gtk.DrawingArea
                 highlight_x = x;
                 highlight_y = y;
                 move (x, y);
+                queue_draw_tile (x, y);
             }
         }
 
         return true;
     }
 
+    internal override bool motion_notify_event (Gdk.EventMotion event)
+    {
+        uint8 x = (uint8) ((event.x - board_x) / paving_size);
+        uint8 y = (uint8) ((event.y - board_y) / paving_size);
+        if ((x >= 0 && x < game.size)
+         && (y >= 0 && y < game.size)
+         && ((x != mouse_position_x)
+          || (y != mouse_position_y)))
+        {
+            mouse_position_x = x;
+            mouse_position_y = y;
+            mouse_position_set = true;
+            if (show_highlight
+             || (x != mouse_highlight_x)
+             || (y != mouse_highlight_y))
+                Timeout.add (200, () => { _motion_notify_event (x, y); return Source.REMOVE; });
+        }
+
+        return base.motion_notify_event (event);
+    }
+    private void _motion_notify_event (uint8 x, uint8 y, bool force_redraw = false)
+    {
+        if (!force_redraw
+         && ((x != mouse_position_x)
+          || (y != mouse_position_y)))
+            return;
+
+        show_mouse_highlight = game.can_place (x, y, game.current_color);
+
+        uint8 old_mouse_highlight_x = mouse_highlight_x;
+        uint8 old_mouse_highlight_y = mouse_highlight_y;
+
+        mouse_highlight_x = x;
+        mouse_highlight_y = y;
+
+        if (old_mouse_highlight_x != uint8.MAX && old_mouse_highlight_y != uint8.MAX)
+            queue_draw_tile (old_mouse_highlight_x, old_mouse_highlight_y);
+        if (show_mouse_highlight && show_highlight)
+        {
+            show_highlight = false;
+            queue_draw_tile (highlight_x, highlight_y);
+        }
+        if (show_mouse_highlight || force_redraw)
+        {
+            queue_draw_tile (mouse_highlight_x, mouse_highlight_y);
+        }
+    }
+
     internal override bool key_press_event (Gdk.EventKey event)
     {
         if (!game_is_set)
@@ -636,12 +709,14 @@ private class GameView : Gtk.DrawingArea
         {
             case "Left":
             case "KP_Left":
-                if (!highlight_set && game.current_color == Player.LIGHT) highlight_y = game.size / 2;
+                if (mouse_position_set && show_mouse_highlight) { highlight_x = mouse_highlight_x; 
highlight_y = mouse_highlight_y; }
+                else if (!highlight_set && game.current_color == Player.LIGHT) highlight_y = game.size / 2;
                 if (highlight_x > 0) highlight_x --;
                 break;
             case "Right":
             case "KP_Right":
-                if (!highlight_set)
+                if (mouse_position_set && show_mouse_highlight) { highlight_x = mouse_highlight_x; 
highlight_y = mouse_highlight_y; }
+                else if (!highlight_set)
                 {
                     highlight_x = game.size / 2;
                     if (game.current_color == Player.DARK) highlight_y = highlight_x;
@@ -650,12 +725,14 @@ private class GameView : Gtk.DrawingArea
                 break;
             case "Up":
             case "KP_Up":
-                if (!highlight_set && game.current_color == Player.LIGHT) highlight_x = game.size / 2;
+                if (mouse_position_set && show_mouse_highlight) { highlight_x = mouse_highlight_x; 
highlight_y = mouse_highlight_y; }
+                else if (!highlight_set && game.current_color == Player.LIGHT) highlight_x = game.size / 2;
                 if (highlight_y > 0) highlight_y --;
                 break;
             case "Down":
             case "KP_Down":
-                if (!highlight_set)
+                if (mouse_position_set && show_mouse_highlight) { highlight_x = mouse_highlight_x; 
highlight_y = mouse_highlight_y; }
+                else if (!highlight_set)
                 {
                     highlight_y = game.size / 2;
                     if (game.current_color == Player.DARK) highlight_x = highlight_y;
@@ -666,6 +743,17 @@ private class GameView : Gtk.DrawingArea
             case "space":
             case "Return":
             case "KP_Enter":
+                if (show_mouse_highlight)
+                {
+                    move (mouse_highlight_x, mouse_highlight_y);
+                    return true;
+                }
+                else if (mouse_position_set)
+                {
+                    highlight_x = mouse_position_x;
+                    highlight_y = mouse_position_y;
+                }
+                break;
 
             case "Escape": break;
 
@@ -722,19 +810,36 @@ private class GameView : Gtk.DrawingArea
         else
             show_highlight = true;
 
-        queue_draw_area ((int) (board_x + old_highlight_x * paving_size),
-                         (int) (board_y + old_highlight_y * paving_size),
-                         tile_size,
-                         tile_size);
+        queue_draw_tile (old_highlight_x, old_highlight_y);
         if ((old_highlight_x != highlight_x)
          || (old_highlight_y != highlight_y))
-            queue_draw_area ((int) (board_x + highlight_x * paving_size),
-                             (int) (board_y + highlight_y * paving_size),
-                             tile_size,
-                             tile_size);
+            queue_draw_tile (highlight_x, highlight_y);
+        if (key != "Escape")
+        {
+            show_mouse_highlight = false;
+            if (mouse_position_set)
+                queue_draw_tile (mouse_highlight_x, mouse_highlight_y);
+        }
+        else if (mouse_position_set)
+        {
+            highlight_x = mouse_position_x;
+            highlight_y = mouse_position_y;
+            if (mouse_position_set)
+                _motion_notify_event (highlight_x, highlight_y, /* force redraw */ true);
+        }
         return true;
     }
 
+    private void queue_draw_tile (uint8 x, uint8 y)
+        requires (x < game.size)
+        requires (y < game.size)
+    {
+        queue_draw_area ((int) (board_x + x * paving_size),
+                         (int) (board_y + y * paving_size),
+                         tile_size,
+                         tile_size);
+    }
+
     /*\
     * * Scoreboard
     \*/
diff --git a/src/iagno.vala b/src/iagno.vala
index 74bd60c..a1cebed 100644
--- a/src/iagno.vala
+++ b/src/iagno.vala
@@ -50,10 +50,10 @@ private class Iagno : Gtk.Application
     private ThemesDialog themes_dialog;
 
     /* Computer player (if there is one) */
-    private ComputerPlayer? computer = null;
+    internal ComputerPlayer? computer { internal get; private set; default = null; }
 
     /* Human player */
-    private Player player_one;
+    internal Player player_one { internal get; private set; }
 
     /* The game being played */
     private Game game;
@@ -210,7 +210,7 @@ private class Iagno : Gtk.Application
         /* UI parts */
         Builder builder = new Builder.from_resource ("/org/gnome/Reversi/ui/iagno-screens.ui");
 
-        view = new GameView ();
+        view = new GameView (this);
         view.move.connect (player_move_cb);
 
         DrawingArea scoredrawing = (DrawingArea) builder.get_object ("scoredrawing");


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