[gnome-mines/wip/cssstyling: 2/4] Use standard GTK+ components for the minefield



commit 9b926f02237ef6c4ac085e8c134e6cb74afd2cd9
Author: Robert Roth <robert roth off gmail com>
Date:   Sun Apr 20 15:22:39 2014 +0300

    Use standard GTK+ components for the minefield

 data/Makefile.am        |    2 +-
 data/gnome-mines.css    |   60 +++++
 src/gnome-mines.vala    |   14 +-
 src/minefield-view.vala |  574 +++++++++++++++++------------------------------
 4 files changed, 279 insertions(+), 371 deletions(-)
---
diff --git a/data/Makefile.am b/data/Makefile.am
index 3134221..409b328 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -6,7 +6,7 @@ gsettings_SCHEMAS = org.gnome.mines.gschema.xml
 man_MANS = gnome-mines.6
 
 pixmapdir   = $(datadir)/gnome-mines
-pixmap_DATA = flag.svg flag-question.svg mine.svg bang.svg warning.svg
+pixmap_DATA = flag.svg flag-question.svg mine.svg bang.svg warning.svg gnome-mines.css
 
 desktopdir = $(datadir)/applications
 desktop_in_files = gnome-mines.desktop.in
diff --git a/data/gnome-mines.css b/data/gnome-mines.css
new file mode 100644
index 0000000..386cf2a
--- /dev/null
+++ b/data/gnome-mines.css
@@ -0,0 +1,60 @@
+/*
+You can type here any CSS rule recognized by GTK+.
+You can temporarily disable this custom CSS by clicking on the "Pause" button above.
+
+Changes are applied instantly and globally, for the whole application.
+*/
+
+.tile {
+  background-image:none;
+  background-color:#d3d7cf;
+  border-radius:0px;
+  border-width:3px;
+  color:black;
+  border-color:transparent;
+  border-image:none;
+  font-size:18px;
+  font-weight: bold;
+}
+
+.tile:hover {
+  border-width:1px;
+  border-color:#babdb6;
+}
+
+.tile:active {
+  background-color:#888a85;
+}
+
+.count {
+  background-color:#eeeeec;
+}
+
+.flag {
+  background-color:#8ae234;
+}
+
+.exploded {
+  background-color:#8ae234;
+}
+
+.maybe {
+  background-color:#fce94f;
+}
+
+.incorrect {
+  background-color:#ef2929;
+}
+
+.mine {
+  background-color:#729fcf;
+}
+
+.exploded {
+  background-color:#cc0000;
+}
+
+.cursor {
+  background-color:#e9b96e;
+}
+
diff --git a/src/gnome-mines.vala b/src/gnome-mines.vala
index 8a6762c..bb51f2f 100644
--- a/src/gnome-mines.vala
+++ b/src/gnome-mines.vala
@@ -32,7 +32,7 @@ public class Mines : Gtk.Application
     private Gtk.Button high_scores_button;
     private Gtk.Button new_game_button;
     private Gtk.AspectFrame minefield_aspect;
-    
+
     private Gtk.Label clock_label;
 
     private Menu app_main_menu;
@@ -96,6 +96,18 @@ public class Mines : Gtk.Application
 
         Gtk.Window.set_default_icon_name ("gnome-mines");
 
+        var css_provider = new Gtk.CssProvider ();
+        var css_path = Path.build_filename (DATA_DIRECTORY, "gnome-mines.css");
+        try
+        {
+            css_provider.load_from_path (css_path);
+        }
+        catch (GLib.Error e)
+        {
+            warning ("Error loading css styles from %s: %s", css_path, e.message);
+        }
+        Gtk.StyleContext.add_provider_for_screen (Gdk.Screen.get_default (), css_provider, 
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
+
         add_action_entries (action_entries, this);
         new_game_action = lookup_action ("new-game") as SimpleAction;
         new_game_action.set_enabled (false);
diff --git a/src/minefield-view.vala b/src/minefield-view.vala
index 5e54976..5956bc6 100644
--- a/src/minefield-view.vala
+++ b/src/minefield-view.vala
@@ -90,7 +90,58 @@ private class Position : Object
     }
 }
 
