[gnome-chess] Use composite template to build promotion type selector
- From: Michael Catanzaro <mcatanzaro src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-chess] Use composite template to build promotion type selector
- Date: Thu, 24 Dec 2020 21:14:57 +0000 (UTC)
commit 07a6086446c0f8b8678451957e564fd60df4a6be
Author: Michael Catanzaro <mcatanzaro gnome org>
Date: Thu Dec 24 13:08:30 2020 -0600
Use composite template to build promotion type selector
This also fixes a bug that I introduced with my GTK 4 porting: the
promotion type selector dialog would always display pieces in the color
of the first player to promote a piece, but it should always change
color to match the current player.
Note that I declared all the GtkChild widgets as unowned due to
vala#1121, which I discovered while working on this.
data/chess.gresource.xml | 1 +
data/promotion-type-selector.ui | 20 +-
src/gnome-chess.vala | 187 ++++---------
src/meson.build | 2 +
src/preferences-dialog.vala | 479 ++++++++++++++++++++++++++++++++
src/promotion-type-selector-dialog.vala | 115 ++++++++
6 files changed, 655 insertions(+), 149 deletions(-)
---
diff --git a/data/chess.gresource.xml b/data/chess.gresource.xml
index 0671d8c..42d9db1 100644
--- a/data/chess.gresource.xml
+++ b/data/chess.gresource.xml
@@ -3,6 +3,7 @@
<gresource prefix="/org/gnome/Chess/ui">
<file preprocess="xml-stripblanks">gnome-chess.ui</file>
<file preprocess="xml-stripblanks">preferences.ui</file>
+ <file preprocess="xml-stripblanks">promotion-type-selector.ui</file>
</gresource>
<gresource prefix="/org/gnome/Chess/pieces">
<file preprocess="xml-stripblanks" alias="fancy/blackBishop.svg">pieces/fancy/blackBishop.svg</file>
diff --git a/data/promotion-type-selector.ui b/data/promotion-type-selector.ui
index 393656c..ac95678 100644
--- a/data/promotion-type-selector.ui
+++ b/data/promotion-type-selector.ui
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk" version="4.0"/>
- <object class="GtkDialog" id="dialog_promotion_type_selector">
+ <template class="PromotionTypeSelectorDialog" parent="GtkDialog">
<property name="can-focus">0</property>
<property name="title" translatable="yes">Select Promotion Type</property>
<property name="use-header-bar">1</property>
@@ -13,7 +13,7 @@
<property name="margin-top">6</property>
<property name="margin-bottom">6</property>
<child>
- <object class="GtkButton" id="button_queen">
+ <object class="GtkButton">
<property name="width-request">100</property>
<property name="height-request">120</property>
<property name="receives-default">1</property>
@@ -36,7 +36,7 @@
</object>
</child>
<child>
- <object class="GtkImage" id="image_queen">
+ <object class="GtkImage" id="queen_image">
<property name="can-focus">0</property>
<layout>
<property name="column">0</property>
@@ -49,7 +49,7 @@
</object>
</child>
<child>
- <object class="GtkButton" id="button_knight">
+ <object class="GtkButton">
<property name="width-request">100</property>
<property name="height-request">120</property>
<property name="receives-default">1</property>
@@ -72,7 +72,7 @@
</object>
</child>
<child>
- <object class="GtkImage" id="image_knight">
+ <object class="GtkImage" id="knight_image">
<property name="can-focus">0</property>
<layout>
<property name="column">0</property>
@@ -85,7 +85,7 @@
</object>
</child>
<child>
- <object class="GtkButton" id="button_rook">
+ <object class="GtkButton">
<property name="width-request">100</property>
<property name="height-request">120</property>
<property name="receives-default">1</property>
@@ -108,7 +108,7 @@
</object>
</child>
<child>
- <object class="GtkImage" id="image_rook">
+ <object class="GtkImage" id="rook_image">
<property name="can-focus">0</property>
<layout>
<property name="column">0</property>
@@ -121,7 +121,7 @@
</object>
</child>
<child>
- <object class="GtkButton" id="button_bishop">
+ <object class="GtkButton">
<property name="width-request">100</property>
<property name="height-request">120</property>
<property name="receives-default">1</property>
@@ -144,7 +144,7 @@
</object>
</child>
<child>
- <object class="GtkImage" id="image_bishop">
+ <object class="GtkImage" id="bishop_image">
<property name="can-focus">0</property>
<layout>
<property name="column">0</property>
@@ -161,5 +161,5 @@
</style>
</object>
</child>
- </object>
+ </template>
</interface>
diff --git a/src/gnome-chess.vala b/src/gnome-chess.vala
index 0824aa0..afdc03f 100644
--- a/src/gnome-chess.vala
+++ b/src/gnome-chess.vala
@@ -15,7 +15,7 @@ using Gtk;
public class ChessApplication : Gtk.Application
{
- private enum LayoutMode {
+ public enum LayoutMode {
NORMAL,
NARROW
}
@@ -62,7 +62,7 @@ public class ChessApplication : Gtk.Application
private MessageDialog? claim_draw_dialog = null;
private MessageDialog? resign_dialog = null;
private AboutDialog? about_dialog = null;
- private Dialog? promotion_type_selector_dialog = null;
+ private PromotionTypeSelectorDialog? promotion_type_selector_dialog = null;
private ChessScene.PromotionTypeCompletionHandler? promotion_type_completion_handler = null;
private PGNGame pgn_game;
@@ -306,143 +306,6 @@ Copyright © 2015–2016 Sahil Sareen""";
set_layout_mode (LayoutMode.NORMAL);
}
- [CCode (cname = "queen_selected_cb", instance_pos = -1)]
- public void queen_selected_cb (Button button)
- requires (promotion_type_selector_dialog != null)
- {
- promotion_type_selector_dialog.response (PromotionTypeSelected.QUEEN);
- }
-
- [CCode (cname = "knight_selected_cb", instance_pos = -1)]
- public void knight_selected_cb (Button button)
- requires (promotion_type_selector_dialog != null)
- {
- promotion_type_selector_dialog.response (PromotionTypeSelected.KNIGHT);
- }
-
- [CCode (cname = "rook_selected_cb", instance_pos = -1)]
- public void rook_selected_cb (Button button)
- requires (promotion_type_selector_dialog != null)
- {
- promotion_type_selector_dialog.response (PromotionTypeSelected.KNIGHT);
- }
-
- [CCode (cname = "bishop_selected_cb", instance_pos = -1)]
- public void bishop_selected_cb (Button button)
- requires (promotion_type_selector_dialog != null)
- {
- promotion_type_selector_dialog.response (PromotionTypeSelected.BISHOP);
- }
-
- private void promotion_type_selector_response_cb (int response_id)
- requires (promotion_type_completion_handler != null)
- {
- switch (response_id)
- {
- case PromotionTypeSelected.QUEEN:
- promotion_type_completion_handler (PieceType.QUEEN);
- break;
- case PromotionTypeSelected.KNIGHT:
- promotion_type_completion_handler (PieceType.KNIGHT);
- break;
- case PromotionTypeSelected.ROOK:
- promotion_type_completion_handler (PieceType.ROOK);
- break;
- case PromotionTypeSelected.BISHOP:
- promotion_type_completion_handler (PieceType.BISHOP);
- break;
- default:
- promotion_type_completion_handler (null);
- break;
- }
-
- promotion_type_selector_dialog.hide ();
-
- promotion_type_completion_handler = null;
- }
-
- public void show_promotion_type_selector (owned ChessScene.PromotionTypeCompletionHandler handler)
- requires (promotion_type_completion_handler == null)
- {
- if (promotion_type_selector_dialog == null)
- {
- Builder builder = new Builder ();
- builder.set_current_object (this);
- try
- {
- builder.add_from_resource ("/org/gnome/Chess/ui/promotion-type-selector.ui");
- }
- catch (Error e)
- {
- error ("Failed to load UI resource: %s", e.message);
- }
-
- promotion_type_selector_dialog = (Dialog) builder.get_object ("dialog_promotion_type_selector");
- promotion_type_selector_dialog.transient_for = window;
- promotion_type_selector_dialog.modal = true;
-
- var button_box = (Box) builder.get_object ("button_box");
- if (layout_mode == LayoutMode.NARROW)
- button_box.orientation = Orientation.VERTICAL;
-
- string color;
- if (game.current_player.color == Color.WHITE)
- color = "white";
- else
- color = "black";
-
- var resource_path = Path.build_path ("/", "/org/gnome/Chess/pieces", scene.theme_name,
"%sQueen.svg".printf (color));
- set_piece_image ((Image) builder.get_object ("image_queen"), resource_path);
-
- resource_path = Path.build_path ("/", "/org/gnome/Chess/pieces", scene.theme_name,
"%sKnight.svg".printf (color));
- set_piece_image ((Image) builder.get_object ("image_knight"), resource_path);
-
- resource_path = Path.build_path ("/", "/org/gnome/Chess/pieces", scene.theme_name,
"%sRook.svg".printf (color));
- set_piece_image ((Image) builder.get_object ("image_rook"), resource_path);
-
- resource_path = Path.build_path ("/", "/org/gnome/Chess/pieces", scene.theme_name,
"%sBishop.svg".printf (color));
- set_piece_image ((Image) builder.get_object ("image_bishop"), resource_path);
-
- promotion_type_selector_dialog.response.connect (promotion_type_selector_response_cb);
- }
-
- promotion_type_selector_dialog.show ();
-
- promotion_type_completion_handler = (type) => handler (type);
- }
-
- private void set_piece_image (Image image, string resource_path)
- {
- const int size = 48;
-
- try
- {
- var stream = resources_open_stream (resource_path, ResourceLookupFlags.NONE);
- var h = new Rsvg.Handle.from_stream_sync (stream, null, Rsvg.HandleFlags.FLAGS_NONE, null);
-
- var s = new Cairo.ImageSurface (Cairo.Format.ARGB32, size, size);
- var c = new Cairo.Context (s);
- h.render_document (c, Rsvg.Rectangle () { width = size, height = size, x = 0, y = 0 });
-
- var p = Gdk.pixbuf_get_from_surface (s, 0, 0, size, size);
- image.set_from_pixbuf (p);
-
- image.height_request = size;
- }
- catch (Error e)
- {
- warning ("Failed to load image %s: %s", resource_path, e.message);
- }
- }
-
- enum PromotionTypeSelected
- {
- QUEEN,
- KNIGHT,
- ROOK,
- BISHOP
- }
-
public void quit_game ()
{
if (save_duration_timeout != 0)
@@ -2372,6 +2235,52 @@ Copyright © 2015–2016 Sahil Sareen""";
about_dialog.show ();
}
+ private void promotion_type_selector_response_cb (int response_id)
+ requires (promotion_type_completion_handler != null)
+ {
+ switch (response_id)
+ {
+ case PromotionTypeSelectorDialog.SelectedType.QUEEN:
+ promotion_type_completion_handler (PieceType.QUEEN);
+ break;
+ case PromotionTypeSelectorDialog.SelectedType.KNIGHT:
+ promotion_type_completion_handler (PieceType.KNIGHT);
+ break;
+ case PromotionTypeSelectorDialog.SelectedType.ROOK:
+ promotion_type_completion_handler (PieceType.ROOK);
+ break;
+ case PromotionTypeSelectorDialog.SelectedType.BISHOP:
+ promotion_type_completion_handler (PieceType.BISHOP);
+ break;
+ default:
+ promotion_type_completion_handler (null);
+ break;
+ }
+
+ /* We cannot cache this dialog because it uses the piece color of the current player. */
+ promotion_type_selector_dialog.destroy ();
+ promotion_type_selector_dialog = null;
+
+ promotion_type_completion_handler = null;
+ }
+
+ private void show_promotion_type_selector (owned ChessScene.PromotionTypeCompletionHandler handler)
+ requires (promotion_type_completion_handler == null)
+ {
+ if (promotion_type_selector_dialog == null)
+ {
+ promotion_type_selector_dialog = new PromotionTypeSelectorDialog (window,
+ game.current_player.color,
+ scene.theme_name,
+ layout_mode);
+ promotion_type_selector_dialog.response.connect (promotion_type_selector_response_cb);
+ }
+
+ promotion_type_selector_dialog.show ();
+
+ promotion_type_completion_handler = (type) => handler (type);
+ }
+
private void run_invalid_pgn_dialog ()
{
var invalid_pgn_dialog = new MessageDialog (window,
diff --git a/src/meson.build b/src/meson.build
index b2daee6..ab69ba9 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -4,10 +4,12 @@ chess_sources = [
'chess-scene.vala',
'chess-view.vala',
'gnome-chess.vala',
+ 'promotion-type-selector-dialog.vala',
]
chess_vala_args = [
'--target-glib=@0@'.format(min_glib_version),
+ '--gresources', resource_files,
]
chess_c_args = [
diff --git a/src/preferences-dialog.vala b/src/preferences-dialog.vala
new file mode 100644
index 0000000..f197a42
--- /dev/null
+++ b/src/preferences-dialog.vala
@@ -0,0 +1,479 @@
+/* -*- Mode: vala; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * Copyright (C) 2010-2013 Robert Ancell
+ * Copyright (C) 2013-2020 Michael Catanzaro
+ *
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
+ * license.
+ */
+
+[GtkTemplate (ui = "/org/gnome/Chess/ui/preferences.ui")]
+public class PreferencesDialog : Gtk.Dialog
+{
+ private Settings settings;
+
+ [GtkChild]
+ private Gtk.CheckButton show_numbering_check;
+ [GtkChild]
+ private Gtk.CheckButton show_move_hints_check;
+ [GtkChild]
+ private Gtk.ComboBox side_combo;
+ [GtkChild]
+ private Gtk.ComboBox difficulty_combo;
+ [GtkChild]
+ private Gtk.ComboBox ai_combo;
+ [GtkChild]
+ private Gtk.ListStore ai_model;
+ [GtkChild]
+ private Gtk.Adjustment duration_adjustment;
+ [GtkChild]
+ private Gtk.Adjustment timer_increment_adjustment;
+ [GtkChild]
+ private Gtk.Box custom_duration_box;
+ [GtkChild]
+ private Gtk.Box timer_increment_box;
+ [GtkChild]
+ private Gtk.ComboBox custom_duration_units_combo;
+ [GtkChild]
+ private Gtk.Label timer_increment_label;
+ [GtkChild]
+ private Gtk.ComboBox timer_increment_units_combo;
+ [GtkChild]
+ private Gtk.ComboBox clock_type_combo;
+ [GtkChild]
+ private Gtk.ComboBox duration_combo;
+
+ public PreferencesDialog (Settings settings)
+ {
+ preferences_dialog.transient_for = window;
+ preferences_dialog.modal = true;
+
+ this.settings = settings;
+
+ settings.bind ("show-numbering", show_numbering_check,
+ "active", SettingsBindFlags.DEFAULT);
+ settings.bind ("show-move-hints", show_move_hints_check,
+ "active", SettingsBindFlags.DEFAULT);
+
+ side_combo.set_active (settings.get_enum ("play-as"));
+ set_combo (difficulty_combo, 1, settings.get_string ("difficulty"));
+
+ var opponent_name = settings.get_string ("opponent");
+ if (opponent_name == "human")
+ ai_combo.set_active (0);
+
+ foreach (var p in ai_profiles)
+ {
+ TreeIter iter;
+ ai_model.append (out iter);
+ ai_model.set (iter, 0, p.name, 1, p.name, -1);
+ if (p.name == opponent_name || (opponent_name == "" && ai_combo.active == -1))
+ ai_combo.set_active_iter (iter);
+ }
+
+ if (ai_combo.active == -1)
+ {
+ ai_combo.active = 0;
+ settings.set_string ("opponent", "human");
+ }
+
+ set_duration (settings.get_int ("duration"));
+
+ if (pgn_game.clock_type != null)
+ set_clock_type (ClockType.string_to_enum (pgn_game.clock_type));
+ else
+ set_clock_type ((int) ClockType.string_to_enum (settings.get_string ("clock-type")));
+
+ if (pgn_game.timer_increment != null)
+ set_timer_increment (int.parse (pgn_game.timer_increment));
+ else
+ set_timer_increment (settings.get_int ("timer-increment"));
+
+ var orientation_combo = (ComboBox) builder.get_object ("orientation_combo");
+ set_combo (orientation_combo, 1, settings.get_string ("board-side"));
+
+ var move_combo = (ComboBox) builder.get_object ("move_format_combo");
+ set_combo (move_combo, 1, settings.get_string ("move-format"));
+
+ var theme_combo = (ComboBox) builder.get_object ("piece_style_combo");
+ set_combo (theme_combo, 1, settings.get_string ("piece-theme"));
+
+ /* Human vs. human */
+ if (ai_combo.get_active () == 0)
+ {
+ side_combo.sensitive = false;
+ difficulty_combo.sensitive = false;
+ }
+ }
+
+ private void set_combo (ComboBox combo, int value_index, string value)
+ {
+ TreeIter iter;
+ var model = combo.model;
+ if (!model.get_iter_first (out iter))
+ return;
+ do
+ {
+ string v;
+ model.@get (iter, value_index, out v, -1);
+ if (v == value)
+ {
+ combo.set_active_iter (iter);
+ return;
+ }
+ } while (model.iter_next (ref iter));
+ }
+
+ private string? get_combo (ComboBox combo, int value_index)
+ {
+ string value;
+ TreeIter iter;
+ if (!combo.get_active_iter (out iter))
+ return null;
+ combo.model.@get (iter, value_index, out value, -1);
+ return value;
+ }
+
+ [CCode (cname = "side_combo_changed_cb", instance_pos = -1)]
+ public void side_combo_changed_cb (ComboBox combo)
+ {
+ TreeIter iter;
+ if (!combo.get_active_iter (out iter))
+ return;
+ int player;
+ combo.model.@get (iter, 1, out player, -1);
+
+ settings.set_enum ("play-as", player);
+ }
+
+ [CCode (cname = "opponent_combo_changed_cb", instance_pos = -1)]
+ public void opponent_combo_changed_cb (ComboBox combo)
+ {
+ TreeIter iter;
+ if (!combo.get_active_iter (out iter))
+ return;
+ string opponent;
+ combo.model.@get (iter, 1, out opponent, -1);
+ settings.set_string ("opponent", opponent);
+ bool vs_human = (combo.get_active () == 0);
+ side_combo.sensitive = !vs_human;
+ difficulty_combo.sensitive = !vs_human;
+ }
+
+ [CCode (cname = "difficulty_combo_changed_cb", instance_pos = -1)]
+ public void difficulty_combo_changed_cb (ComboBox combo)
+ {
+ TreeIter iter;
+ if (!combo.get_active_iter (out iter))
+ return;
+ string difficulty;
+ combo.model.@get (iter, 1, out difficulty, -1);
+ settings.set_string ("difficulty", difficulty);
+ }
+
+ private void set_clock_type (int clock_type)
+ {
+ var model = clock_type_combo.model;
+ TreeIter iter, active_iter_clock_type = {};
+
+ /* Find the largest units that can be used for this value */
+ if (model.get_iter_first (out iter))
+ {
+ do
+ {
+ int type;
+ model.@get (iter, 1, out type, -1);
+ if (type == clock_type)
+ {
+ active_iter_clock_type = iter;
+ }
+ } while (model.iter_next (ref iter));
+ }
+
+ clock_type_combo.set_active_iter (active_iter_clock_type);
+ clock_type_changed_cb (clock_type_combo);
+ }
+
+ private void set_timer_increment (int timer_increment)
+ {
+ int timer_increment_multiplier = 1;
+
+ if (timer_increment >= 60)
+ {
+ timer_increment_adjustment.value = timer_increment / 60;
+ timer_increment_multiplier = 60;
+ } else
+ timer_increment_adjustment.value = timer_increment;
+
+ var model = timer_increment_units_combo.model;
+ TreeIter iter, reqd_iter = {};
+
+ /* Find the largest units that can be used for this value */
+ if (model.get_iter_first (out iter))
+ {
+ do
+ {
+ int multiplier;
+ model.@get (iter, 1, out multiplier, -1);
+ if (multiplier == timer_increment_multiplier)
+ {
+ reqd_iter = iter;
+ }
+ } while (model.iter_next (ref iter));
+ }
+
+ timer_increment_units_combo.set_active_iter (reqd_iter);
+ timer_increment_units_changed_cb (timer_increment_units_combo);
+ }
+
+ private void set_duration (int duration, bool simplify = true)
+ {
+ var model = custom_duration_units_combo.model;
+ TreeIter iter, max_iter = {};
+
+ /* Find the largest units that can be used for this value */
+ int max_multiplier = 0;
+ if (model.get_iter_first (out iter))
+ {
+ do
+ {
+ int multiplier;
+ model.@get (iter, 1, out multiplier, -1);
+ if (multiplier > max_multiplier && duration % multiplier == 0)
+ {
+ max_multiplier = multiplier;
+ max_iter = iter;
+ }
+ } while (model.iter_next (ref iter));
+ }
+
+ /* Set the spin button to the value with the chosen units */
+ var value = 0;
+ if (max_multiplier > 0)
+ {
+ value = duration / max_multiplier;
+ duration_adjustment.value = value;
+ custom_duration_units_combo.set_active_iter (max_iter);
+ }
+
+ if (!simplify)
+ return;
+
+ model = duration_combo.model;
+ if (!model.get_iter_first (out iter))
+ return;
+ do
+ {
+ int v;
+ model.@get (iter, 1, out v, -1);
+ if (v == duration || v == -1)
+ {
+ duration_combo.set_active_iter (iter);
+ custom_duration_box.visible = v == -1;
+ return;
+ }
+ } while (model.iter_next (ref iter));
+ }
+
+ private int get_duration ()
+ {
+ TreeIter iter;
+ if (duration_combo.get_active_iter (out iter))
+ {
+ int duration;
+ duration_combo.model.@get (iter, 1, out duration, -1);
+ if (duration >= 0)
+ return duration;
+ }
+
+ var magnitude = (int) duration_adjustment.value;
+ int multiplier = 1;
+ if (custom_duration_units_combo.get_active_iter (out iter))
+ custom_duration_units_combo.model.@get (iter, 1, out multiplier, -1);
+
+ switch (multiplier)
+ {
+ case 60:
+ if (duration_adjustment.get_upper () != 600)
+ duration_adjustment.set_upper (600);
+ break;
+ case 3600:
+ if (duration_adjustment.get_upper () != 10)
+ {
+ duration_adjustment.set_upper (10);
+ if (duration_adjustment.value > 10)
+ {
+ duration_adjustment.value = 10;
+ magnitude = 10;
+ }
+ }
+ break;
+ default:
+ assert_not_reached ();
+ }
+
+ return magnitude * multiplier;
+ }
+
+ private bool save_duration_cb ()
+ {
+ settings.set_int ("duration", get_duration ());
+ Source.remove (save_duration_timeout);
+ save_duration_timeout = 0;
+ return Source.REMOVE;
+ }
+
+ [CCode (cname = "duration_changed_cb", instance_pos = -1)]
+ public void duration_changed_cb (Adjustment adjustment)
+ {
+ var model = (Gtk.ListStore) custom_duration_units_combo.model;
+ TreeIter iter;
+ /* Set the unit labels to the correct plural form */
+ if (model.get_iter_first (out iter))
+ {
+ do
+ {
+ int multiplier;
+ model.@get (iter, 1, out multiplier, -1);
+ switch (multiplier)
+ {
+ case 60:
+ model.set (iter, 0, ngettext (/* Preferences Dialog: Combo box entry for a custom game
timer set in minutes */
+ "minute", "minutes", (ulong) adjustment.value), -1);
+ break;
+ case 3600:
+ model.set (iter, 0, ngettext (/* Preferences Dialog: Combo box entry for a custom game
timer set in hours */
+ "hour", "hours", (ulong) adjustment.value), -1);
+ break;
+ default:
+ assert_not_reached ();
+ }
+ } while (model.iter_next (ref iter));
+ }
+
+ save_duration ();
+ }
+
+ [CCode (cname = "duration_units_changed_cb", instance_pos = -1)]
+ public void duration_units_changed_cb (Widget widget)
+ {
+ save_duration ();
+ }
+
+ [CCode (cname = "timer_increment_units_changed_cb", instance_pos = -1)]
+ public void timer_increment_units_changed_cb (Widget widget)
+ {
+ var model = (Gtk.ListStore) timer_increment_units_combo.model;
+ TreeIter iter;
+ int multiplier = 0;
+ /* Set the unit labels to the correct plural form */
+ if (model.get_iter_first (out iter))
+ {
+ do
+ {
+ model.@get (iter, 1, out multiplier, -1);
+ switch (multiplier)
+ {
+ case 1:
+ model.set (iter, 0, ngettext (/* Preferences Dialog: Combo box entry for a custom clock
type set in seconds */
+ "second", "seconds", (ulong)
timer_increment_adjustment.value), -1);
+ break;
+ case 60:
+ model.set (iter, 0, ngettext (/* Preferences Dialog: Combo box entry for a custom clock
type set in minutes */
+ "minute", "minutes", (ulong)
timer_increment_adjustment.value), -1);
+ break;
+ default:
+ assert_not_reached ();
+ }
+ } while (model.iter_next (ref iter));
+ }
+
+ if (timer_increment_units_combo.get_active_iter (out iter))
+ timer_increment_units_combo.model.@get (iter, 1, out multiplier, -1);
+
+ switch (multiplier)
+ {
+ case 1:
+ if (timer_increment_adjustment.get_upper () != 59)
+ timer_increment_adjustment.set_upper (59);
+ break;
+ case 60:
+ if (timer_increment_adjustment.get_upper () != 10)
+ {
+ timer_increment_adjustment.set_upper (10);
+ if (timer_increment_adjustment.value > 10)
+ timer_increment_adjustment.value = 10;
+ }
+ break;
+ default:
+ assert_not_reached ();
+ }
+ settings.set_int ("timer-increment", (int) timer_increment_adjustment.value * multiplier);
+ }
+
+ private void save_duration ()
+ {
+ /* Delay writing the value as it this event will be generated a lot spinning through the value */
+ if (save_duration_timeout != 0)
+ Source.remove (save_duration_timeout);
+ save_duration_timeout = Timeout.add (100, save_duration_cb);
+ }
+
+ [CCode (cname = "duration_combo_changed_cb", instance_pos = -1)]
+ public void duration_combo_changed_cb (ComboBox combo)
+ {
+ TreeIter iter;
+ if (!combo.get_active_iter (out iter))
+ return;
+ int duration;
+ combo.model.@get (iter, 1, out duration, -1);
+ custom_duration_box.visible = duration < 0;
+ clock_type_combo.sensitive = duration != 0;
+
+ if (duration == 0)
+ set_clock_type (ClockType.SIMPLE);
+
+ if (duration >= 0)
+ set_duration (duration, false);
+ /* Default to one hour (30 minutes/player) when setting custom duration */
+ else if (get_duration () <= 0)
+ set_duration (60 * 60, false);
+
+ save_duration ();
+ }
+
+ [CCode (cname = "clock_type_changed_cb", instance_pos = -1)]
+ public void clock_type_changed_cb (ComboBox combo)
+ {
+ TreeIter iter;
+ if (!combo.get_active_iter (out iter))
+ return;
+ ClockType clock_type;
+ combo.model.@get (iter, 1, out clock_type, -1);
+
+ timer_increment_box.visible = clock_type > 0;
+ timer_increment_label.visible = clock_type > 0;
+ settings.set_string ("clock-type", clock_type.to_string ());
+ }
+
+ [CCode (cname = "piece_style_combo_changed_cb", instance_pos = -1)]
+ public void piece_style_combo_changed_cb (ComboBox combo)
+ {
+ settings.set_string ("piece-theme", get_combo (combo, 1));
+ }
+
+ [CCode (cname = "move_format_combo_changed_cb", instance_pos = -1)]
+ public void move_format_combo_changed_cb (ComboBox combo)
+ {
+ settings.set_string ("move-format", get_combo (combo, 1));
+ }
+
+ [CCode (cname = "orientation_combo_changed_cb", instance_pos = -1)]
+ public void orientation_combo_changed_cb (ComboBox combo)
+ {
+ settings.set_string ("board-side", get_combo (combo, 1));
+ }
+}
diff --git a/src/promotion-type-selector-dialog.vala b/src/promotion-type-selector-dialog.vala
new file mode 100644
index 0000000..73ea536
--- /dev/null
+++ b/src/promotion-type-selector-dialog.vala
@@ -0,0 +1,115 @@
+/* -*- Mode: vala; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * Copyright (C) 2010-2013 Robert Ancell
+ * Copyright (C) 2013-2020 Michael Catanzaro
+ *
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
+ * license.
+ */
+
+[GtkTemplate (ui = "/org/gnome/Chess/ui/promotion-type-selector.ui")]
+public class PromotionTypeSelectorDialog : Gtk.Dialog
+{
+ enum SelectedType
+ {
+ QUEEN,
+ KNIGHT,
+ ROOK,
+ BISHOP
+ }
+
+ [GtkChild]
+ private unowned Gtk.Box? button_box;
+ [GtkChild]
+ private unowned Gtk.Image queen_image;
+ [GtkChild]
+ private unowned Gtk.Image knight_image;
+ [GtkChild]
+ private unowned Gtk.Image rook_image;
+ [GtkChild]
+ private unowned Gtk.Image bishop_image;
+
+ public PromotionTypeSelectorDialog (Gtk.Window window, Color color, string theme,
ChessApplication.LayoutMode layout_mode)
+ {
+ transient_for = window;
+ modal = true;
+
+ if (layout_mode == ChessApplication.LayoutMode.NARROW)
+ button_box.orientation = Gtk.Orientation.VERTICAL;
+
+ var color_string = color == Color.WHITE ? "white" : "black";
+ var resource_path = Path.build_path ("/", "/org/gnome/Chess/pieces", theme, "%sQueen.svg".printf
(color_string));
+ set_piece_image (queen_image, resource_path);
+
+ resource_path = Path.build_path ("/", "/org/gnome/Chess/pieces", theme, "%sKnight.svg".printf
(color_string));
+ set_piece_image (knight_image, resource_path);
+
+ resource_path = Path.build_path ("/", "/org/gnome/Chess/pieces", theme, "%sRook.svg".printf
(color_string));
+ set_piece_image (rook_image, resource_path);
+
+ resource_path = Path.build_path ("/", "/org/gnome/Chess/pieces", theme, "%sBishop.svg".printf
(color_string));
+ set_piece_image (bishop_image, resource_path);
+ }
+
+ public override void dispose ()
+ {
+ if (button_box != null)
+ {
+ button_box.unparent ();
+ button_box = null;
+ }
+
+ base.dispose ();
+ }
+
+ private void set_piece_image (Gtk.Image image, string resource_path)
+ {
+ const int size = 48;
+
+ try
+ {
+ var stream = resources_open_stream (resource_path, ResourceLookupFlags.NONE);
+ var h = new Rsvg.Handle.from_stream_sync (stream, null, Rsvg.HandleFlags.FLAGS_NONE, null);
+
+ var s = new Cairo.ImageSurface (Cairo.Format.ARGB32, size, size);
+ var c = new Cairo.Context (s);
+ h.render_document (c, Rsvg.Rectangle () { width = size, height = size, x = 0, y = 0 });
+
+ var p = Gdk.pixbuf_get_from_surface (s, 0, 0, size, size);
+ image.set_from_pixbuf (p);
+
+ image.height_request = size;
+ }
+ catch (Error e)
+ {
+ warning ("Failed to load piece image %s: %s", resource_path, e.message);
+ }
+ }
+
+ [GtkCallback]
+ private void queen_selected_cb (Gtk.Button button)
+ {
+ response (SelectedType.QUEEN);
+ }
+
+ [GtkCallback]
+ private void knight_selected_cb (Gtk.Button button)
+ {
+ response (SelectedType.KNIGHT);
+ }
+
+ [GtkCallback]
+ private void rook_selected_cb (Gtk.Button button)
+ {
+ response (SelectedType.ROOK);
+ }
+
+ [GtkCallback]
+ private void bishop_selected_cb (Gtk.Button button)
+ {
+ response (SelectedType.BISHOP);
+ }
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]