[gnome-chess] Use composite template to build preferences dialog



commit 13f03c5e00b10ee2854cf2503003c2b47412e490
Author: Michael Catanzaro <mcatanzaro gnome org>
Date:   Thu Dec 24 16:07:31 2020 -0600

    Use composite template to build preferences dialog

 data/preferences.ui         |  88 ++++----
 src/gnome-chess.vala        | 477 +-----------------------------------------
 src/meson.build             |   1 +
 src/preferences-dialog.vala | 498 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 547 insertions(+), 517 deletions(-)
---
diff --git a/data/preferences.ui b/data/preferences.ui
index 3400541..f3f0b3b 100644
--- a/data/preferences.ui
+++ b/data/preferences.ui
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <interface>
   <requires lib="gtk" version="4.0"/>
-  <object class="GtkListStore" id="custom-duration-units-model">
+  <object class="GtkListStore" id="custom_duration_units_model">
     <columns>
       <column type="gchararray"/>
       <column type="gint"/>
@@ -17,7 +17,7 @@
       </row>
     </data>
   </object>
-  <object class="GtkListStore" id="timer-increment-units-model">
+  <object class="GtkListStore" id="timer_increment_units_model">
     <columns>
       <column type="gchararray"/>
       <column type="gint"/>
@@ -33,7 +33,7 @@
       </row>
     </data>
   </object>
-  <object class="GtkListStore" id="clock-type-model">
+  <object class="GtkListStore" id="clock_type_model">
     <columns>
       <column type="gchararray"/>
       <column type="gint"/>
@@ -53,7 +53,7 @@
       </row>
     </data>
   </object>
-  <object class="GtkListStore" id="difficulty-model">
+  <object class="GtkListStore" id="difficulty_model">
     <columns>
       <column type="gchararray"/>
       <column type="gchararray"/>
@@ -87,7 +87,7 @@
     <property name="page-increment">10</property>
     <signal name="value-changed" handler="duration_changed_cb" swapped="no"/>
   </object>
-  <object class="GtkListStore" id="duration-model">
+  <object class="GtkListStore" id="duration_model">
     <columns>
       <column type="gchararray"/>
       <column type="gint"/>
@@ -127,7 +127,7 @@
       </row>
     </data>
   </object>
-  <object class="GtkListStore" id="move-format-model">
+  <object class="GtkListStore" id="move_format_model">
     <columns>
       <column type="gchararray"/>
       <column type="gchararray"/>
@@ -151,7 +151,7 @@
       </row>
     </data>
   </object>
-  <object class="GtkListStore" id="opponent-model">
+  <object class="GtkListStore" id="opponent_model">
     <columns>
       <column type="gchararray"/>
       <column type="gchararray"/>
@@ -163,7 +163,7 @@
       </row>
     </data>
   </object>
-  <object class="GtkListStore" id="orientation-model">
+  <object class="GtkListStore" id="orientation_model">
     <columns>
       <column type="gchararray"/>
       <column type="gchararray"/>
@@ -187,7 +187,7 @@
       </row>
     </data>
   </object>
-  <object class="GtkListStore" id="piece-style-model">
+  <object class="GtkListStore" id="piece_style_model">
     <columns>
       <column type="gchararray"/>
       <column type="gchararray"/>
@@ -203,14 +203,34 @@
       </row>
     </data>
   </object>
-  <object class="GtkDialog" id="preferences">
+  <object class="GtkListStore" id="side_model">
+    <columns>
+      <column type="gchararray"/>
+      <column type="gint"/>
+    </columns>
+    <data>
+      <row>
+        <col id="0" translatable="yes" context="chess-player" comments="Preferences Dialog: Combo box entry 
for playing as white">White</col>
+        <col id="1">0</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes" context="chess-player" comments="Preferences Dialog: Combo box entry 
for playing as black">Black</col>
+        <col id="1">1</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes" context="chess-player" comments="Preferences Dialog: Combo box entry 
for alterning between black and white">Alternate</col>
+        <col id="1">2</col>
+      </row>
+    </data>
+  </object>
+  <template class="PreferencesDialog" parent="GtkDialog">
     <property name="can-focus">0</property>
     <property name="title" translatable="yes" comments="Title for preferences dialog">Preferences</property>
     <property name="resizable">0</property>
     <property name="destroy-with-parent">1</property>
     <property name="use-header-bar">1</property>
     <child>
-      <object class="GtkBox">
+      <object class="GtkBox" id="main_box">
         <property name="can-focus">0</property>
         <child>
           <object class="GtkNotebook">