-public class MinefieldView : Gtk.DrawingArea
+private class Tile : Gtk.Button
+{
+    private int _row;
+    private int _column;
+    public signal void tile_mouse_over (int x, int y);
+    public signal void tile_pressed (int x, int y, Gdk.EventButton event);
+    public signal void tile_released (int x, int y, Gdk.EventButton event);
+
+    public int row
+    {
+        get { return _row; }
+    }
+    public int column
+    {
+        get { return _column; }
+    }
+
+    public Tile (int prow, int pcol)
+    {
+        _row = prow;
+        _column = pcol;
+        can_focus = true;
+        add_class ("tile");
+        enter_notify_event.connect ( (event) =>
+        {
+            tile_mouse_over (prow, pcol);
+            return false;
+        } );
+        button_press_event.connect ( (event) =>
+        {
+            tile_pressed (prow, pcol, event);
+            return false;
+        } );
+        button_release_event.connect ( (event) =>
+        {
+            tile_released (prow, pcol, event);
+            return false;
+        } );
+    }
+
+    public void add_class (string style_class)
+    {
+        get_style_context ().add_class (style_class);
+    }
+
+    public void remove_class (string style_class)
+    {
+        get_style_context ().remove_class (style_class);
+    }
+}
+
+public class MinefieldView : Gtk.Grid
 {
     private Settings settings;
 
@@ -125,14 +176,7 @@ public class MinefieldView : Gtk.DrawingArea
     private Position keyboard_cursor;
     private Position selected;
 
-    /* Pre-rendered images */
-    private uint render_size = 0;
-    private Cairo.Pattern? flag_pattern;
-    private Cairo.Pattern? mine_pattern;
-    private Cairo.Pattern? question_pattern;
-    private Cairo.Pattern? bang_pattern;
-    private Cairo.Pattern? warning_pattern;
-    private Cairo.Pattern[] number_patterns;
+    private Tile[,] mines;
 
     private uint mine_size
     {
@@ -161,11 +205,21 @@ public class MinefieldView : Gtk.DrawingArea
     public MinefieldView (Settings settings)
     {
         this.settings = settings;
-        set_events (Gdk.EventMask.EXPOSURE_MASK | Gdk.EventMask.BUTTON_PRESS_MASK | 
Gdk.EventMask.POINTER_MOTION_MASK | Gdk.EventMask.BUTTON_RELEASE_MASK | Gdk.EventMask.KEY_PRESS_MASK | 
Gdk.EventMask.KEY_RELEASE_MASK);
+        row_homogeneous = true;
+        column_homogeneous = true;
+        set_events (Gdk.EventMask.KEY_PRESS_MASK | Gdk.EventMask.KEY_RELEASE_MASK);
         can_focus = true;
+        expand = true;
+        get_style_context ().add_class ("minefield");
+
         selected = new Position ();
+        selected.set_x.connect ((x) => { return x; });
+        selected.set_y.connect ((y) => { return y; });
+        selected.redraw.connect (redraw_sector_cb);
+
         keyboard_cursor = new Position ();
-        number_patterns = new Cairo.Pattern[8];
+        keyboard_cursor.redraw.connect (redraw_sector_cb);
+        keyboard_cursor.validate.connect ((x, y) => { return true; });
     }
     
     private Minefield _minefield;
@@ -175,22 +229,33 @@ public class MinefieldView : Gtk.DrawingArea
         set
         {
             if (_minefield != null)
+            {
                 SignalHandler.disconnect_by_func (_minefield, null, this);
+            }
             _minefield = value;
-
+            mines = new Tile[_minefield.width, _minefield.height];
+            forall ( (child) => { remove (child);});
+            for (int i = 0; i < _minefield.width; i++)
+            {
+                for (int j = 0; j < _minefield.height; j++)
+                {
+                    mines[i,j] = new Tile (i, j);
+                    mines[i,j].show ();
+                    mines[i,j].tile_mouse_over.connect ( (x, y) => { tile_mouse_over_cb (x, y); });
+                    mines[i,j].tile_pressed.connect ( (x, y, event) => { tile_pressed_cb (x, y, event); });
+                    mines[i,j].tile_released.connect ( (x, y, event) => { tile_released_cb (x, y, event); });
+                    add (mines[i,j], i, j);
+                }
+            }
             selected.is_set = false;
-            selected.redraw.connect (redraw_sector_cb);
+
             selected.redraw.connect ((x, y) => { if (_minefield.is_cleared (x, y)) redraw_adjacent (x, y); 
});
-            selected.set_x.connect ((x) => { return x; });
-            selected.set_y.connect ((y) => { return y; });
             selected.validate.connect (_minefield.is_location);
 
             keyboard_cursor.is_set = false;
             keyboard_cursor.position = {0, 0};
-            keyboard_cursor.redraw.connect (redraw_sector_cb);
-            keyboard_cursor.set_x.connect ((x) => { return (int) (x % _minefield.width); });
-            keyboard_cursor.set_y.connect ((y) => { return (int) (y % _minefield.height); });
-            keyboard_cursor.validate.connect ((x, y) => { return true; });
+            keyboard_cursor.set_x.connect ((x) => { return x; }); //(int) (x % _minefield.width); });
+            keyboard_cursor.set_y.connect ((y) => { return y; }); //(int) (y % _minefield.height); });
 
             _minefield.redraw_sector.connect (redraw_sector_cb);
             _minefield.explode.connect (explode_cb);
@@ -200,114 +265,97 @@ public class MinefieldView : Gtk.DrawingArea
         }
     }
 
-    private void explode_cb (Minefield minefield)
+    public void tile_mouse_over_cb (int x, int y)
     {
-        /* Show the mines that we missed or the flags that were wrong */
-        for (var x = 0; x < minefield.width; x++)
-            for (var y = 0; y < minefield.height; y++)
-                if (minefield.has_mine (x, y) || (!minefield.has_mine (x, y) && minefield.get_flag (x, y) == 
FlagType.FLAG))
-                    redraw_sector_cb (x, y);
+        /* Check for end cases and paused game */
+        if (minefield.exploded || minefield.is_complete || minefield.paused)
+            return;
+
+        /* Check that the user isn't currently navigating with keyboard */
+        if (!selected.is_set || keyboard_cursor.is_set)
+            return;
+
+        selected.position = {x, y};
     }
 
-    private Cairo.Pattern render_svg_pattern (Cairo.Context cr, string filename)
+    public void tile_pressed_cb (int x, int y, Gdk.EventButton event)
     {
-        var surface = new Cairo.Surface.similar (cr.get_target (), Cairo.Content.COLOR_ALPHA, (int) 
mine_size, (int) mine_size); 
-        var c = new Cairo.Context (surface);
-        var size = (double) mine_size - 2;
-        try
+        /* Ignore double click events */
+        if (event.type != Gdk.EventType.BUTTON_PRESS)
+            return;
+
+        /* Check for end cases and paused game */
+        if (minefield.exploded || minefield.is_complete || minefield.paused)
+            return;
+
+        /* Does the user have the space key down? */
+        if (selected.is_set && keyboard_cursor.is_set)
+            return;
+
+        /* Hide any lingering previously selected and get new location */
+        selected.is_set = false;
+        selected.position = {x, y};
+
+        /* Is the current position a minefield square? */
+        if (!selected.is_valid)
+            return;
+
+        /* Right or Ctrl+Left button to toggle flags */
+        if (event.button == 3 || (event.button == 1 && (event.state & Gdk.ModifierType.CONTROL_MASK) != 0))
         {
-            var h = new Rsvg.Handle.from_file (filename);
-            var m = Cairo.Matrix.identity ();
-            m.translate (1.0, 1.0);
-            m.scale (size / h.width, size / h.height);
-            c.set_matrix (m);
-            h.render_cairo (c);
+            toggle_mark (selected.x, selected.y);
+            unlook ();
         }
-        catch (Error e)
+        /* Left button to clear */
+        else if (event.button == 1)
         {
-            warning ("Failed to load texture %s: %s", filename, e.message);
+            selected.is_set = true;
+            look ();
         }
 
-        var pattern = new Cairo.Pattern.for_surface (surface);
-        pattern.set_extend (Cairo.Extend.REPEAT);
-        return pattern;
+        keyboard_cursor.is_set = false;
+        mines[keyboard_cursor.x,keyboard_cursor.y].remove_class ("cursor");
+        keyboard_cursor.position = {selected.x, selected.y};
     }
-    
-    private Cairo.Pattern render_number_pattern (uint n)
+
+    public void tile_released_cb (int x, int y, Gdk.EventButton event)
     {
-        var layout = create_pango_layout ("%u".printf (n));
-        layout.set_alignment (Pango.Alignment.CENTER);
+        if (event.button != 1)
+            return;
+
+        /* Check for end cases and paused game */
+        if (minefield.exploded || minefield.is_complete || minefield.paused)
+            return;
+
+        /* Check that the user isn't currently using the mouse */
+        if (!selected.is_set || keyboard_cursor.is_set)
+            return;
+
+        /* Check if the user released button outside the minefield */
+        if (!minefield.is_location (selected.x, selected.y))
+            return;
 
-        /* set attributes for the layout */
-        var attributes = new Pango.AttrList ();
+        unlook ();
 
-        /* Color */
-        Pango.Attribute color_attribute;
-        double color_outline[3];
-        switch (n)
+        if (minefield.is_cleared (selected.x, selected.y))
         {
-        case 1:
-            color_attribute = Pango.attr_foreground_new (0x0000, 0x0000, 0xffff); /* Blue */
-            color_outline = {0.0, 0.0, 0.5};
-            break;
-        case 2:
-            color_attribute = Pango.attr_foreground_new (0x0000, 0xa0a0, 0x0000); /* Green */
-            color_outline = {0.0, 0.5*0.62745098039, 0.0};
-            break;
-        case 3:
-            color_attribute = Pango.attr_foreground_new (0xffff, 0x0000, 0x0000); /* Red */
-            color_outline = {0.5, 0.0, 0.0};
-            break;
-        case 4:
-            color_attribute = Pango.attr_foreground_new (0x0000, 0x0000, 0x7fff); /* Dark Blue */
-            color_outline = {0.0, 0.0, 0.5*0.49999237048};
-            break;
-        case 5:
-            color_attribute = Pango.attr_foreground_new (0xa0a0, 0x0000, 0x0000); /* Dark Red */
-            color_outline = {0.5*0.62745098039, 0.0, 0.0};
-            break;
-        case 6:
-            color_attribute = Pango.attr_foreground_new (0x0000, 0xffff, 0xffff); /* Cyan */
-            color_outline = {0.0, 0.5, 0.5};
-            break;
-        case 7:
-            color_attribute = Pango.attr_foreground_new (0xa0a0, 0x0000, 0xa0a0); /* Dark Violet */
-            color_outline = {0.5*0.62745098039, 0.0, 0.5*0.62745098039};
-            break;
-        default:
-        case 8:
-            color_attribute = Pango.attr_foreground_new (0x0000, 0x0000, 0x0000); /* Black */
-            color_outline = {0.0, 0.0, 0.0};
-            break;
+            multi_release (selected.x, selected.y);
+            redraw_adjacent (selected.x, selected.y);
         }
-        color_attribute.start_index = 0;
-        color_attribute.end_index = uint.MAX;
-        attributes.insert ((owned) color_attribute);
-
-        var font_desc = new Pango.FontDescription ();
-        font_desc.set_family ("Sans");
-        var font_size = (mine_size - 2) * Pango.SCALE * 0.85;
-        font_desc.set_absolute_size (font_size);
-        font_desc.set_weight (Pango.Weight.BOLD);
-        var font_attribute = new Pango.AttrFontDesc (font_desc);
-        font_attribute.start_index = 0;
-        font_attribute.end_index = uint.MAX;
-        attributes.insert ((owned) font_attribute);
-
-        layout.set_attributes (attributes);
-
-        var surface = new Cairo.ImageSurface (Cairo.Format.ARGB32, (int) mine_size, (int) mine_size);
-        var c = new Cairo.Context (surface);
-        Pango.Rectangle extent;
-        layout.get_extents (null, out extent);
-        var dx = ((int) mine_size - 2 - extent.width / Pango.SCALE) / 2 + 1;
-        var dy = ((int) mine_size - 2 - extent.height / Pango.SCALE) / 2 + 1;
-        c.move_to (dx, dy);
-        Pango.cairo_show_layout (c, layout);
-
-        var pattern = new Cairo.Pattern.for_surface (surface);
-        pattern.set_extend (Cairo.Extend.REPEAT);
-        return pattern;
+        else if (minefield.get_flag (selected.x, selected.y) != FlagType.FLAG)
+            minefield.clear_mine (selected.x, selected.y);
+
+        keyboard_cursor.position = {selected.x, selected.y};
+        selected.is_set = false;
+    }
+
+    private void explode_cb (Minefield minefield)
+    {
+        /* Show the mines that we missed or the flags that were wrong */
+        for (var x = 0; x < minefield.width; x++)
+            for (var y = 0; y < minefield.height; y++)
+                if (minefield.has_mine (x, y) || (!minefield.has_mine (x, y) && minefield.get_flag (x, y) == 
FlagType.FLAG))
+                    redraw_sector_cb (x, y);
     }
 
     public override void get_preferred_width (out int minimum, out int natural)
@@ -320,12 +368,13 @@ public class MinefieldView : Gtk.DrawingArea
         minimum = natural = (int) (minefield.height * minimum_size);
     }
 
