[gnome-nibbles] Add preferences dialog



commit 1eef395622bf94fb4ebe929a8b06f0d97a0f2278
Author: Gabriel Ivascu <ivascu gabriel59 gmail com>
Date:   Mon Dec 28 13:35:18 2015 +0200

    Add preferences dialog
    
    https://bugzilla.gnome.org/show_bug.cgi?id=757872

 data/Makefile.am                   |    3 +-
 data/org.gnome.nibbles.gschema.xml |   11 +
 data/preferences-dialog.ui         |  572 ++++++++++++++++++++++++++++++++++++
 src/Makefile.am                    |    1 +
 src/gnome-nibbles.gresource.xml.in |    1 +
 src/gnome-nibbles.vala             |   95 ++++++
 src/nibbles-game.vala              |   10 +-
 src/preferences-dialog.vala        |  285 ++++++++++++++++++
 8 files changed, 975 insertions(+), 3 deletions(-)
---
diff --git a/data/Makefile.am b/data/Makefile.am
index 46a2061..fcd2d3c 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -21,7 +21,8 @@ dist_noinst_DATA = \
        nibbles.css \
        scoreboard.ui \
        player-score-box.ui \
-       controls-grid.ui
+       controls-grid.ui \
+       preferences-dialog.ui
 
 soundsdir = $(datadir)/gnome-nibbles/sounds
 dist_sounds_DATA = \
diff --git a/data/org.gnome.nibbles.gschema.xml b/data/org.gnome.nibbles.gschema.xml
index c897ad1..53ae856 100644
--- a/data/org.gnome.nibbles.gschema.xml
+++ b/data/org.gnome.nibbles.gschema.xml
@@ -32,11 +32,22 @@
       <summary>Game level to start on</summary>
       <description>Game level to start on.</description>
     </key>
+    <key name="speed" type="i">
+      <default>2</default>
+      <range min="1" max="4"/>
+      <summary>Worms movement speed</summary>
+      <description>Worms movement speed.</description>
+    </key>
     <key name="sound" type="b">
       <default>true</default>
       <summary>Enable sounds</summary>
       <description>Enable sounds.</description>
     </key>
+    <key name="fakes" type="b">
+      <default>false</default>
+      <summary>Enable fake bonuses</summary>
+      <description>Enable fake bonuses.</description>
+    </key>
   </schema>
   <schema id="org.gnome.nibbles.worm0" path="/org/gnome/nibbles/worm0/">
     <key name="color" type="s">