@@ -244,7 +264,7 @@
                         <property name="halign">start</property>
                         <property name="label" translatable="yes" comments="Preferences Dialog: Label before 
timer increment combo box">Timer _increment:</property>
                         <property name="use-underline">1</property>
-                        <property name="mnemonic-widget">timer-increment-spin</property>
+                        <property name="mnemonic-widget">timer_increment_spin</property>
                         <layout>
                           <property name="row">6</property>
                           <property name="column">0</property>
@@ -255,7 +275,7 @@
                       <object class="GtkComboBox" id="clock_type_combo">
                         <property name="hexpand">1</property>
                         <property name="can-focus">0</property>
-                        <property name="model">clock-type-model</property>
+                        <property name="model">clock_type_model</property>
                         <signal name="changed" handler="clock_type_changed_cb" swapped="no"/>
                         <child>
                           <object class="GtkCellRendererText"/>
@@ -314,7 +334,7 @@
                         <property name="can-focus">0</property>
                         <property name="spacing">6</property>
                         <child>
-                          <object class="GtkSpinButton" id="timer-increment-spin">
+                          <object class="GtkSpinButton" id="timer_increment_spin">
                             <property name="hexpand">1</property>
                             <property name="adjustment">timer_increment_adjustment</property>
                             <property name="climb-rate">1</property>
@@ -325,7 +345,7 @@
                           <object class="GtkComboBox" id="timer_increment_units_combo">
                             <property name="hexpand">1</property>
                             <property name="can-focus">0</property>
-                            <property name="model">timer-increment-units-model</property>
+                            <property name="model">timer_increment_units_model</property>
                             <signal name="changed" handler="timer_increment_units_changed_cb" swapped="no"/>
                             <child>
                               <object class="GtkCellRendererText"/>
@@ -345,7 +365,7 @@
                       <object class="GtkComboBox" id="side_combo">
                         <property name="hexpand">1</property>
                         <property name="can-focus">0</property>
-                        <property name="model">side-model</property>
+                        <property name="model">side_model</property>
                         <signal name="changed" handler="side_combo_changed_cb" swapped="no"/>
                         <child>
                           <object class="GtkCellRendererText"/>
@@ -363,7 +383,7 @@
                       <object class="GtkComboBox" id="opponent_combo">
                         <property name="hexpand">1</property>
                         <property name="can-focus">0</property>
-                        <property name="model">opponent-model</property>
+                        <property name="model">opponent_model</property>
                         <signal name="changed" handler="opponent_combo_changed_cb" swapped="no"/>
                         <child>
                           <object class="GtkCellRendererText"/>
@@ -381,7 +401,7 @@
                       <object class="GtkComboBox" id="difficulty_combo">
                         <property name="hexpand">1</property>
                         <property name="can-focus">0</property>
-                        <property name="model">difficulty-model</property>
+                        <property name="model">difficulty_model</property>
                         <signal name="changed" handler="difficulty_combo_changed_cb" swapped="no"/>
                         <child>
                           <object class="GtkCellRendererText"/>
@@ -412,7 +432,7 @@
                           <object class="GtkComboBox" id="custom_duration_units_combo">
                             <property name="hexpand">1</property>
                             <property name="can-focus">0</property>
-                            <property name="model">custom-duration-units-model</property>
+                            <property name="model">custom_duration_units_model</property>
                             <signal name="changed" handler="duration_units_changed_cb" swapped="no"/>
                             <child>
                               <object class="GtkCellRendererText"/>
@@ -445,7 +465,7 @@
                       <object class="GtkComboBox" id="duration_combo">
                         <property name="hexpand">1</property>
                         <property name="can-focus">0</property>
-                        <property name="model">duration-model</property>
+                        <property name="model">duration_model</property>
                         <signal name="changed" handler="duration_combo_changed_cb" swapped="no"/>
                         <child>
                           <object class="GtkCellRendererText"/>
@@ -551,7 +571,7 @@
                       <object class="GtkComboBox" id="orientation_combo">
                         <property name="hexpand">1</property>
                         <property name="can-focus">0</property>
-                        <property name="model">orientation-model</property>
+                        <property name="model">orientation_model</property>
                         <signal name="changed" handler="orientation_combo_changed_cb" swapped="no"/>
                         <child>
                           <object class="GtkCellRendererText"/>
@@ -569,7 +589,7 @@
                       <object class="GtkComboBox" id="move_format_combo">
                         <property name="hexpand">1</property>
                         <property name="can-focus">0</property>
