[gnome-chess] Prompt user for selecting promotion type when the pawn reaches 8th rank



commit 7e16e130a1434a901da0cd6b91ead1744b9ab6dc
Author: Chandni Verma <chandniverma2112 gmail com>
Date:   Tue Dec 11 14:40:37 2012 +1300

    Prompt user for selecting promotion type when the pawn reaches 8th rank
    
    Fixes: https://bugzilla.gnome.org/show_bug.cgi?id=655761

 data/Makefile.am                |    3 +-
 data/promotion-type-selector.ui |  268 +++++++++++++++++++++++++++++++++++++++
 src/chess-game.vala             |   22 +++-
 src/chess-scene.vala            |   12 ++
 src/gnome-chess.vala            |  114 ++++++++++++++++-
 5 files changed, 416 insertions(+), 3 deletions(-)
---
diff --git a/data/Makefile.am b/data/Makefile.am
index 29cae9a..c6bc697 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -8,7 +8,8 @@ desktop_DATA = $(desktop_in_files:.desktop.in.in=.desktop)
 uidir = $(datadir)/gnome-chess
 ui_DATA = \
 	gnome-chess.ui \
-	preferences.ui
+	preferences.ui \
+	promotion-type-selector.ui
 
 gsettings_SCHEMAS = org.gnome.gnome-chess.gschema.xml
 @INTLTOOL_XML_NOMERGE_RULE@
diff --git a/data/promotion-type-selector.ui b/data/promotion-type-selector.ui
new file mode 100644
index 0000000..deeac9b
--- /dev/null
+++ b/data/promotion-type-selector.ui
@@ -0,0 +1,268 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <!-- interface-requires gtk+ 3.0 -->
+  <object class="GtkDialog" id="dialog_promotion_type_selector">
+    <property name="can_focus">False</property>
+    <property name="border_width">5</property>
+    <property name="type_hint">dialog</property>
+    <property name="has_resize_grip">False</property>
+    <child internal-child="vbox">
+      <object class="GtkBox" id="dialog-vbox1">
+        <property name="can_focus">False</property>
+        <property name="margin_left">12</property>
+        <property name="margin_right">12</property>
+        <property name="margin_top">6</property>
+        <property name="margin_bottom">20</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">12</property>
+        <child internal-child="action_area">
+          <object class="GtkButtonBox" id="dialog-action_area1">
+            <property name="can_focus">False</property>
+            <property name="layout_style">center</property>
+            <child>
+              <object class="GtkToggleButton" id="togglebutton_queen">
+                <property name="width_request">100</property>
+                <property name="height_request">120</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_action_appearance">False</property>
+                <property name="use_underline">True</property>
+                <property name="image_position">top</property>
+                <child>
+                  <object class="GtkGrid" id="grid_queen">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="halign">center</property>
+                    <property name="valign">center</property>
+                    <property name="n_rows">2</property>
+                    <property name="n_columns">1</property>
+                    <child>
+                      <object class="GtkLabel" id="label_queen">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="label" translatable="yes">_Queen</property>
+                        <property name="use_underline">True</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">1</property>
+                        <property name="width">1</property>
+                        <property name="height">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkImage" id="image_queen">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">0</property>
+                        <property name="width">1</property>
+                        <property name="height">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkToggleButton" id="togglebutton_knight">
+                <property name="width_request">100</property>
+                <property name="height_request">120</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_action_appearance">False</property>
+                <property name="use_underline">True</property>
+                <property name="image_position">top</property>
+                <child>
+                  <object class="GtkGrid" id="grid_knight">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="halign">center</property>
+                    <property name="valign">center</property>
+                    <property name="n_rows">2</property>
+                    <property name="n_columns">1</property>
+                    <child>
+                      <object class="GtkLabel" id="label_knight">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="label" translatable="yes">_Knight</property>
+                        <property name="use_underline">True</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">1</property>
+                        <property name="width">1</property>
+                        <property name="height">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkImage" id="image_knight">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">0</property>
+                        <property name="width">1</property>
+                        <property name="height">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkToggleButton" id="togglebutton_rook">
+                <property name="width_request">100</property>
+                <property name="height_request">120</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_action_appearance">False</property>
+                <property name="use_underline">True</property>
+                <property name="image_position">top</property>
+                <child>
+                  <object class="GtkGrid" id="grid_rook">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="halign">center</property>
+                    <property name="valign">center</property>
+                    <property name="n_rows">2</property>
+                    <property name="n_columns">1</property>
+                    <child>
+                      <object class="GtkLabel" id="label_rook">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="label" translatable="yes">_Rook</property>
+                        <property name="use_underline">True</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">1</property>
+                        <property name="width">1</property>
+                        <property name="height">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkImage" id="image_rook">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">0</property>
+                        <property name="width">1</property>
+                        <property name="height">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">2</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkToggleButton" id="togglebutton_bishop">
+                <property name="width_request">100</property>
+                <property name="height_request">120</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_action_appearance">False</property>
+                <property name="use_underline">True</property>
+                <property name="image_position">top</property>
+                <child>
+                  <object class="GtkGrid" id="grid_bishop">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="halign">center</property>
+                    <property name="valign">center</property>
+                    <property name="n_rows">2</property>
+                    <property name="n_columns">1</property>
+                    <child>
+                      <object class="GtkLabel" id="label_bishop">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="label" translatable="yes">_Bishop</property>
+                        <property name="use_underline">True</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">1</property>
+                        <property name="width">1</property>
+                        <property name="height">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkImage" id="image_bishop">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">0</property>
+                        <property name="width">1</property>
+                        <property name="height">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">3</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="label_select_promotion_type">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="has_tooltip">True</property>
+            <property name="tooltip_markup" translatable="yes">Promotion is a chess rule describing the transformation of a pawn that reaches its eighth rank into the player&amp;apos;s choice of a queen, knight, rook, or bishop of the same color. The new piece replaces the pawn on the same square and is part of the move. Every pawn that reaches its eighth rank must be promoted. Pawn promotion often decides the result of a chess endgame.</property>
+            <property name="tooltip_text" translatable="yes">Promotion is a chess rule describing the transformation of a pawn that reaches its eighth rank into the player's choice of a queen, knight, rook, or bishop of the same color. The new piece replaces the pawn on the same square and is part of the move. Every pawn that reaches its eighth rank must be promoted. Pawn promotion often decides the result of a chess endgame.</property>
+            <property name="hexpand">True</property>
+            <property name="vexpand">True</property>
+            <property name="label" translatable="yes">Select Pawn Promotion Type</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="0">togglebutton_queen</action-widget>
+      <action-widget response="1">togglebutton_knight</action-widget>
+      <action-widget response="2">togglebutton_rook</action-widget>
+      <action-widget response="3">togglebutton_bishop</action-widget>
+    </action-widgets>
+  </object>
+</interface>
diff --git a/src/chess-game.vala b/src/chess-game.vala
index 86cc5a4..a29e745 100644
--- a/src/chess-game.vala
+++ b/src/chess-game.vala
@@ -23,9 +23,29 @@ public class ChessPlayer : Object
         return do_move (move, apply);
     }
 
