From 5e516f679d6ce68ad7c20775b9501b08adb49c25 Mon Sep 17 00:00:00 2001
From: Bruce Cowan <bruce@bcowan.me.uk>
Date: Sun, 26 Jul 2020 19:14:14 +0100
Subject: [PATCH] Add preference dialogue for points configuring

---
 build-aux/post_install.py           |  20 +++++
 data/interface.ui                   |  34 ++++++--
 data/meson.build                    |  14 +++-
 data/prefs.ui                       | 120 ++++++++++++++++++++++++++++
 data/rugby.gresource.xml            |   4 +-
 data/uk.me.bcowan.Rugby.gschema.xml |  25 ++++++
 meson.build                         |  12 ++-
 meson_options.txt                   |   5 --
 src/main.c                          |  16 +++-
 src/meson.build                     |   3 +-
 src/rugby-list-store.c              |  50 ++++++++++--
 src/rugby-pref-window.c             |  73 +++++++++++++++++
 src/rugby-pref-window.h             |  21 +++++
 13 files changed, 371 insertions(+), 26 deletions(-)
 create mode 100644 build-aux/post_install.py
 create mode 100644 data/prefs.ui
 create mode 100644 data/uk.me.bcowan.Rugby.gschema.xml
 delete mode 100644 meson_options.txt
 create mode 100644 src/rugby-pref-window.c
 create mode 100644 src/rugby-pref-window.h

diff --git a/build-aux/post_install.py b/build-aux/post_install.py
new file mode 100644
index 0000000..40fa31e
--- /dev/null
+++ b/build-aux/post_install.py
@@ -0,0 +1,20 @@
+#!/usr/bin/env python3
+
+# SPDX-FileCopyrightText: 2017 Carlos Sanchez <csoriano@gnome.org>
+# SPDX-FileCopyrightText: 2020 Bruce Cowan <bruce@bcowan.me.uk>
+#
+# SPDX-License-Identifier: CC0-1.0
+
+import os
+import subprocess
+
+prefix = os.environ.get("MESON_INSTALL_PREFIX", "/usr/local")
+datadir = os.path.join(prefix, "share")
+
+if "DESTDIR" not in os.environ:
+    print("Compiling GSettings schemas...")
+    schemas_dir = os.path.join(datadir, "glib-2.0", "schemas")
+    if not os.path.exists(schemas_dir):
+        os.makedirs(schemas_dir)
+    subprocess.call(["glib-compile-schemas", schemas_dir])
+
diff --git a/data/interface.ui b/data/interface.ui
index 9c10b6b..2e473ed 100644
--- a/data/interface.ui
+++ b/data/interface.ui
@@ -14,16 +14,38 @@
   <object class="GtkPopoverMenu" id="popovermenu1">
     <property name="can_focus">False</property>
     <child>
-      <object class="GtkModelButton">
+      <object class="GtkGrid">
         <property name="visible">True</property>
-        <property name="can_focus">True</property>
-        <property name="receives_default">True</property>
-        <property name="action_name">app.about</property>
-        <property name="text" translatable="yes">About Rugby</property>
+        <property name="can_focus">False</property>
+        <child>
+          <object class="GtkModelButton">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">True</property>
+            <property name="action_name">app.about</property>
+            <property name="text" translatable="yes">_About Rugby</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkModelButton">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">True</property>
+            <property name="action_name">app.prefs</property>
+            <property name="text" translatable="yes">_Preferences</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
       </object>
       <packing>
         <property name="submenu">main</property>
-        <property name="position">1</property>
       </packing>
     </child>
   </object>
diff --git a/data/meson.build b/data/meson.build
index 70a7b08..8724dc3 100644
--- a/data/meson.build
+++ b/data/meson.build
@@ -1,5 +1,17 @@
-# SPDX-FileCopyrightText: 2016, 2018 Bruce Cowan <bruce@bcowan.me.uk>
+# SPDX-FileCopyrightText: 2016-2020 Bruce Cowan <bruce@bcowan.me.uk>
+#
 # SPDX-License-Identifier: CC0-1.0
