[gnome-games] iagno: Make window scalable



commit 6684801a700fb7a5e4e025aad3324b5b0acf99e1
Author: Robert Ancell <robert ancell canonical com>
Date:   Thu Dec 29 16:15:45 2011 +1100

    iagno: Make window scalable

 iagno/src/game-view.vala |  184 +++++++++++++++++++++++-----------------------
 iagno/src/iagno.vala     |   58 ++++++++++-----
 2 files changed, 129 insertions(+), 113 deletions(-)
---
diff --git a/iagno/src/game-view.vala b/iagno/src/game-view.vala
index bbb4446..50f9960 100644
--- a/iagno/src/game-view.vala
+++ b/iagno/src/game-view.vala
@@ -1,23 +1,49 @@
 public class GameView : Gtk.DrawingArea
 {
-    private const int GRIDWIDTH = 1;
-    private const int PIXMAP_FLIP_DELAY = 20;
+    /* Space between tiles in pixels */
+    private const int GRID_WIDTH = 1;
 
-    private uint tile_width = 80;
-    private uint tile_height = 80;
-    private uint board_width = 648;
-    private uint board_height = 648;
-    private double[] dash = {4.0};
+    /* Delay in milliseconds between tile flip frames */
+    private const int PIXMAP_FLIP_DELAY = 20;
 
-    private Cairo.Surface? tiles_surface = null;
-    private Cairo.Surface? background_surface = null;
+    /* Pre-rendered image */
+    private uint render_size = 0;
+    private Cairo.Pattern? tiles_pattern = null;
 
+    /* The images being showed on each location */
     private int[,] pixmaps;
 
+    /* Animation timer */
     private uint animate_timeout = 0;
 
     public signal void move (int x, int y);
 
+    private int tile_size
+    {
+        get
+        {
+            return int.min (get_allocated_width () / 8, get_allocated_height () / (int) 8) - GRID_WIDTH;
+        }
+    }
+    
+    private int x_offset
+    {
+        get
+        {
+            return (get_allocated_width () - 8 * (tile_size + GRID_WIDTH)) / 2;
+        }
+    }
+
+    private int y_offset
+    {
+        get
+        {
+            return (get_allocated_height () - 8 * (tile_size + GRID_WIDTH)) / 2;
+        }
+    }
+
+    private int board_size { get { return (tile_size + GRID_WIDTH) * 8; } }
+
     public GameView ()
     {
         set_events (Gdk.EventMask.EXPOSURE_MASK | Gdk.EventMask.BUTTON_PRESS_MASK);
@@ -44,11 +70,11 @@ public class GameView : Gtk.DrawingArea
         }
     }
 
-    private string? _tile_set = null;
-    public string? tile_set
+    private GnomeGamesSupport.Preimage? _theme = null;
+    public GnomeGamesSupport.Preimage? theme
     {
-        get { return _tile_set; }
-        set { _tile_set = value; tiles_surface = null; redraw (); }
+        get { return _theme; }
+        set { _theme = value; tiles_pattern = null; queue_draw (); }
     }
 
     private bool _show_grid;
@@ -58,50 +84,72 @@ public class GameView : Gtk.DrawingArea
         set { _show_grid = value; redraw (); }
     }
 