-    private void redraw_sector_cb (uint x, uint y)
+    public new void add (Gtk.Widget child, int i, int j)
     {
-        queue_draw_area ((int) (x * mine_size), (int) (y * mine_size), (int) mine_size, (int) mine_size);
+        attach (child, i-1, j-1, 1, 1);
+        child.expand = true;
     }
-    
-    private void draw_square (Cairo.Context cr, uint x, uint y)
+
+    private void redraw_sector_cb (uint x, uint y)
     {
         /* Work out if the cursor is being held down on this square or neighbouring cleared squares */
         var is_down = false;
@@ -355,11 +404,8 @@ public class MinefieldView : Gtk.DrawingArea
             /* Draw explosion if have uncovered a mine */
             if (minefield.has_mine (x, y))
             {
-                if (bang_pattern == null)
-                    bang_pattern = render_svg_pattern (cr, Path.build_filename (DATA_DIRECTORY, "bang.svg"));
-                cr.set_source (bang_pattern);
-                cr.rectangle (0, 0, mine_size, mine_size);
-                cr.fill ();
+                mines[x,y].label = "x";
+                mines[x,y].add_class ("exploded");
             }
             /* Indicate the number of mines around this location */
             else
@@ -367,191 +413,53 @@ public class MinefieldView : Gtk.DrawingArea
                 /* Warn if more flags than the number of mines available */
                 if (use_overmine_warning && minefield.has_flag_warning (x, y))
                 {
-                    if (warning_pattern == null)
-                        warning_pattern = render_svg_pattern (cr, Path.build_filename (DATA_DIRECTORY, 
"warning.svg"));
-                    cr.set_source (warning_pattern);
-                    cr.rectangle (0, 0, mine_size, mine_size);
-                    cr.fill ();
+                    mines[x, y].label = "!";
+                    mines[x,y].add_class ("overmine");
                 }
 
                 var n = minefield.get_n_adjacent_mines (x, y);
                 if (n != 0)
                 {
-                    if (number_patterns[n-1] == null)
-                        number_patterns[n-1] = render_number_pattern (n);
-                    cr.set_source (number_patterns[n-1]);
-                    cr.rectangle (0, 0, mine_size, mine_size);
-                    cr.fill ();
+                    mines[x, y].label = n.to_string ();
+                    mines[x, y].sensitive = false;
+                } else {
+                    mines[x, y].sensitive = false;
                 }
+                mines[x,y].add_class ("count");
+                mines[x,y].add_class ("mines" + n.to_string ());
             }
         }
         else
         {
-            var style_context = get_style_context ();
-            style_context.save ();
-            style_context.add_class (Gtk.STYLE_CLASS_BUTTON);
-            style_context.set_state (is_down ? Gtk.StateFlags.ACTIVE : Gtk.StateFlags.NORMAL);
-            style_context.render_frame (cr, 0, 0, (int) mine_size, (int) mine_size);
-            style_context.render_background (cr, 0, 0, (int) mine_size, (int) mine_size);
-            style_context.restore ();
-
             if (minefield.paused)
                 return;
 
             /* Draw flags on uncleared locations */
             if (minefield.get_flag (x, y) == FlagType.FLAG)
             {
-                if (flag_pattern == null)
-                    flag_pattern = render_svg_pattern (cr, Path.build_filename (DATA_DIRECTORY, 
"flag.svg"));                    
-                cr.set_source (flag_pattern);
-                cr.rectangle (0, 0, mine_size, mine_size);
-                cr.fill ();
-
+                mines[x,y].label = "F";
+                mines[x,y].add_class ("flag");
                 /* Cross out incorrect flags */
                 if (minefield.exploded && !minefield.has_mine (x, y))
                 {
-                    var x1 = 0.1 * mine_size;
-                    var y1 = 0.1 * mine_size;
-                    var x2 = 0.9 * mine_size;
-                    var y2 = 0.9 * mine_size;
-
-                    cr.move_to (x1, y1);
-                    cr.line_to (x2, y2);
-                    cr.move_to (x1, y2);
-                    cr.line_to (x2, y1);
-
-                    cr.save ();
-                    cr.set_source_rgba (0.0, 0.0, 0.0, 1.0);
-                    cr.set_line_width (double.max (1, 0.1 * mine_size));
-                    cr.set_line_join (Cairo.LineJoin.ROUND);
-                    cr.set_line_cap (Cairo.LineCap.ROUND);
-                    cr.stroke ();
-                    cr.restore ();
+                    mines[x,y].label="Fx";
+                    mines[x,y].add_class ("incorrect");
                 }
             }
             else if (minefield.exploded && minefield.has_mine (x, y))
             {
-                if (mine_pattern == null)
-                    mine_pattern = render_svg_pattern (cr, Path.build_filename (DATA_DIRECTORY, "mine.svg"));
-                cr.set_source (mine_pattern);
-                cr.rectangle (0, 0, mine_size, mine_size);
-                cr.fill ();
+                mines[x,y].label = "x";
+                mines[x,y].add_class ("mine");
             }
             else if (minefield.get_flag (x, y) == FlagType.MAYBE)
             {
-                if (question_pattern == null)
-                    question_pattern = render_svg_pattern (cr, Path.build_filename (DATA_DIRECTORY, 
"flag-question.svg"));
-                cr.set_source (question_pattern);
-                cr.rectangle (0, 0, mine_size, mine_size);
-                cr.fill ();
+                mines[x,y].label = "?";
             }
-        }
-    }
-
-    public override bool draw (Cairo.Context cr)
-    {
-        /* Resize images */
-        if (render_size != mine_size)
-        {
-            render_size = mine_size;
-            flag_pattern = null;
-            mine_pattern = null;
-            question_pattern = null;
-            bang_pattern = null;
-            warning_pattern = null;
-            for (var i = 0; i < number_patterns.length; i++)
-                number_patterns[i] = null;
-        }
-
-        double dimensions[2] = {minefield.width * mine_size, minefield.height * mine_size};
-        double centre[2] = { 0.5 * dimensions[0], 0.5 * dimensions[1] };
-        double radius = Math.fmax (dimensions[0], dimensions[1]);
-
-        /* Draw Background */
-        var pattern = new Cairo.Pattern.radial (centre[0], centre[1], 0.0, centre[0], centre[1], radius);
-        pattern.add_color_stop_rgba (0.0, 0.0, 0.0, 0.0, 0.1);
-        pattern.add_color_stop_rgba (1.0, 0.0, 0.0, 0.0, 0.4);
-
-        cr.rectangle (- 0.5, - 0.5, dimensions[0] + 0.5, dimensions[1] + 0.5);
-        cr.save ();
-        cr.set_source (pattern);
-        cr.fill_preserve ();
-        cr.set_line_width (0.5);
-        cr.set_source_rgba (0.0, 0.0, 0.0, 1.0);
-        cr.stroke ();
-        cr.restore ();
-
-        /* Draw Grid */
-        cr.save ();
-        cr.set_line_width (0.5);
-        cr.set_source_rgba (0.0, 0.0, 0.0, 1.0);
-        double[] dots = {2, 2};
-        cr.set_dash (dots, 0);
-
-        for (var x = 1; x < minefield.width; x++)
-        {
-            cr.move_to (x * mine_size, 0);
-            cr.line_to (x * mine_size, dimensions[1]);
-            cr.stroke ();
-        }
-
-        for (var y = 1; y < minefield.height; y++)
-        {
-            cr.move_to (0, y * mine_size);
-            cr.line_to (dimensions[0], y * mine_size);
-            cr.stroke ();
-        }
-
-        cr.restore ();
-
-        /* Draw Minefield */
-        for (var x = 0; x < minefield.width; x++)
-        {
-            for (var y = 0; y < minefield.height; y++)
+            else if (minefield.get_flag (x, y) == FlagType.NONE)
             {
-                cr.save ();
-                cr.translate (x * mine_size, y * mine_size);
-                draw_square (cr, x, y);
-                cr.restore ();
+                mines[x,y].label = "";
             }
         }
-
-        /* Draw keyboard cursor */
-        if (keyboard_cursor.is_set)
-        {
-            double key_centre[2] = { (keyboard_cursor.x+0.5) * mine_size, (keyboard_cursor.y+0.5) * 
mine_size };
-            var key_cursor = new Cairo.Pattern.radial (key_centre[0], key_centre[1], 0.0, key_centre[0], 
key_centre[1], 0.25 * mine_size);
-            key_cursor.add_color_stop_rgba (0.0, 1.0, 1.0, 1.0, 1.0);
-            key_cursor.add_color_stop_rgba (0.8, 1.0, 1.0, 1.0, 0.1);
-            key_cursor.add_color_stop_rgba (0.9, 0.0, 0.0, 0.0, 0.5);
-            key_cursor.add_color_stop_rgba (1.0, 0.0, 0.0, 0.0, 0.2);
-            key_cursor.add_color_stop_rgba (1.0, 0.0, 0.0, 0.0, 0.0);
-
-            cr.save ();
-            cr.rectangle (key_centre[0] - 0.45 * mine_size, key_centre[1] - 0.45 * mine_size, 0.9 * 
mine_size, 0.9 * mine_size);
-            cr.set_source (key_cursor);
-            cr.fill ();
-            cr.restore ();
-        }
-
-        /* Draw pause overlay */
-        if (minefield.paused)
-        {
-            cr.set_source_rgba (0, 0, 0, 0.75);
-            cr.paint ();
-
-            cr.select_font_face ("Sans", Cairo.FontSlant.NORMAL, Cairo.FontWeight.BOLD);
-            cr.set_font_size (get_allocated_width () * 0.125);
-
-            var text = _("Paused");
-            Cairo.TextExtents extents;
-            cr.text_extents (text, out extents);
-            cr.move_to ((get_allocated_width () - extents.width) / 2.0, (get_allocated_height () + 
extents.height) / 2.0);
-            cr.set_source_rgb (1, 1, 1);
-            cr.show_text (text);
-        }
-
-        return false;
     }
 
     private void toggle_mark (uint x, uint y)