+
 resources = gnome.compile_resources('gen-resources',
                                     'rugby.gresource.xml',
                                     source_dir: 'data')
+
+gnome.compile_schemas(
+  build_by_default: true,
+  depend_files: 'uk.me.bcowan.Rugby.gschema.xml',
+)
+
+install_data(
+  'uk.me.bcowan.Rugby.gschema.xml',
+  install_dir: join_paths(datadir, 'glib-2.0', 'schemas'),
+)
diff --git a/data/prefs.ui b/data/prefs.ui
new file mode 100644
index 0000000..2365435
--- /dev/null
+++ b/data/prefs.ui
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.0 -->
+<!--
+  SPDX-FileCopyrightText: 2020 Bruce Cowan <bruce@bcowan.me.uk>
+
+  SPDX-License-Identifier: GPL-3.0-or-later
+-->
+<interface>
+  <requires lib="gtk+" version="3.16"/>
+  <object class="GtkAdjustment" id="adjustment1">
+    <property name="lower">1</property>
+    <property name="upper">7</property>
+    <property name="value">7</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">1</property>
+  </object>
+  <object class="GtkAdjustment" id="adjustment2">
+    <property name="lower">1</property>
+    <property name="upper">5</property>
+    <property name="value">5</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">1</property>
+  </object>
+  <object class="GtkAdjustment" id="adjustment3">
+    <property name="lower">1</property>
+    <property name="upper">4</property>
+    <property name="value">3</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">1</property>
+  </object>
+  <template class="RugbyPrefWindow" parent="GtkWindow">
+    <property name="can_focus">False</property>
+    <property name="title">Preferences</property>
+    <property name="type_hint">dialog</property>
+    <child>
+      <object class="GtkGrid">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="margin_start">6</property>
+        <property name="margin_end">6</property>
+        <property name="margin_top">6</property>
+        <property name="margin_bottom">6</property>
+        <property name="row_spacing">6</property>
+        <property name="column_spacing">6</property>
+        <child>
+          <object class="GtkLabel">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">Points for a converted try</property>
+            <property name="xalign">0</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">Points for an unconverted try</property>
+            <property name="xalign">0</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">Points for a kick</property>
+            <property name="xalign">0</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">2</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkSpinButton" id="try_spin">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="adjustment">adjustment1</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkSpinButton" id="utry_spin">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="adjustment">adjustment2</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkSpinButton" id="kick_spin">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="adjustment">adjustment3</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">2</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <child type="titlebar">
+      <placeholder/>
+    </child>
+  </template>
+</interface>
diff --git a/data/rugby.gresource.xml b/data/rugby.gresource.xml
index ea27570..24d7d80 100644
--- a/data/rugby.gresource.xml
+++ b/data/rugby.gresource.xml
@@ -1,11 +1,13 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!--
-  SPDX-FileCopyrightText: 2012-2017 Bruce Cowan <bruce@bcowan.me.uk>
+  SPDX-FileCopyrightText: 2012-2020 Bruce Cowan <bruce@bcowan.me.uk>
+
   SPDX-License-Identifier: GPL-3.0-or-later
 -->
 <gresources>
   <gresource prefix="/uk/me/bcowan/rugby">
     <file preprocess="xml-stripblanks">interface.ui</file>
+    <file preprocess="xml-stripblanks">prefs.ui</file>
     <file compressed="true">rugby.css</file>
   </gresource>
 </gresources>