+    public override void get_preferred_width (out int minimum, out int natural)
+    {
+        minimum = natural = (int) (8 * (20 + GRID_WIDTH));
+    }
+
+    public override void get_preferred_height (out int minimum, out int natural)
+    {
+        minimum = natural = (int) (8 * (20 + GRID_WIDTH));
+    }
+
     public override bool draw (Cairo.Context cr)
     {
         if (game == null)
             return false;
-
-        if (tiles_surface == null)
-            load_pixmaps ();
-
-        var p = new Cairo.Pattern.for_surface (background_surface);
-        p.set_extend (Cairo.Extend.REPEAT);
-        cr.set_source (p);
-        cr.move_to (0, 0);
-        cr.line_to (0, board_height);
-        cr.line_to (board_width, board_height);
-        cr.line_to (board_width, 0);
-        cr.line_to (0, 0);
-        cr.fill ();
+            
+        if (tiles_pattern == null || render_size != tile_size)
+        {
+            render_size = tile_size;
+            var surface = new Cairo.ImageSurface (Cairo.Format.ARGB32, tile_size * 8, tile_size * 4);
+            var c = new Cairo.Context (surface);
+            var pixbuf = theme.render (tile_size * 8, tile_size * 4);
+            Gdk.cairo_set_source_pixbuf (c, pixbuf, 0, 0);
+            c.paint ();
+
+            tiles_pattern = new Cairo.Pattern.for_surface (surface);
+        }
 
         for (var x = 0; x < 8; x++)
         {
             for (var y = 0; y < 8; y++)
             {
-                var tile_surface_x = x * (int) (tile_width + GRIDWIDTH) - (pixmaps[x, y] % 8) * (int) tile_width;
-                var tile_surface_y = y * (int) (tile_height + GRIDWIDTH) - (pixmaps[x, y] / 8) * (int) tile_height;
-
-                cr.set_source_surface (tiles_surface, tile_surface_x, tile_surface_y);
-                cr.rectangle (x * (tile_width + GRIDWIDTH), y * (tile_height + GRIDWIDTH), tile_width, tile_height);
+                var tile_x = x_offset + x * (tile_size + GRID_WIDTH);
+                var tile_y = y_offset + y * (tile_size + GRID_WIDTH);
+                var texture_x = (pixmaps[x, y] % 8) * tile_size;
+                var texture_y = (pixmaps[x, y] / 8) * tile_size;
+
+                var matrix = Cairo.Matrix.identity ();
+                matrix.translate (texture_x - tile_x, texture_y - tile_y);
+                tiles_pattern.set_matrix (matrix);
+                cr.set_source (tiles_pattern);
+                cr.rectangle (tile_x, tile_y, tile_size, tile_size);
                 cr.fill ();
             }
         }
 
         if (show_grid)
         {
+            /* Make sure the dash width evenly subdivides the tile height, and is at least 4 pixels long.
+            * This makes the dash crossings always cross in the same place, which looks nicer. */
+            var dash_count = (tile_size + GRID_WIDTH) / 4;
+            if (dash_count % 2 != 0)
+                dash_count--;
+            double dash[1];
+            dash[0] = ((double)(tile_size + GRID_WIDTH)) / dash_count;
+            cr.set_dash (dash, 2.5);
+
             cr.set_source_rgb (1.0, 1.0, 1.0);
             cr.set_operator (Cairo.Operator.DIFFERENCE);
-            cr.set_dash (dash, 2.5);
-            cr.set_line_width (GRIDWIDTH);
+            cr.set_line_width (GRID_WIDTH);
             for (var i = 1; i < 8; i++)
             {
-                cr.move_to (i * board_width / 8 - 0.5, 0);
-                cr.line_to (i * board_width / 8 - 0.5, board_height);
+                cr.move_to (x_offset + i * board_size / 8 - 0.5, y_offset);
+                cr.rel_line_to (0, board_size);
 
-                cr.move_to (0, i * board_height / 8 - 0.5);
-                cr.line_to (board_width, i * board_height / 8 - 0.5);
+                cr.move_to (x_offset, y_offset + i * board_size / 8 - 0.5);
+                cr.rel_line_to (board_size, 0);
             }
 
             cr.stroke ();
@@ -110,60 +158,9 @@ public class GameView : Gtk.DrawingArea
         return false;
     }
 
-    private void load_pixmaps ()
-    {
-        var dname = GnomeGamesSupport.runtime_get_directory (GnomeGamesSupport.RuntimeDirectory.GAME_PIXMAP_DIRECTORY);
-        var fname = Path.build_filename (dname, tile_set);
-
-        /* fall back to default tileset if chosen set not found */
-        if (!FileUtils.test (fname, FileTest.EXISTS | FileTest.IS_REGULAR))
-            fname = Path.build_filename (dname, "sun_and_star.svg");
-
-        if (!FileUtils.test (fname, FileTest.EXISTS | FileTest.IS_REGULAR))
-        {
-            stderr.printf (_("Could not find \'%s\' pixmap file\n"), fname);
-            Posix.exit (Posix.EXIT_FAILURE);
-        }
-
-        Gdk.Pixbuf image;
-        try
-        {
-            image = new Gdk.Pixbuf.from_file (fname);
-        }
-        catch (Error e)
-        {
-            warning ("gdk-pixbuf error %s\n", e.message);
-            return;
-        }
-
-        tile_width = image.get_width () / 8;
-        tile_height = image.get_height () / 4;
-
-        /* Make sure the dash width evenly subdivides the tile height, and is at least 4 pixels long.
-         * This makes the dash crossings always cross in the same place, which looks nicer. */
-        var dash_count = (tile_height + GRIDWIDTH) / 4;
-        if (dash_count % 2 != 0)
-            dash_count--;
-        dash[0] = ((double)(tile_height + GRIDWIDTH)) / dash_count;
-
-        board_width = (tile_width + GRIDWIDTH) * 8;
-        board_height = (tile_height + GRIDWIDTH) * 8;
-        set_size_request ((int) board_width, (int) board_height);
-
-        tiles_surface = get_window ().create_similar_surface (Cairo.Content.COLOR_ALPHA, image.get_width (), image.get_height ());
-        var cr = new Cairo.Context (tiles_surface);
-        Gdk.cairo_set_source_pixbuf (cr, image, 0, 0);
-        cr.paint ();
-
-        background_surface = get_window ().create_similar_surface (Cairo.Content.COLOR_ALPHA, 1, 1);
-        cr = new Cairo.Context (background_surface);
-        Gdk.cairo_set_source_pixbuf (cr, image, 0, 0);
-        cr.paint ();
-    }
-
     public void redraw ()
     {
-        queue_draw_area (0, 0, (int) board_width, (int) board_height);
+        queue_draw ();
     }
 
     private void square_changed_cb (int x, int y)
@@ -184,7 +181,7 @@ public class GameView : Gtk.DrawingArea
             if (animate_timeout == 0)
                 animate_timeout = Timeout.add (PIXMAP_FLIP_DELAY, animate_cb);
         }