-                        <property name="model">move-format-model</property>
+                        <property name="model">move_format_model</property>
                         <signal name="changed" handler="move_format_combo_changed_cb" swapped="no"/>
                         <child>
                           <object class="GtkCellRendererText"/>
@@ -586,7 +606,7 @@
                     <child>
                       <object class="GtkComboBox" id="piece_style_combo">
                         <property name="hexpand">1</property>
-                        <property name="model">piece-style-model</property>
+                        <property name="model">piece_style_model</property>
                         <signal name="changed" handler="piece_style_combo_changed_cb" swapped="no"/>
                         <child>
                           <object class="GtkCellRendererText"/>
@@ -637,25 +657,5 @@
         </child>
       </object>
     </child>
-  </object>
-  <object class="GtkListStore" id="side-model">
-    <columns>
-      <column type="gchararray"/>
-      <column type="gint"/>
-    </columns>
-    <data>
-      <row>
-        <col id="0" translatable="yes" context="chess-player" comments="Preferences Dialog: Combo box entry 
for playing as white">White</col>
-        <col id="1">0</col>
-      </row>
-      <row>
-        <col id="0" translatable="yes" context="chess-player" comments="Preferences Dialog: Combo box entry 
for playing as black">Black</col>
-        <col id="1">1</col>
-      </row>
-      <row>
-        <col id="0" translatable="yes" context="chess-player" comments="Preferences Dialog: Combo box entry 
for alterning between black and white">Alternate</col>
-        <col id="1">2</col>
-      </row>
-    </data>
-  </object>
+  </template>
 </interface>
diff --git a/src/gnome-chess.vala b/src/gnome-chess.vala
index afdc03f..d3ca1bd 100644
--- a/src/gnome-chess.vala
+++ b/src/gnome-chess.vala
@@ -38,21 +38,9 @@ public class ChessApplication : Gtk.Application
     private Box clock_box;
     private DrawingArea white_time_label;
     private DrawingArea black_time_label;
-    private Label timer_increment_label;
     private HeaderBar headerbar;
 
-    private Dialog? preferences_dialog = null;
-    private ComboBox side_combo;
-    private ComboBox difficulty_combo;
-    private ComboBox duration_combo;
-    private ComboBox clock_type_combo;
-    private Adjustment duration_adjustment;
-    private Adjustment timer_increment_adjustment;
-    private Box custom_duration_box;
-    private Box timer_increment_box;
-    private ComboBox timer_increment_units_combo;
-    private ComboBox custom_duration_units_combo;
-    private uint save_duration_timeout = 0;
+    private PreferencesDialog? preferences_dialog = null;
     private FileChooserNative? open_dialog = null;
     private FileChooserNative? save_dialog = null;
     private delegate void PromptSaveGameCallback (bool cancelled);
@@ -308,9 +296,6 @@ Copyright © 2015–2016 Sahil Sareen""";
 
     public void quit_game ()
     {
-        if (save_duration_timeout != 0)
-            save_duration_cb ();
-
         autosave ();
 
         /* Save window state */
@@ -1735,12 +1720,7 @@ Copyright © 2015–2016 Sahil Sareen""";
         scene.move_number = -1;
     }
 