-    public bool move_with_coords (int r0, int f0, int r1, int f1, bool apply = true)
+    public bool move_with_coords (int r0, int f0, int r1, int f1,
+        bool apply = true, PieceType promotion_type = PieceType.QUEEN)
     {
         string move = "%c%d%c%d".printf ('a' + f0, r0 + 1, 'a' + f1, r1 + 1);    
+
+        switch (promotion_type)
+        {
+            case PieceType.QUEEN:
+                /* Default is queen so don't add anything */
+                break;
+            case PieceType.KNIGHT:
+                move += "=N";
+                break;
+            case PieceType.ROOK:
+                move += "=R";
+                break;
+            case PieceType.BISHOP:
+                move += "=B";
+                break;
+            default:
+                break;
+        }
+
         return do_move (move, apply);
     }
 
diff --git a/src/chess-scene.vala b/src/chess-scene.vala
index 6c7588d..88b5ee6 100644
--- a/src/chess-scene.vala
+++ b/src/chess-scene.vala
@@ -66,6 +66,7 @@ public class ChessScene : Object
     private double animation_time;
 
     public signal bool is_human (ChessPlayer player);
+    public signal PieceType choose_promotion_type ();
     public signal void changed ();
 
     public int selected_rank = -1;
@@ -202,6 +203,17 @@ public class ChessScene : Object
         /* Move to this square */
         else if (selected_file != -1)
         {
+            bool can_move = game.current_player.move_with_coords (selected_rank, selected_file,
+                rank, file, false);
+            if (can_move && (get_selected_piece ()).type == PieceType.PAWN &&
+                (rank == 0 || rank == 7))
+            {
+                /* Prompt user for selecting promotion type */
+                PieceType promotion_selection = choose_promotion_type ();
+                game.current_player.move_with_coords (selected_rank,
+                    selected_file, rank, file, true, promotion_selection);
+                selected_rank = selected_file = -1;
+            }
             if (game.current_player.move_with_coords(selected_rank, selected_file, rank, file))
                 selected_rank = selected_file = -1;            
         }
diff --git a/src/gnome-chess.vala b/src/gnome-chess.vala
index e7fb109..a048efc 100644
--- a/src/gnome-chess.vala
+++ b/src/gnome-chess.vala
@@ -120,6 +120,7 @@ public class Application : Gtk.Application
         scene = new ChessScene ();
         scene.is_human.connect ((p) => { return p == human_player; } );
         scene.changed.connect (scene_changed_cb);
+        scene.choose_promotion_type.connect (show_promotion_type_selector);
         settings.bind ("show-move-hints", scene, "show-move-hints", SettingsBindFlags.GET);
         settings.bind ("show-numbering", scene, "show-numbering", SettingsBindFlags.GET);
         settings.bind ("piece-theme", scene, "theme-name", SettingsBindFlags.GET);