-        queue_draw_area (x * (int) (tile_width + GRIDWIDTH), y * (int) (tile_height + GRIDWIDTH), (int) tile_width, (int) tile_height);
+        queue_draw_area (x_offset + x * (int) (tile_size + GRID_WIDTH), y_offset + y * (int) (tile_size + GRID_WIDTH), tile_size, tile_size);
     }
 
     private bool animate_cb ()
@@ -229,9 +226,10 @@ public class GameView : Gtk.DrawingArea
     {
         if (event.button == 1)
         {
-            var x = (int) event.x / (int) (tile_width + GRIDWIDTH);
-            var y = (int) event.y / (int) (tile_height + GRIDWIDTH);
-            move (x, y);
+            var x = (int) (event.x - x_offset) / (tile_size + GRID_WIDTH);
+            var y = (int) (event.y - y_offset) / (tile_size + GRID_WIDTH);
+            if (x >= 0 && x < 8 && y >= 0 && y < 8)
+                move (x, y);
         }
 
         return true;
diff --git a/iagno/src/iagno.vala b/iagno/src/iagno.vala
index 44a8c82..c5af7e9 100644
--- a/iagno/src/iagno.vala
+++ b/iagno/src/iagno.vala
@@ -101,23 +101,22 @@ public class Iagno
         var menubar = (Gtk.MenuBar) ui_manager.get_widget ("/MainMenu");
         vbox.pack_start (menubar, false, false, 0);
 
-        var notebook = new Gtk.Notebook ();
-        notebook.show ();
-        notebook.set_show_tabs (false);
-        notebook.set_show_border (false);
-
         window.delete_event.connect (window_delete_event_cb);
 
         view = new GameView ();
         view.game = game;
         view.move.connect (player_move_cb);
         view.show_grid = settings.get_boolean ("show-grid");
-        view.tile_set = settings.get_string ("tileset");
+        var tile_set = settings.get_string ("tileset");
+        var theme = load_theme_texture (tile_set);
+        if (theme == null)
+        {
+            warning ("Unable to load theme %s, falling back to default", tile_set);
+            theme = load_theme_texture ("black_and_white.svg", true);
+        }
+        view.theme = theme;
         view.show ();
-
-        notebook.append_page (view, null);
-        notebook.set_current_page (0);
-        vbox.pack_start (notebook, false, false, 0);
+        vbox.pack_start (view, true, true, 0);
 
         statusbar = new Gtk.Statusbar ();
         statusbar.show ();
@@ -144,8 +143,6 @@ public class Iagno
         light_score_label.show ();
         grid.attach (light_score_label, 5, 0, 1, 1);
 
-        window.set_resizable (false);
-
         statusbar_id = statusbar.get_context_id ("iagno");
 
         GnomeGamesSupport.sound_enable (settings.get_boolean ("sound"));
@@ -158,6 +155,21 @@ public class Iagno
         window.show ();
     }
 