diff --git a/data/preferences-dialog.ui b/data/preferences-dialog.ui
new file mode 100644
index 0000000..d107d01
--- /dev/null
+++ b/data/preferences-dialog.ui
@@ -0,0 +1,572 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <template class="PreferencesDialog" parent="GtkDialog">
+    <property name="can_focus">False</property>
+    <property name="border_width">5</property>
+    <property name="modal">True</property>
+    <property name="title" translatable="yes">Preferences</property>
+    <property name="icon_name">gnome-nibbles</property>
+    <child internal-child="vbox">
+      <object class="GtkVBox" id="dialog_vbox">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="spacing">2</property>
+        <child>
+          <object class="GtkNotebook" id="notebook">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <child>
+              <object class="GtkBox" id="box_general">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="border_width">12</property>
+                <property name="spacing">50</property>
+                <property name="orientation">horizontal</property>
+                <property name="homogeneous">True</property>
+                <child>
+                  <object class="GtkBox" id="box_speed">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="border_width">0</property>
+                    <property name="spacing">4</property>
+                    <property name="orientation">vertical</property>
+                    <child>
+                      <object class="GtkLabel" id="speed_label">
+                        <property name="label" translatable="yes">Speed</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="xalign">0.5</property>
+                        <property name="yalign">0.5</property>
+                        <property name="halign">start</property>
+                        <attributes>
+                          <attribute name="weight" value="bold"/>
+                        </attributes>
+                      </object>
+                      <packing>
+                        <property name="pack-type">start</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkRadioButton" id="fast_radio_button">
+                        <property name="use-underline">True</property>
+                        <property name="label" translatable="yes">_Fast</property>
+                        <property name="visible">True</property>
+                        <property name="yalign">0.5</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">False</property>
+                        <property name="active">False</property>
+                        <property name="draw_indicator">True</property>
+                      </object>
+                      <packing>
+                        <property name="pack-type">start</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkRadioButton" id="medium_radio_button">
+                        <property name="use-underline">True</property>
+                        <property name="label" translatable="yes">_Medium</property>
+                        <property name="visible">True</property>
+                        <property name="yalign">0.5</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">False</property>
+                        <property name="active">False</property>
+                        <property name="draw_indicator">True</property>
+                        <property name="group">fast_radio_button</property>
+                      </object>
+                      <packing>
+                        <property name="pack-type">start</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkRadioButton" id="slow_radio_button">
+                        <property name="use-underline">True</property>
+                        <property name="label" translatable="yes">_Slow</property>
+                        <property name="visible">True</property>
+                        <property name="yalign">0.5</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">False</property>
+                        <property name="active">False</property>
+                        <property name="draw_indicator">True</property>
+                        <property name="group">fast_radio_button</property>
+                      </object>
+                      <packing>
+                        <property name="pack-type">start</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkRadioButton" id="beginner_radio_button">
+                        <property name="use-underline">True</property>
+                        <property name="label" translatable="yes">_Beginner</property>
+                        <property name="visible">True</property>
+                        <property name="yalign">0.5</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">False</property>
+                        <property name="active">False</property>
+                        <property name="draw_indicator">True</property>
+                        <property name="group">fast_radio_button</property>
+                      </object>
+                      <packing>
+                        <property name="pack-type">start</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="pack-type">start</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkBox" id="box_options">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="border_width">0</property>
+                    <property name="spacing">7</property>
+                    <property name="orientation">vertical</property>
+                    <child>
+                      <object class="GtkLabel" id="options_label">
+                        <property name="label" translatable="yes">Options</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="xalign">0.5</property>
+                        <property name="yalign">0.5</property>
+                        <property name="halign">start</property>
+                        <attributes>
+                          <attribute name="weight" value="bold"/>
+                        </attributes>
+                      </object>
+                      <packing>
+                        <property name="pack-type">start</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkCheckButton" id="sound_check_button">
+                        <property name="use-underline">True</property>
+                        <property name="label" translatable="yes">E_nable sounds</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="yalign">0.5</property>
+                      </object>
+                      <packing>
+                        <property name="pack-type">start</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkCheckButton" id="fakes_check_button">
+                        <property name="use-underline">True</property>
+                        <property name="label" translatable="yes">_Enable fake bonuses</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="yalign">0.5</property>
+                      </object>
+                      <packing>
+                        <property name="pack-type">start</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="pack-type">start</property>
+                  </packing>
+                </child>
+              </object>
+            </child>
+            <child type="tab">
+              <object class="GtkLabel" id="label_general">
+                <property name="use-underline">True</property>
+                <property name="label" translatable="yes">_General</property>
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+              </object>
+              <packing>
+                <property name="tab_fill">False</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkBox" id="box_worm_1">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="border_width">12</property>
+                <property name="spacing">6</property>
+                <property name="orientation">vertical</property>
+                <child>
+                  <object class="GtkLabel" id="controls_label_1">
+                    <property name="label" translatable="yes">Controls</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">0.5</property>
+                    <property name="yalign">0.5</property>
+                    <property name="halign">start</property>
+                    <attributes>
+                      <attribute name="weight" value="bold"/>
+                    </attributes>
+                  </object>
+                  <packing>
+                    <property name="pack-type">start</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkListStore" id="list_store_1">
+                    <columns>
+                      <column type="gchararray"/>
+                      <column type="gchararray"/>
+                      <column type="gint"/>
+                    </columns>
+                  </object>
+                  <object class="GtkTreeView" id="tree_view_1">
+                    <property name="model">list_store_1</property>
+                    <property name="visible">True</property>
+                  </object>
+                </child>
+                <child>
+                  <object class="GtkSeparator" id="separator_1">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="orientation">horizontal</property>
+                  </object>
+                  <packing>
+                    <property name="pack-type">start</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkGrid" id="color_grid_1">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="row_spacing">0</property>
+                    <property name="column_spacing">12</property>
+                    <property name="border_width">0</property>
+                    <child>
+                      <object class="GtkLabel" id="color_label_1">
+                        <property name="label" translatable="yes">Worm color</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="xalign">0.5</property>
+                        <property name="yalign">0.5</property>
+                        <property name="halign">start</property>
+                        <attributes>
+                          <attribute name="weight" value="bold"/>
+                        </attributes>
+                      </object>
+                      <packing>
+                        <property name="left-attach">0</property>
+                        <property name="top-attach">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkComboBoxText" id="combo_box_1">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                      </object>
+                      <packing>
+                        <property name="left-attach">1</property>
+                        <property name="top-attach">0</property>
+                      </packing>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+            <child type="tab">
+              <object class="GtkLabel" id="label_worm_1">
+                <property name="use-underline">True</property>
+                <property name="label" translatable="yes">Worm _1</property>
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+              </object>
+              <packing>
+                <property name="tab_fill">False</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkBox" id="box_worm_2">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="border_width">12</property>
+                <property name="spacing">6</property>
+                <property name="orientation">vertical</property>
+                <child>
+                  <object class="GtkLabel" id="controls_label_2">
+                    <property name="label" translatable="yes">Controls</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">0.5</property>
+                    <property name="yalign">0.5</property>
+                    <property name="halign">start</property>
+                    <attributes>
+                      <attribute name="weight" value="bold"/>
+                    </attributes>
+                  </object>
+                  <packing>
+                    <property name="pack-type">start</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkListStore" id="list_store_2">
+                    <columns>
+                      <column type="gchararray"/>
+                      <column type="gchararray"/>
+                      <column type="guint"/>
+                    </columns>
+                  </object>
+                  <object class="GtkTreeView" id="tree_view_2">
+                    <property name="model">list_store_2</property>
+                    <property name="visible">True</property>
+                  </object>
+                </child>
+                <child>
+                  <object class="GtkSeparator" id="separator_2">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="orientation">horizontal</property>
+                  </object>
+                  <packing>
+                    <property name="pack-type">start</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkGrid" id="color_grid_2">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="row_spacing">0</property>
+                    <property name="column_spacing">12</property>
+                    <property name="border_width">0</property>
+                    <child>
+                      <object class="GtkLabel" id="color_label_2">
+                        <property name="label" translatable="yes">Worm color</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="xalign">0.5</property>
+                        <property name="yalign">0.5</property>
+                        <property name="halign">start</property>
+                        <attributes>
+                          <attribute name="weight" value="bold"/>
+                        </attributes>
+                      </object>
+                      <packing>
+                        <property name="left-attach">0</property>
+                        <property name="top-attach">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkComboBoxText" id="combo_box_2">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                      </object>
+                      <packing>
+                        <property name="left-attach">1</property>
+                        <property name="top-attach">0</property>
+                      </packing>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+            <child type="tab">
+              <object class="GtkLabel" id="label_worm_2">
+                <property name="use-underline">True</property>
+                <property name="label" translatable="yes">Worm _2</property>
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+              </object>
+              <packing>
+                <property name="tab_fill">False</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkBox" id="box_worm_3">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="border_width">12</property>
+                <property name="spacing">6</property>
+                <property name="orientation">vertical</property>
+                <child>
+                  <object class="GtkLabel" id="controls_label_3">
+                    <property name="label" translatable="yes">Controls</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">0.5</property>
+                    <property name="yalign">0.5</property>
+                    <property name="halign">start</property>
+                    <attributes>
+                      <attribute name="weight" value="bold"/>
+                    </attributes>
+                  </object>
+                  <packing>
+                    <property name="pack-type">start</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkListStore" id="list_store_3">
+                    <columns>
+                      <column type="gchararray"/>
+                      <column type="gchararray"/>
+                      <column type="guint"/>
+                    </columns>
+                  </object>
+                  <object class="GtkTreeView" id="tree_view_3">
+                    <property name="model">list_store_3</property>
+                    <property name="visible">True</property>
+                  </object>
+                </child>
+                <child>
+                  <object class="GtkSeparator" id="separator_3">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="orientation">horizontal</property>
+                  </object>
+                  <packing>
+                    <property name="pack-type">start</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkGrid" id="color_grid_3">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="row_spacing">0</property>
+                    <property name="column_spacing">12</property>
+                    <property name="border_width">0</property>
+                    <child>
+                      <object class="GtkLabel" id="color_label_3">
+                        <property name="label" translatable="yes">Worm color</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="xalign">0.5</property>
+                        <property name="yalign">0.5</property>
+                        <property name="halign">start</property>
+                        <attributes>
+                          <attribute name="weight" value="bold"/>
+                        </attributes>
+                      </object>
+                      <packing>
+                        <property name="left-attach">0</property>
+                        <property name="top-attach">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkComboBoxText" id="combo_box_3">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                      </object>
+                      <packing>
+                        <property name="left-attach">1</property>
+                        <property name="top-attach">0</property>
+                      </packing>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+            <child type="tab">
+              <object class="GtkLabel" id="label_worm_3">
+                <property name="use-underline">True</property>
+                <property name="label" translatable="yes">Worm _3</property>
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+              </object>
+              <packing>
+                <property name="tab_fill">False</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkBox" id="box_worm_4">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="border_width">12</property>
+                <property name="spacing">6</property>
+                <property name="orientation">vertical</property>
+                <child>
+                  <object class="GtkLabel" id="controls_label_4">
+                    <property name="label" translatable="yes">Controls</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">0.5</property>
+                    <property name="yalign">0.5</property>
+                    <property name="halign">start</property>
+                    <attributes>
+                      <attribute name="weight" value="bold"/>
+                    </attributes>
+                  </object>
+                  <packing>
+                    <property name="pack-type">start</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkListStore" id="list_store_4">
+                    <columns>
+                      <column type="gchararray"/>
+                      <column type="gchararray"/>
+                      <column type="guint"/>
+                    </columns>
+                  </object>
+                  <object class="GtkTreeView" id="tree_view_4">
+                    <property name="model">list_store_4</property>
+                    <property name="visible">True</property>
+                  </object>
+                </child>
+                <child>
+                  <object class="GtkSeparator" id="separator_4">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="orientation">horizontal</property>
+                  </object>
+                  <packing>
+                    <property name="pack-type">start</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkGrid" id="color_grid_4">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="row_spacing">0</property>
+                    <property name="column_spacing">12</property>
+                    <property name="border_width">0</property>
+                    <child>
+                      <object class="GtkLabel" id="color_label_4">
+                        <property name="label" translatable="yes">Worm color</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="xalign">0.5</property>
+                        <property name="yalign">0.5</property>
+                        <property name="halign">start</property>
+                        <attributes>
+                          <attribute name="weight" value="bold"/>
+                        </attributes>
+                      </object>
+                      <packing>
+                        <property name="left-attach">0</property>
+                        <property name="top-attach">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkComboBoxText" id="combo_box_4">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                      </object>
+                      <packing>
+                        <property name="left-attach">1</property>
+                        <property name="top-attach">0</property>
+                      </packing>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+            <child type="tab">
+              <object class="GtkLabel" id="label_worm_4">
+                <property name="use-underline">True</property>
+                <property name="label" translatable="yes">Worm _4</property>
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+              </object>
+              <packing>
+                <property name="tab_fill">False</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">True</property>
+            <property name="fill">True</property>
+            <property name="position">2</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/src/Makefile.am b/src/Makefile.am
index 19cdef5..4eb7334 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -10,6 +10,7 @@ gnome_nibbles_SOURCES = \
        worm.vala \
        boni.vala \
        warp.vala \