@@ -566,20 +474,33 @@ public class MinefieldView : Gtk.DrawingArea
              * this should be an indication to the player that they
              * have made a mistake. */
             if (minefield.n_flags >= minefield.n_mines && use_question_marks)
+            {
                 minefield.set_flag (x, y, FlagType.MAYBE);
+                mines[x,y].add_class ("maybe");
+            }
             else
+            {
                 minefield.set_flag (x, y, FlagType.FLAG);
+                mines[x,y].add_class ("flag");
+            }
             break;
 
         case FlagType.MAYBE:
+            mines[x,y].remove_class ("maybe");
             minefield.set_flag (x, y, FlagType.NONE);
             break;
 
         case FlagType.FLAG:
+            mines[x,y].remove_class ("flag");
             if (use_question_marks)
+            {
                 minefield.set_flag (x, y, FlagType.MAYBE);
+                mines[x,y].add_class ("maybe");
+            }
             else
+            {
                 minefield.set_flag (x, y, FlagType.NONE);
+            }
             break;
         }
     }
@@ -644,98 +565,6 @@ public class MinefieldView : Gtk.DrawingArea
         }
     }
 
-    public override bool button_press_event (Gdk.EventButton event)
-    {
-        /* Ignore double click events */
-        if (event.type != Gdk.EventType.BUTTON_PRESS)
-            return false;
-
-        /* Check for end cases and paused game */
-        if (minefield.exploded || minefield.is_complete || minefield.paused)
-            return false;
-
-        /* Does the user have the space key down? */
-        if (selected.is_set && keyboard_cursor.is_set)
-            return false;
-
-        /* Hide any lingering previously selected and get new location */
-        selected.is_set = false;
-        selected.x = (int) Math.floor ((event.x) / mine_size);
-        selected.y = (int) Math.floor ((event.y) / mine_size);
-
-        /* Is the current position a minefield square? */
-        if (!selected.is_valid)
-            return false;
-
-        /* Right or Ctrl+Left button to toggle flags */
-        if (event.button == 3 || (event.button == 1 && (event.state & Gdk.ModifierType.CONTROL_MASK) != 0))
-        {
-            toggle_mark (selected.x, selected.y);
-            unlook ();
-        }
-        /* Left button to clear */
-        else if (event.button == 1)
-        {
-            selected.is_set = true;
-            look ();
-        }
-
-        keyboard_cursor.is_set = false;
-        keyboard_cursor.position = {selected.x, selected.y};
-
-        return false;
-    }
-
-    public override bool motion_notify_event (Gdk.EventMotion event)
-    {
-        /* Check for end cases and paused game */
-        if (minefield.exploded || minefield.is_complete || minefield.paused)
-            return false;
-
-        /* Check that the user isn't currently navigating with keyboard */
-        if (!selected.is_set || keyboard_cursor.is_set)
-            return false;
-
-        var x = (int) Math.floor ((event.x) / mine_size);
-        var y = (int) Math.floor ((event.y) / mine_size);
-        selected.position = {x, y};
-
-        return false;
-    }
-
-    public override bool button_release_event (Gdk.EventButton event)
-    {
-        if (event.button != 1)
-            return false;
-
-        /* Check for end cases and paused game */
-        if (minefield.exploded || minefield.is_complete || minefield.paused)
-            return false;
-
-        /* Check that the user isn't currently using the mouse */
-        if (!selected.is_set || keyboard_cursor.is_set)
-            return false;
-
-        /* Check if the user released button outside the minefield */
-        if (!minefield.is_location(selected.x, selected.y))
-            return false;
-
-        unlook ();
-
-        if (minefield.is_cleared (selected.x, selected.y))
-        {
-            multi_release (selected.x, selected.y);
-            redraw_adjacent (selected.x, selected.y);
-        }
-        else if (minefield.get_flag (selected.x, selected.y) != FlagType.FLAG)
-            minefield.clear_mine (selected.x, selected.y);
-
-        keyboard_cursor.position = {selected.x, selected.y};
-        selected.is_set = false;
-
-        return false;
-    }
-
     public override bool key_press_event (Gdk.EventKey event)
     {
         /* Check for end cases and paused game */
@@ -748,6 +577,7 @@ public class MinefieldView : Gtk.DrawingArea
 
         var x = keyboard_cursor.x;
         var y = keyboard_cursor.y;
+        mines[keyboard_cursor.x,keyboard_cursor.y].remove_class ("cursor");
 
         switch (event.keyval)
         {
@@ -795,16 +625,21 @@ public class MinefieldView : Gtk.DrawingArea
         }
 
         if (x == keyboard_cursor.x && y == keyboard_cursor.y)
+        {
+            mines[keyboard_cursor.x,keyboard_cursor.y].add_class ("cursor");
             return true;
+        }
 
         if (!keyboard_cursor.is_set)
         {
             keyboard_cursor.is_set = true;
+            mines[keyboard_cursor.x,keyboard_cursor.y].add_class ("cursor");
             return true;
         }
 
-        keyboard_cursor.position = {x, y};
+        keyboard_cursor.position = { (int) (x % _minefield.height), (int) (y % _minefield.width)};
 
+        mines[keyboard_cursor.x,keyboard_cursor.y].add_class ("cursor");
         if (selected.is_set)
             selected.position = {keyboard_cursor.x, keyboard_cursor.y};
 
@@ -838,4 +673,5 @@ public class MinefieldView : Gtk.DrawingArea
 
         return false;
     }
+
 }


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