diff --git a/data/uk.me.bcowan.Rugby.gschema.xml b/data/uk.me.bcowan.Rugby.gschema.xml
new file mode 100644
index 0000000..f159c5b
--- /dev/null
+++ b/data/uk.me.bcowan.Rugby.gschema.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  SPDX-FileCopyrightText: 2020 Bruce Cowan <bruce@bcowan.me.uk>
+
+  SPDX-License-Identifier: GPL-3.0-or-later
+-->
+<schemalist>
+  <schema id="uk.me.bcowan.Rugby" path="/uk/me/bcowan/Rugby/">
+    <key name="try-points" type="i">
+      <default>7</default>
+      <summary>Try points</summary>
+      <description>Number of points for a try</description>
+    </key>
+    <key name="utry-points" type="i">
+      <default>5</default>
+      <summary>Unconverted try points</summary>
+      <description>Number of points for an unconverted try</description>
+    </key>
+    <key name="kick-points" type="i">
+      <default>3</default>
+      <summary>Kick points</summary>
+      <description>Number of points for a kick (drop goal or penalty)</description>
+    </key>
+  </schema>
+</schemalist>
diff --git a/meson.build b/meson.build
index c403d1b..6f9a214 100644
--- a/meson.build
+++ b/meson.build
@@ -1,24 +1,26 @@
 # SPDX-FileCopyrightText: 2016-2020 Bruce Cowan <bruce@bcowan.me.uk>
+#
 # SPDX-License-Identifier: CC0-1.0
+
 project('rugby', 'c',
+    version: '0.1.0',
     license:'GPL',
     default_options: ['c_std=gnu11', 'warning_level=3'])
 
+datadir = get_option('datadir')
+
 gnome = import('gnome')
 
 gio_dep = dependency('gio-2.0', version: '>= 2.44')
 gtk_dep = dependency('gtk+-3.0', version: '>= 3.16')
 
 conf = configuration_data()
-conf.set('TRY_POINTS', get_option('try_points'))
-conf.set('UTRY_POINTS', get_option('utry_points'))
-conf.set('KICK_POINTS', get_option('kick_points'))
 
 git = find_program('git', required: false)
 if git.found()
     VERSION = run_command('git', 'describe', '--always').stdout().strip()
 else
-    VERSION = 'unknown'
+    VERSION = meson.version()
 endif
 
 conf.set_quoted('VERSION', VERSION)
@@ -37,3 +39,5 @@ add_project_arguments(cc.get_supported_arguments(cflags),
 
 subdir('data')
 subdir('src')
+
+meson.add_install_script('build-aux/post_install.py')
diff --git a/meson_options.txt b/meson_options.txt
deleted file mode 100644
index 368fd1a..0000000
--- a/meson_options.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-# SPDX-FileCopyrightText: 2018-2020 Bruce Cowan <bruce@bcowan.me.uk>
-# SPDX-License-Identifier: CC0-1.0
-option('try_points', type: 'integer', value: 7)
-option('utry_points', type: 'integer', value: 5)
-option('kick_points', type: 'integer', value: 3)
diff --git a/src/main.c b/src/main.c
index e0fcb27..566bdb6 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,11 +1,12 @@
 /*
- * SPDX-FileCopyrightText: 2012, 2016-2018 Bruce Cowan <bruce@bcowan.me.uk>
+ * SPDX-FileCopyrightText: 2012-2020 Bruce Cowan <bruce@bcowan.me.uk>
  * SPDX-License-Identifier: GPL-3.0-or-later
  */
 
 #include "config.h"
 
 #include "rugby-app-window.h"
+#include "rugby-pref-window.h"
 
 static GtkWidget *window = NULL;
 
@@ -40,6 +41,18 @@ about_activated (G_GNUC_UNUSED GSimpleAction *simple,
                            NULL);
 }
 
+static void
+preferences_activated (G_GNUC_UNUSED GSimpleAction *simple,
+                       G_GNUC_UNUSED GVariant      *parameter,
+                                     gpointer       user_data)
+{
+    GtkApplication *app = GTK_APPLICATION (user_data);
+    GtkWindow *window = gtk_application_get_active_window (app);
+
+    RugbyPrefWindow *pref_window = rugby_pref_window_new (RUGBY_APP_WINDOW (window));
+    gtk_window_present (GTK_WINDOW (pref_window));
+}
+
 static void
 on_startup (GApplication          *app,
             G_GNUC_UNUSED gpointer user_data)