+       preferences-dialog.vala \
        $(BUILT_SOURCES)
 
 gnome_nibbles_CFLAGS = -w
diff --git a/src/gnome-nibbles.gresource.xml.in b/src/gnome-nibbles.gresource.xml.in
index 3ea56cd..f3d15a0 100644
--- a/src/gnome-nibbles.gresource.xml.in
+++ b/src/gnome-nibbles.gresource.xml.in
@@ -6,6 +6,7 @@
     <file alias="scoreboard.ui">@top_srcdir@/data/scoreboard.ui</file>
     <file alias="player-score-box.ui">@top_srcdir@/data/player-score-box.ui</file>
     <file alias="controls-grid.ui">@top_srcdir@/data/controls-grid.ui</file>
+    <file alias="preferences-dialog.ui">@top_srcdir@/data/preferences-dialog.ui</file>
   </gresource>
   <gresource prefix="/org/gnome/nibbles/gtk">
     <file alias="menus.ui">@top_srcdir@/data/nibbles-menus.ui</file>
diff --git a/src/gnome-nibbles.vala b/src/gnome-nibbles.vala
index 75d7e7a..2bf1cf4 100644
--- a/src/gnome-nibbles.vala
+++ b/src/gnome-nibbles.vala
@@ -51,6 +51,9 @@ public class Nibbles : Gtk.Application
     private Scoreboard scoreboard;
     private Gdk.Pixbuf scoreboard_life;
 