+    private GnomeGamesSupport.Preimage? load_theme_texture (string filename, bool fail_on_error = false)
+    {
+        var pixmap_directory = GnomeGamesSupport.runtime_get_directory (GnomeGamesSupport.RuntimeDirectory.GAME_PIXMAP_DIRECTORY);
+        var path = Path.build_filename (pixmap_directory, filename);
+        try
+        {
+            return new GnomeGamesSupport.Preimage.from_file (path);
+        }
+        catch (Error e)
+        {
+            warning ("Failed to load theme %s: %s", filename, path);
+            return null;
+        }
+    }
+
     private void quit_game_cb ()
     {
         Gtk.main_quit ();
@@ -413,10 +425,17 @@ public class Iagno
         return true;
     }
 
-    private void set_selection (Gtk.ComboBox widget)
+    private void theme_changed_cb (Gtk.ComboBox widget)
     {
-        view.tile_set = theme_file_list.get_nth (widget.get_active ());
-        settings.set_string ("tileset", view.tile_set);
+        var tile_set = theme_file_list.get_nth (widget.get_active ());
+        settings.set_string ("tileset", tile_set);
+
+        var theme = load_theme_texture (tile_set);
+        if (theme == null)
+            warning ("Unable to load theme %s", tile_set);
+        else
+            view.theme = theme;
+
         view.redraw ();
     }
 
@@ -544,12 +563,11 @@ public class Iagno
         var dir = GnomeGamesSupport.runtime_get_directory (GnomeGamesSupport.RuntimeDirectory.GAME_PIXMAP_DIRECTORY);
         theme_file_list = new GnomeGamesSupport.FileList.images (dir, null);
         theme_file_list.transform_basename ();
-        var option_menu = (Gtk.ComboBox) theme_file_list.create_widget (view.tile_set, GnomeGamesSupport.FILE_LIST_REMOVE_EXTENSION | GnomeGamesSupport.FILE_LIST_REPLACE_UNDERSCORES);
-
-        label.set_mnemonic_widget (option_menu);
-        option_menu.changed.connect (set_selection);
-        hbox.pack_start (option_menu, true, true, 0);
+        var theme_combo = (Gtk.ComboBox) theme_file_list.create_widget (settings.get_string ("tileset"), GnomeGamesSupport.FILE_LIST_REMOVE_EXTENSION | GnomeGamesSupport.FILE_LIST_REPLACE_UNDERSCORES);
 
+        label.set_mnemonic_widget (theme_combo);
+        theme_combo.changed.connect (theme_changed_cb);
+        hbox.pack_start (theme_combo, true, true, 0);
 
         propbox.show_all ();
     }



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