@@ -47,6 +60,7 @@ on_startup (GApplication          *app,
     const GActionEntry app_entries[] =
     {
         { .name = "about", .activate = about_activated },
+        { .name = "prefs", .activate = preferences_activated },
     };
 
     g_action_map_add_action_entries (G_ACTION_MAP (app),
diff --git a/src/meson.build b/src/meson.build
index 7d11fb6..ca4bb92 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -5,7 +5,8 @@ sources = [
     'rugby-app-window.c',
     'rugby-list-store.c',
     'rugby-possibility.c',
-    'rugby-possibility-widget.c'
+    'rugby-possibility-widget.c',
+    'rugby-pref-window.c',
 ]
 
 config_h = configure_file(configuration: conf, output: 'config.h')
diff --git a/src/rugby-list-store.c b/src/rugby-list-store.c
index f0f7d6e..fedcb1a 100644
--- a/src/rugby-list-store.c
+++ b/src/rugby-list-store.c
@@ -1,8 +1,9 @@
 /*
  * SPDX-FileCopyrightText: 2018-2020 Bruce Cowan <bruce@bcowan.me.uk>
+ *
  * SPDX-License-Identifier: GPL-3.0-or-later
  */
-#include "config.h"
+
 #include "rugby-list-store.h"
 
 #include "rugby-possibility.h"
@@ -13,6 +14,8 @@ struct _RugbyListStore
 {
     GObject parent_instance;
 
+    GSettings *settings;
+
     GPtrArray *items;
     int score;
 };
@@ -60,10 +63,14 @@ sort_func (gconstpointer a,
 }
 
 static void
-on_score_changed (RugbyListStore *self)
+process_data (RugbyListStore *self)
 {
-    int max_tries = self->score / TRY_POINTS;
-    int max_utries = self->score / UTRY_POINTS;
+    int try_points = g_settings_get_int (self->settings, "try-points");
+    int utry_points = g_settings_get_int (self->settings, "utry-points");
+    int kick_points = g_settings_get_int (self->settings, "kick-points");
+
+    int max_tries = self->score / try_points;
+    int max_utries = self->score / utry_points;
 
     unsigned old_length = self->items->len;
     g_ptr_array_remove_range (self->items, 0, self->items->len);
@@ -72,14 +79,14 @@ on_score_changed (RugbyListStore *self)
     {
         for (int utries = 0; utries <= max_utries; utries++)
         {
-            int left = self->score - (tries * TRY_POINTS) - (utries * UTRY_POINTS);
+            int left = self->score - (tries * try_points) - (utries * utry_points);
 
             if (left < 0)
                 break;
 
-            if (left % KICK_POINTS == 0)
+            if (left % kick_points == 0)
             {
-                int kicks = left / KICK_POINTS;
+                int kicks = left / kick_points;
 
                 RugbyPossibility *possibility = rugby_possibility_new (tries,
                                                                        utries,
@@ -93,6 +100,20 @@ on_score_changed (RugbyListStore *self)
     g_list_model_items_changed (G_LIST_MODEL (self), 0, old_length, self->items->len);
 }
 
+static void
+on_score_changed (RugbyListStore *self)
+{
+    process_data (self);
+}
+
+static void
+on_settings_changed (GSettings G_GNUC_UNUSED *settings,
+                     char      G_GNUC_UNUSED *key,
+                     gpointer                 user_data)
+{
+    process_data (RUGBY_LIST_STORE (user_data));
+}
+
 // GListModel implementation
 
 static GType
@@ -130,6 +151,16 @@ rugby_list_store_list_model_iface_init (GListModelInterface *iface)
 
 // Class functions
 
+static void
+rugby_list_store_dispose (GObject *object)
+{
+    RugbyListStore *self = RUGBY_LIST_STORE (object);
+
+    g_clear_object (&self->settings);
+
+    G_OBJECT_CLASS (rugby_list_store_parent_class)->dispose (object);
+}
+
 static void
 rugby_list_store_finalize (GObject *object)
 {
@@ -181,6 +212,7 @@ rugby_list_store_class_init (RugbyListStoreClass *klass)
 {
     GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
+    object_class->dispose = rugby_list_store_dispose;
     object_class->finalize = rugby_list_store_finalize;
     object_class->get_property = rugby_list_store_get_property;
     object_class->set_property = rugby_list_store_set_property;
@@ -199,6 +231,10 @@ rugby_list_store_class_init (RugbyListStoreClass *klass)
 static void
 rugby_list_store_init (RugbyListStore *self)
 {
+    self->settings = g_settings_new ("uk.me.bcowan.Rugby");
+    g_signal_connect (self->settings, "changed",
+                      G_CALLBACK (on_settings_changed), self);
+
     self->score = 0;
     self->items = g_ptr_array_new_with_free_func (g_object_unref);
 }
diff --git a/src/rugby-pref-window.c b/src/rugby-pref-window.c
new file mode 100644
index 0000000..5211404
--- /dev/null
+++ b/src/rugby-pref-window.c
@@ -0,0 +1,73 @@
+/*
+ * SPDX-FileCopyrightText: 2020 Bruce Cowan <bruce@bcowan.me.uk>
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#include "rugby-pref-window.h"
+
+struct _RugbyPrefWindow
+{
+  GtkWindow parent_instance;
+
+  GtkWidget *try_spin;
+  GtkWidget *utry_spin;
+  GtkWidget *kick_spin;
+
+  GSettings *settings;
+};
+
+G_DEFINE_TYPE (RugbyPrefWindow, rugby_pref_window, GTK_TYPE_WINDOW)
+
+static void
+rugby_pref_window_dispose (GObject *object)
+{
+  RugbyPrefWindow *self = RUGBY_PREF_WINDOW (object);
+
+  g_clear_object (&self->settings);
+
+  G_OBJECT_CLASS (rugby_pref_window_parent_class)->dispose (object);
+}
+
+static void
+rugby_pref_window_class_init (RugbyPrefWindowClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+  object_class->dispose = rugby_pref_window_dispose;
+
+  gtk_widget_class_set_template_from_resource (widget_class,
+                                               "/uk/me/bcowan/rugby/prefs.ui");
+
+  gtk_widget_class_bind_template_child (widget_class, RugbyPrefWindow, try_spin);
+  gtk_widget_class_bind_template_child (widget_class, RugbyPrefWindow, utry_spin);
+  gtk_widget_class_bind_template_child (widget_class, RugbyPrefWindow, kick_spin);
+
+}
+
+static void
+rugby_pref_window_init (RugbyPrefWindow *self)
+{
+  gtk_widget_init_template (GTK_WIDGET (self));
+
+  self->settings = g_settings_new ("uk.me.bcowan.Rugby");
+
+  g_settings_bind (self->settings, "try-points",
+                   self->try_spin, "value",
+                   G_SETTINGS_BIND_DEFAULT);
+  g_settings_bind (self->settings, "utry-points",
+                   self->utry_spin, "value",
+                   G_SETTINGS_BIND_DEFAULT);
+  g_settings_bind (self->settings, "kick-points",
+                   self->kick_spin, "value",
+                   G_SETTINGS_BIND_DEFAULT);
+}
+
+RugbyPrefWindow *
+rugby_pref_window_new (RugbyAppWindow *window)
+{
+  return g_object_new (RUGBY_TYPE_PREF_WINDOW,
+                       "transient-for", window,
+                       NULL);
+}
diff --git a/src/rugby-pref-window.h b/src/rugby-pref-window.h
new file mode 100644
index 0000000..a7c69fe
--- /dev/null
+++ b/src/rugby-pref-window.h
@@ -0,0 +1,21 @@
+/*
+ * SPDX-FileCopyrightText: 2020 Bruce Cowan <bruce@bcowan.me.uk>
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include "rugby-app-window.h"
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define RUGBY_TYPE_PREF_WINDOW (rugby_pref_window_get_type())
+
+G_DECLARE_FINAL_TYPE (RugbyPrefWindow, rugby_pref_window, RUGBY, PREF_WINDOW, GtkWindow)
+
+RugbyPrefWindow *rugby_pref_window_new (RugbyAppWindow *window);
+
+G_END_DECLS
-- 
GitLab