+    /* Preferences dialog */
+    private PreferencesDialog preferences_dialog = null;
+
     /* Rendering of the game */
     private NibblesView? view;
 
@@ -77,6 +80,7 @@ public class Nibbles : Gtk.Application
         {"start-game", start_game_cb},
         {"new-game", new_game_cb},
         {"pause", pause_cb},
+        {"preferences", preferences_cb},
         {"scores", scores_cb},
         {"about", about_cb},
         {"quit", quit}
@@ -131,11 +135,15 @@ public class Nibbles : Gtk.Application
         add_action_entries (menu_entries, this);
 
         settings = new Settings ("org.gnome.nibbles");
+        settings.changed.connect (settings_changed_cb);
+
+
         worm_settings = new Gee.ArrayList<Settings> ();
         for (int i = 0; i < NibblesGame.MAX_WORMS; i++)
         {
             var name = "org.gnome.nibbles.worm%d".printf(i);
             worm_settings.add (new Settings (name));
+            worm_settings[i].changed.connect (worm_settings_changed_cb);
         }
 
         set_accels_for_action ("app.quit", {"<Primary>q"});
@@ -404,6 +412,62 @@ public class Nibbles : Gtk.Application
     }
 
     /*\
+    * * Settings changed events
+    \*/
+
+    private void settings_changed_cb (string key)
+    {
+        switch (key)
+        {
+            case "speed":
+                game.speed = settings.get_int (key);
+                break;
+            case "sound":
+                view.is_muted = !settings.get_boolean (key);
+                break;
+            case "fakes":
+                game.fakes = settings.get_boolean (key);
+                break;
+        }
+    }
+
+    private void worm_settings_changed_cb (Settings changed_worm_settings, string key)
+    {
+        /* Empty worm properties means game has not started yet */
+        if (game.worm_props.size == 0)
+            return;
+
+        var id = worm_settings.index_of (changed_worm_settings);
+
+        if (id >= game.numworms)
+            return;
+
+        var worm = game.worms[id];
+        var properties = game.worm_props.get (worm);
+
+        switch (key)
+        {
+            case "color":
+                properties.color = NibblesView.colorval_from_name (changed_worm_settings.get_string 
("color"));
+                break;
+            case "key-up":
+                properties.up = changed_worm_settings.get_int ("key-up");
+                break;
+            case "key-down":
+                properties.down = changed_worm_settings.get_int ("key-down");
+                break;
+            case "key-left":
+                properties.left = changed_worm_settings.get_int ("key-left");
+                break;
+            case "key-right":
+                properties.right = changed_worm_settings.get_int ("key-right");
+                break;
+        }
+
+        game.worm_props.set (worm, properties);
+    }
+
+    /*\
     * * Switching the stack
     \*/
 