-    private void preferences_response_cb (int response_id)
-    {
-        preferences_dialog.hide ();
-    }
-
-    public void preferences_cb ()
+    private void preferences_cb ()
     {
         if (preferences_dialog != null)
         {
@@ -1748,460 +1728,11 @@ Copyright © 2015–2016 Sahil Sareen""";
             return;
         }
 
-        Builder builder = new Builder ();
-        builder.set_current_object (this);
-        try
-        {
-            builder.add_from_resource ("/org/gnome/Chess/ui/preferences.ui");
-        }
-        catch (Error e)
-        {
-            error ("Failed to load UI resource: %s", e.message);
-        }
-
-        preferences_dialog = (Dialog) builder.get_object ("preferences");
-        preferences_dialog.transient_for = window;
-        preferences_dialog.modal = true;
-
-        settings.bind ("show-numbering", builder.get_object ("show_numbering_check"),
-                       "active", SettingsBindFlags.DEFAULT);
-        settings.bind ("show-move-hints", builder.get_object ("show_move_hints_check"),
-                       "active", SettingsBindFlags.DEFAULT);
-
-        side_combo = (ComboBox) builder.get_object ("side_combo");
-        side_combo.set_active (settings.get_enum ("play-as"));
-
-        difficulty_combo = (ComboBox) builder.get_object ("difficulty_combo");
-        set_combo (difficulty_combo, 1, settings.get_string ("difficulty"));
-
-        var ai_combo = (ComboBox) builder.get_object ("opponent_combo");
-        var ai_model = (Gtk.ListStore) ai_combo.model;
-        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.get_active () == -1))
-                ai_combo.set_active_iter (iter);
-        }
-        if (ai_combo.get_active () == -1)
-        {
-            ai_combo.set_active (0);
-            settings.set_string ("opponent", "human");
-        }
-
-        duration_adjustment = (Adjustment) builder.get_object ("duration_adjustment");
-        timer_increment_adjustment = (Adjustment) builder.get_object ("timer_increment_adjustment");
-        custom_duration_box = (Box) builder.get_object ("custom_duration_box");
-        timer_increment_box = (Box) builder.get_object ("timer_increment_box");
-        custom_duration_units_combo = (ComboBox) builder.get_object ("custom_duration_units_combo");
-        timer_increment_label = (Label) builder.get_object ("timer_increment_label");
-        timer_increment_units_combo = (ComboBox) builder.get_object ("timer_increment_units_combo");
-        clock_type_combo = (ComboBox) builder.get_object ("clock_type_combo");
-        duration_combo = (ComboBox) builder.get_object ("duration_combo");
-        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;
-        }
-
-        preferences_dialog.response.connect (preferences_response_cb);
+        preferences_dialog = new PreferencesDialog (window, settings, ai_profiles);
+        preferences_dialog.response.connect (() => preferences_dialog.hide ());
         preferences_dialog.show ();
     }
 
-    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));
-    }
-
     public void help_cb ()
     {
         show_uri (window, "help:gnome-chess", Gdk.CURRENT_TIME);
diff --git a/src/meson.build b/src/meson.build
index ab69ba9..e17df79 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -4,6 +4,7 @@ chess_sources = [
   'chess-scene.vala',
   'chess-view.vala',
   'gnome-chess.vala',
+  'preferences-dialog.vala',
   'promotion-type-selector-dialog.vala',
 ]
 
diff --git a/src/preferences-dialog.vala b/src/preferences-dialog.vala
new file mode 100644
index 0000000..414d9c3
--- /dev/null
+++ b/src/preferences-dialog.vala
@@ -0,0 +1,498 @@
+/* -*- 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;
+    private unowned List<AIProfile> ai_profiles;
+    private uint save_duration_timeout = 0;
+
+    [GtkChild]
+    private unowned Gtk.Box main_box;
+    [GtkChild]
+    private unowned Gtk.CheckButton show_numbering_check;
+    [GtkChild]
+    private unowned Gtk.CheckButton show_move_hints_check;
+    [GtkChild]
+    private unowned Gtk.ComboBox side_combo;
+    [GtkChild]
+    private unowned Gtk.ComboBox difficulty_combo;
+    [GtkChild]
+    private unowned Gtk.ComboBox opponent_combo;
+    [GtkChild]
+    private unowned Gtk.ListStore opponent_model;
+    [GtkChild]
+    private unowned Gtk.Adjustment duration_adjustment;
+    [GtkChild]
+    private unowned Gtk.Adjustment timer_increment_adjustment;
+    [GtkChild]
+    private unowned Gtk.Box custom_duration_box;
+    [GtkChild]
+    private unowned Gtk.Box timer_increment_box;
+    [GtkChild]
+    private unowned Gtk.ComboBox custom_duration_units_combo;
+    [GtkChild]
+    private unowned Gtk.Label timer_increment_label;
+    [GtkChild]
+    private unowned Gtk.ComboBox timer_increment_units_combo;
+    [GtkChild]
+    private unowned Gtk.ComboBox clock_type_combo;
+    [GtkChild]
+    private unowned Gtk.ComboBox duration_combo;
+    [GtkChild]
+    private unowned Gtk.ComboBox orientation_combo;
+    [GtkChild]
+    private unowned Gtk.ComboBox move_format_combo;
+    [GtkChild]
+    private unowned Gtk.ComboBox piece_style_combo;
+
+    public PreferencesDialog (Gtk.Window window, Settings settings, List<AIProfile> ai_profiles)
+    {
+        transient_for = window;
+        modal = true;
+
+        this.settings = settings;
+        this.ai_profiles = ai_profiles;
+
+        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")
+            opponent_combo.set_active (0);
+
+        foreach (var p in ai_profiles)
+        {
+            Gtk.TreeIter iter;
+            opponent_model.append (out iter);
+            opponent_model.set (iter, 0, p.name, 1, p.name, -1);
+            if (p.name == opponent_name || (opponent_name == "" && opponent_combo.active == -1))
+                opponent_combo.set_active_iter (iter);
+        }
+
+        if (opponent_combo.active == -1)
+        {
+            opponent_combo.active = 0;
+            settings.set_string ("opponent", "human");
+        }
+
+        set_duration (settings.get_int ("duration"));
+
+        set_clock_type ((int) ClockType.string_to_enum (settings.get_string ("clock-type")));
+        set_timer_increment (settings.get_int ("timer-increment"));
+
+        set_combo (orientation_combo, 1, settings.get_string ("board-side"));
+        set_combo (move_format_combo, 1, settings.get_string ("move-format"));
+        set_combo (piece_style_combo, 1, settings.get_string ("piece-theme"));
+
+        /* Human vs. human */
+        if (opponent_combo.get_active () == 0)
+        {
+            side_combo.sensitive = false;
+            difficulty_combo.sensitive = false;
+        }
+    }
+
+    ~PreferencesDialog ()
+    {
+        if (save_duration_timeout != 0)
+        {
+            Source.remove (save_duration_timeout);
+            save_duration_cb ();
+        }
+    }
+
+    public override void dispose ()
+    {
+        if (main_box != null)
+        {
+            main_box.unparent ();
+            main_box = null;
+        }
+
+        base.dispose ();
+    }
+
+    private void set_combo (Gtk.ComboBox combo, int value_index, string value)
+    {
+        Gtk.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 (Gtk.ComboBox combo, int value_index)
+    {
+        string value;
+        Gtk.TreeIter iter;
+        if (!combo.get_active_iter (out iter))
+            return null;
+        combo.model.@get (iter, value_index, out value, -1);
+        return value;
+    }
+
+    [GtkCallback]
+    private void side_combo_changed_cb (Gtk.ComboBox combo)
+    {
+        Gtk.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);
+    }
+
+    [GtkCallback]
+    private void opponent_combo_changed_cb (Gtk.ComboBox combo)
+    {
+        Gtk.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;
+    }
+
+    [GtkCallback]
+    private void difficulty_combo_changed_cb (Gtk.ComboBox combo)
+    {
+        Gtk.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;
+        Gtk.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;
+        Gtk.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;
+        Gtk.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 ()
+    {
+        Gtk.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;
+    }
+
+    [GtkCallback]
+    private void duration_changed_cb (Gtk.Adjustment adjustment)
+    {
+        var model = (Gtk.ListStore) custom_duration_units_combo.model;
+        Gtk.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 ();
+    }
+
+    [GtkCallback]
+    private void duration_units_changed_cb (Gtk.Widget widget)
+    {
+        save_duration ();
+    }
+
+    [GtkCallback]
+    private void timer_increment_units_changed_cb (Gtk.Widget widget)
+    {
+        var model = (Gtk.ListStore) timer_increment_units_combo.model;
+        Gtk.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 bool save_duration_cb ()
+    {
+        settings.set_int ("duration", get_duration ());
+        save_duration_timeout = 0;
+        return Source.REMOVE;
+    }
+
+    private void save_duration ()
+    {
+        if (save_duration_timeout != 0)
+            Source.remove (save_duration_timeout);
+
+        /* Delay writing the value as this event will be generated a lot spinning through the value */
+        save_duration_timeout = Timeout.add (100, save_duration_cb);
+    }
+
+    [GtkCallback]
+    private void duration_combo_changed_cb (Gtk.ComboBox combo)
+    {
+        Gtk.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 ();
+    }
+
+    [GtkCallback]
+    private void clock_type_changed_cb (Gtk.ComboBox combo)
+    {
+        Gtk.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 ());
+    }
+
+    [GtkCallback]
+    private void piece_style_combo_changed_cb (Gtk.ComboBox combo)
+    {
+        settings.set_string ("piece-theme", get_combo (combo, 1));
+    }
+
+    [GtkCallback]
+    private void move_format_combo_changed_cb (Gtk.ComboBox combo)
+    {
+        settings.set_string ("move-format", get_combo (combo, 1));
+    }
+
+    [GtkCallback]
+    private void orientation_combo_changed_cb (Gtk.ComboBox combo)
+    {
+        settings.set_string ("board-side", get_combo (combo, 1));
+    }
+}


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