@@ -172,6 +173,113 @@ public class Application : Gtk.Application
             opponent_engine.stop ();
     }
 
+    public PieceType show_promotion_type_selector ()
+    {
+        Gtk.Builder promotion_type_selector_builder;
+
+        promotion_type_selector_builder = new Gtk.Builder ();
+        try
+        {
+            promotion_type_selector_builder.add_from_file (Path.build_filename
+                (Config.PKGDATADIR, "promotion-type-selector.ui", null));
+        }
+        catch (Error e)
+        {
+            warning ("Could not load promotion type selector UI: %s", e.message);
+        }
+
+        Gtk.Dialog promotion_type_selector_dialog = (Gtk.Dialog)
+            promotion_type_selector_builder.get_object
+                ("dialog_promotion_type_selector");
+
+        Gtk.Widget image_queen = (Gtk.Widget) promotion_type_selector_builder.get_object ("image_queen");
+        Gtk.Widget image_knight = (Gtk.Widget) promotion_type_selector_builder.get_object ("image_knight");
+        Gtk.Widget image_rook = (Gtk.Widget) promotion_type_selector_builder.get_object ("image_rook");
+        Gtk.Widget image_bishop = (Gtk.Widget) promotion_type_selector_builder.get_object ("image_bishop");
+
+        try
+        {
+            Gtk.IconTheme icon_theme = Gtk.IconTheme.get_default ();
+            string queen_icon, knight_icon, rook_icon, bishop_icon;
+
+            /* We follow the standard FIDE rules and accordingly, the pawn can be
+             * replaced by a new queen, rook, bishop or knight of the same
+             * colour only */
+            if (game.current_player.color == Color.WHITE)
+            {
+                queen_icon = "whiteQueen";
+                knight_icon = "whiteKnight";
+                rook_icon = "whiteRook";
+                bishop_icon = "whiteBishop";
+            }
+            else
+            {
+                queen_icon = "blackQueen";
+                knight_icon = "blackKnight";
+                rook_icon = "blackRook";
+                bishop_icon = "blackBishop";
+            }
+            Gdk.Pixbuf pixbuf = icon_theme.load_icon
+                (queen_icon, 80, Gtk.IconLookupFlags.GENERIC_FALLBACK);
+            if (pixbuf != null)
+                ((Gtk.Image) image_queen).set_from_pixbuf (pixbuf);
+
+            pixbuf = icon_theme.load_icon
+                (knight_icon, 80, Gtk.IconLookupFlags.GENERIC_FALLBACK);
+            if (pixbuf != null)
+                ((Gtk.Image) image_knight).set_from_pixbuf (pixbuf);
+
+            pixbuf = icon_theme.load_icon
+                (rook_icon, 80, Gtk.IconLookupFlags.GENERIC_FALLBACK);
+            if (pixbuf != null)
+                ((Gtk.Image) image_rook).set_from_pixbuf (pixbuf);
+
+            pixbuf = icon_theme.load_icon
+                (bishop_icon, 80, Gtk.IconLookupFlags.GENERIC_FALLBACK);
+            if (pixbuf != null)
+                ((Gtk.Image) image_bishop).set_from_pixbuf (pixbuf);
+        }
+        catch (Error error)
+        {
+            warning ("Failed to load image: %s", error.message);
+        }
+
+
+        promotion_type_selector_builder.connect_signals (this);
+
+        PieceType selection;
+        int choice = promotion_type_selector_dialog.run ();
+        switch (choice)
+        {
+            case PromotionTypeSelected.QUEEN:
+                selection = PieceType.QUEEN;
+                break;
+            case PromotionTypeSelected.KNIGHT:
+                selection = PieceType.KNIGHT;
+                break;
+            case PromotionTypeSelected.ROOK:
+                selection = PieceType.ROOK;
+                break;
+            case PromotionTypeSelected.BISHOP:
+                selection = PieceType.BISHOP;
+                break;
+            default:
+                selection = PieceType.QUEEN;
+                break;
+        }
+        promotion_type_selector_dialog.destroy ();
+
+        return selection;
+    }
+
+    enum PromotionTypeSelected
+    {
+        QUEEN,
+        KNIGHT,
+        ROOK,
+        BISHOP
+    }
+
     public void quit_game ()
     {
         if (save_duration_timeout != 0)
@@ -1645,7 +1753,11 @@ class GnomeChess
         Intl.textdomain (GETTEXT_PACKAGE);
 
         Gtk.init (ref args);
-        
+
+        Gtk.IconTheme icon_theme = Gtk.IconTheme.get_default ();
+        icon_theme.append_search_path ("%s%s%s".printf
+            (Config.PKGDATADIR, Path.DIR_SEPARATOR_S, "icons"));
+
         var c = new OptionContext (/* Arguments and description for --help text */
                                    _("[FILE] - Play Chess"));
         c.add_main_entries (options, GETTEXT_PACKAGE);



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