@@ -691,6 +755,37 @@ public class Nibbles : Gtk.Application
         });
     }
 
+    private void preferences_cb ()
+    {
+        var should_unpause = false;
+        if (game.is_running)
+        {
+            pause_action.activate (null);
+            should_unpause = true;
+        }
+
+        if (preferences_dialog != null)
+        {
+            preferences_dialog.present ();
+
+            if (should_unpause)
+                pause_action.activate (null);
+
+            return;
+        }
+
+        preferences_dialog = new PreferencesDialog (window, settings, worm_settings);
+
+        preferences_dialog.destroy.connect (() => {
+            preferences_dialog = null;
+
+            if (should_unpause)
+                pause_action.activate (null);
+        });
+
+        preferences_dialog.run ();
+    }
+
     private void game_over (int score, long last_score)
     {
         new_game_action.set_enabled (false);
diff --git a/src/nibbles-game.vala b/src/nibbles-game.vala
index 50ec619..e8f7830 100644
--- a/src/nibbles-game.vala
+++ b/src/nibbles-game.vala
@@ -37,6 +37,8 @@ public class NibblesGame : Object
     public const int MAX_AI = 5;
     public const int MAX_WORMS = 6;
 
+    public const int MAX_SPEED = 4;
+
     public const int WIDTH = 92;
     public const int HEIGHT = 66;
     public const int CAPACITY = WIDTH * HEIGHT;
@@ -49,7 +51,7 @@ public class NibblesGame : Object
 
     public int start_level { get; private set; }
     public int current_level { get; private set; }
-    public int speed { get; private set; default = 2; }
+    public int speed { get; set; }
 
     /* Board data */
     public int tile_size { get; set; }
@@ -73,7 +75,7 @@ public class NibblesGame : Object
     private uint main_id = 0;
     private uint add_bonus_id = 0;
 
-    public bool fakes { get; private set; default = false; }
+    public bool fakes { get; set; }
 
     public signal void worm_moved (Worm worm);
     public signal void bonus_applied (Worm worm);
@@ -538,12 +540,16 @@ public class NibblesGame : Object
     {
         tile_size = settings.get_int ("tile-size");
         start_level = settings.get_int ("start-level");
+        speed = settings.get_int ("speed");
+        fakes = settings.get_boolean ("fakes");
     }
 
     public void save_properties (Settings settings)
     {
         settings.set_int ("tile-size", tile_size);
         settings.set_int ("start-level", start_level);
+        settings.set_int ("speed", speed);
+        settings.set_boolean ("fakes", fakes);
     }
 
     public void load_worm_properties (Gee.ArrayList<Settings> worm_settings)
diff --git a/src/preferences-dialog.vala b/src/preferences-dialog.vala
new file mode 100644
index 0000000..f4afa1a
--- /dev/null
+++ b/src/preferences-dialog.vala
@@ -0,0 +1,285 @@
+[GtkTemplate (ui = "/org/gnome/nibbles/ui/preferences-dialog.ui")]
+private class PreferencesDialog : Gtk.Dialog
+{
+    private Gtk.ApplicationWindow window;
+
+    private Settings settings;
+    private Gee.ArrayList<Settings> worm_settings;
+
+    [GtkChild]
+    private Gtk.Notebook notebook;
+    [GtkChild]
+    private Gtk.RadioButton beginner_radio_button;
+    [GtkChild]
+    private Gtk.RadioButton slow_radio_button;
+    [GtkChild]
+    private Gtk.RadioButton medium_radio_button;
+    [GtkChild]
+    private Gtk.RadioButton fast_radio_button;
+    [GtkChild]
+    private Gtk.CheckButton sound_check_button;
+    [GtkChild]
+    private Gtk.CheckButton fakes_check_button;
+    [GtkChild]
+    private Gtk.ListStore list_store_1;
+    [GtkChild]
+    private Gtk.ListStore list_store_2;
+    [GtkChild]
+    private Gtk.ListStore list_store_3;
+    [GtkChild]
+    private Gtk.ListStore list_store_4;
+    [GtkChild]
+    private Gtk.TreeView tree_view_1;
+    [GtkChild]
+    private Gtk.TreeView tree_view_2;
+    [GtkChild]
+    private Gtk.TreeView tree_view_3;
+    [GtkChild]
+    private Gtk.TreeView tree_view_4;
+    [GtkChild]
+    private Gtk.ComboBoxText combo_box_1;
+    [GtkChild]
+    private Gtk.ComboBoxText combo_box_2;
+    [GtkChild]
+    private Gtk.ComboBoxText combo_box_3;
+    [GtkChild]
+    private Gtk.ComboBoxText combo_box_4;
+
+    private Gee.ArrayList<Gtk.RadioButton> radio_buttons;
+    private Gee.ArrayList<Gtk.ListStore> list_stores;
+    private Gee.ArrayList<Gtk.TreeView> tree_views;
+    private Gee.ArrayList<Gtk.ComboBoxText> combo_boxes;
+
+    public PreferencesDialog (Gtk.ApplicationWindow window, Settings settings, Gee.ArrayList<Settings> 
worm_settings)
+    {
+        Object (use_header_bar: 1);
+
+        this.settings = settings;
+        this.worm_settings = worm_settings;
+        this.window = window;
+
+        this.response.connect (() => {
+            this.destroy ();
+        });
+
+        this.set_transient_for (window);
+
+        /* Speed radio buttons */
+        radio_buttons = new Gee.ArrayList<Gtk.RadioButton> ();
+        radio_buttons.add (beginner_radio_button);
+        radio_buttons.add (slow_radio_button);
+        radio_buttons.add (medium_radio_button);
+        radio_buttons.add (fast_radio_button);
+
+        foreach (var radio_button in radio_buttons)
+        {
+            var speed = NibblesGame.MAX_SPEED - radio_buttons.index_of (radio_button);
+            radio_button.set_active (speed == settings.get_int ("speed"));
+            radio_button.toggled.connect (radio_button_toggled_cb);
+        }
+
+        /* Sound check button */
+        sound_check_button.set_active (settings.get_boolean ("sound"));
+        sound_check_button.toggled.connect (sound_toggled_cb);
+
+        /* Fake bonuses check button */
+        fakes_check_button.set_active (settings.get_boolean ("fakes"));
+        fakes_check_button.toggled.connect (fakes_toggles_cb);
+
+        /* Control keys */
+        tree_views = new Gee.ArrayList<Gtk.TreeView> ();
+        tree_views.add (tree_view_1);
+        tree_views.add (tree_view_2);
+        tree_views.add (tree_view_3);
+        tree_views.add (tree_view_4);
+
+        list_stores = new Gee.ArrayList<Gtk.ListStore> ();
+        list_stores.add (list_store_1);
+        list_stores.add (list_store_2);
+        list_stores.add (list_store_3);
+        list_stores.add (list_store_4);
+
+        foreach (var list_store in list_stores)
+        {
+            var id = list_stores.index_of (list_store);
+            var tree_view = tree_views[id];
+
+            Gtk.TreeIter iter;
+            list_store.append (out iter);
+            var keyval = worm_settings[id].get_int ("key-up");
+            list_store.set (iter, 0, "key-up", 1, _("Move up"), 2, keyval);
+            list_store.append (out iter);
+            keyval = worm_settings[id].get_int ("key-down");
+            list_store.set (iter, 0, "key-down", 1, _("Move down"), 2, keyval);
+            list_store.append (out iter);
+            keyval = worm_settings[id].get_int ("key-left");
+            list_store.set (iter, 0, "key-left", 1, _("Move left"), 2, keyval);
+            list_store.append (out iter);
+            keyval = worm_settings[id].get_int ("key-right");
+            list_store.set (iter, 0, "key-right", 1, _("Move right"), 2, keyval);
+
+            var label_renderer = new Gtk.CellRendererText ();
+            tree_view.insert_column_with_attributes (-1, _("Action"), label_renderer, "text", 1);
+
+            var key_renderer = new Gtk.CellRendererAccel ();
+            key_renderer.editable = true;
+            key_renderer.accel_mode = Gtk.CellRendererAccelMode.OTHER;
+            key_renderer.accel_edited.connect (accel_edited_cb);
+            key_renderer.accel_cleared.connect (accel_cleared_cb);
+            tree_view.insert_column_with_attributes (-1, _("Key"), key_renderer, "accel-key", 2);
+
+        }
+
+        /* Worm color */
+        combo_boxes = new Gee.ArrayList<Gtk.ComboBoxText> ();
+        combo_boxes.add (combo_box_1);
+        combo_boxes.add (combo_box_2);
+        combo_boxes.add (combo_box_3);
+        combo_boxes.add (combo_box_4);
+
+        foreach (var combo_box in combo_boxes)
+        {
+            for (int i = 0; i < NibblesView.NUM_COLORS; i++)
+                combo_box.append_text (NibblesView.colorval_name (i));
+
+            var id = combo_boxes.index_of (combo_box);
+
+            var color = worm_settings[id].get_string ("color");
+            combo_box.set_active (NibblesView.colorval_from_name (color));
+            combo_box.changed.connect (combo_box_changed_cb);
+        }
+    }
+
+    private void radio_button_toggled_cb (Gtk.ToggleButton button)
+    {
+        if (button.get_active ())
+        {
+            var speed = NibblesGame.MAX_SPEED - radio_buttons.index_of ((Gtk.RadioButton) button);
+            settings.set_int ("speed", speed);
+        }
+    }
+
+    private void sound_toggled_cb ()
+    {
+        var play_sound = sound_check_button.get_active ();
+        settings.set_boolean ("sound", play_sound);
+    }
+
+    private void fakes_toggles_cb ()
+    {
+        var has_fakes = fakes_check_button.get_active ();
+        settings.set_boolean ("fakes", has_fakes);
+    }
+
+    private void accel_edited_cb (Gtk.CellRendererAccel cell, string path_string, uint keyval,
+                                  Gdk.ModifierType mask, uint hardware_keycode)
+    {
+        var path = new Gtk.TreePath.from_string (path_string);
+        if (path == null)
+            return;
+
+        var id = notebook.get_current_page () - 1;
+        var list_store = list_stores[id];
+
+        Gtk.TreeIter it;
+        if (!list_store.get_iter (out it, path))
+            return;
+
+        string? key = null;
+        list_store.get (it, 0, out key);
+        if (key == null)
+            return;
+
+        if (worm_settings[id].get_int (key) == keyval)
+            return;
+
+        /* Duplicate key check */
+        bool valid = true;
+        for (int i = 0; i < NibblesGame.MAX_HUMANS; i++)
+        {
+            if (worm_settings[i].get_int ("key-up") == keyval ||
+                worm_settings[i].get_int ("key-down") == keyval ||
+                worm_settings[i].get_int ("key-left") == keyval ||
+                worm_settings[i].get_int ("key-right") == keyval)
+            {
+                valid = false;
+
+                /* Translators: This string appears when one tries to assign an already assigned key */
+                var dialog = new Gtk.MessageDialog (window,
+                                                    Gtk.DialogFlags.DESTROY_WITH_PARENT,
+                                                    Gtk.MessageType.WARNING,
+                                                    Gtk.ButtonsType.OK,
+                                                    _("The key you selected is already assigned!"));
+
+                dialog.run ();
+                dialog.destroy ();
+                break;
+            }
+        }
+
+        if (valid)
+        {
+            list_store.set (it, 2, keyval);
+            worm_settings[id].set_int (key, (int) keyval);
+        }
+    }
+
+    private void accel_cleared_cb (Gtk.CellRendererAccel cell, string path_string)
+    {
+        var path = new Gtk.TreePath.from_string (path_string);
+        if (path == null)
+            return;
+
+        var id = notebook.get_current_page () - 1;
+        var list_store = list_stores[id];
+
+        Gtk.TreeIter it;
+        if (!list_store.get_iter (out it, path))
+            return;
+
+        string? key = null;
+        list_store.get (it, 0, out key);
+        if (key == null)
+            return;
+
+        list_store.set (it, 2, 0);
+        worm_settings[id].set_int (key, 0);
+    }
+
+    private void combo_box_changed_cb (Gtk.ComboBox combo_box)
+    {
+        var id = combo_boxes.index_of ((Gtk.ComboBoxText) combo_box);
+        var color_new = NibblesView.colorval_name (combo_box.get_active ());
+        var color_old = worm_settings[id].get_string ("color");
+
+        if (color_new == color_old)
+            return;
+
+        /* Swap the colors if the new color is already set for another worm */
+        for (int i = 0; i < NibblesGame.MAX_WORMS; i++)
+        {
+            if (i != id && worm_settings[i].get_string ("color") == color_new)
+            {
+                worm_settings[i].set_string ("color", color_old);
+
+                /* Update swapped colors in UI */
+                if (i < NibblesGame.MAX_HUMANS)
+                {
+                    foreach (var cbox in combo_boxes)
+                    {
+                        var index = combo_boxes.index_of (cbox);
+                        if (index == i)
+                        {
+                            cbox.set_active (NibblesView.colorval_from_name (color_old));
+                            break;
+                        }
+                    }
+                }
+
+                break;
+            }
+        }
+
+        worm_settings[id].set_string ("color", color_new);
+    }
+}



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