Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • SuborbitalPigeon/rugby
  • webpigeon/rugby
2 results
Show changes
Showing
with 713 additions and 328 deletions
<?xml version="1.0" encoding="UTF-8"?>
<!--
SPDX-FileCopyrightText: 2023-2024 Bruce Cowan
SPDX-License-Identifier: CC0-1.0
-->
<component type="desktop-application">
<id>uk.me.bcowan.Rugby</id>
<name>Rugby</name>
<developer_name>Bruce Cowan</developer_name>
<summary>Find possibilities for rugby scores</summary>
<metadata_license>CC0-1.0</metadata_license>
<project_license>GPL-3.0-or-later</project_license>
<supports>
<control>pointing</control>
<control>keyboard</control>
<control>touch</control>
</supports>
<description>
<p>
A program to determine possible combinations of scoring for rugby matches.
</p>
</description>
<launchable type="desktop-id">uk.me.bcowan.Rugby.desktop</launchable>
<icon type="stock">rugby</icon>
<categories>
<category>Utility</category>
<category>GNOME</category>
</categories>
<provides>
<binary>rugby</binary>
</provides>
</component>
# SPDX-FileCopyrightText: 2016-2020 Bruce Cowan <bruce@bcowan.me.uk>
# SPDX-License-Identifier: CC0-1.0
# SPDX-FileCopyrightText: 2016-2024 Bruce Cowan <bruce@bcowan.me.uk>
#
# SPDX-License-Identifier: GPL-3.0-or-later
project('rugby', 'c',
license:'GPL')
version: '0.4.alpha',
license:'GPLv3+',
meson_version: '>= 1.1.0',
default_options: [
'buildtype=debugoptimized',
'c_std=gnu11',
'warning_level=3'
],
)
datadir = get_option('datadir')
desktopdir = datadir / 'applications'
gnome = import('gnome')
gio_dep = dependency('gio-2.0', version: '>= 2.46')
gtk_dep = dependency('gtk+-3.0', version: '>= 3.16')
gio_dep = dependency('gio-2.0', version: '>= 2.76')
gtk_dep = dependency('gtk4', version: '>= 4.12')
libadwaita_dep = dependency('libadwaita-1', version: '>=1.5.beta')
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()
profile = get_option('profile')
conf.set_quoted('PROFILE', profile)
if profile == 'development'
conf.set_quoted('VERSION', '@0@-@VCS_TAG@'.format(meson.project_version()))
else
VERSION = 'unknown'
conf.set_quoted('VERSION', meson.project_version())
endif
conf.set_quoted('VERSION', VERSION)
cflags = ['-DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_70',
'-DGLIB_VERSION_MAX_ALLOWED=GLIB_VERSION_2_70',
'-DGDK_VERSION_MIN_REQUIRED=GDK_VERSION_4_12',
'-DGDK_VERSION_MAX_ALLOWED=GDK_VERSION_4_12',
'-Wno-overlength-strings',
]
cc = meson.get_compiler('c')
add_project_arguments(cc.get_supported_arguments(cflags),
language: 'c')
subdir('data')
subdir('src')
gnome.post_install(
glib_compile_schemas: true,
update_desktop_database: true,
)
# SPDX-FileCopyrightText: 2022 Bruce Cowan <bruce@bcowan.me.uk>
#
# SPDX-License-Identifier: CC0-1.0
option(
'profile',
type: 'combo',
choices: ['default', 'development'],
value: 'default',
description: 'What sort of build is this?'
)
# 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)
/*
* SPDX-FileCopyrightText: 2012, 2016-2018 Bruce Cowan <bruce@bcowan.me.uk>
* SPDX-FileCopyrightText: 2012-2024 Bruce Cowan <bruce@bcowan.me.uk>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include <gtk/gtk.h>
#include <config.h>
#include "config.h"
#include "rugby-app-window.h"
#include "rugby-pref-dialog.h"
static void
on_activate (GApplication *app,
gpointer user_data)
on_activate ( GApplication *app,
G_GNUC_UNUSED void *user_data)
{
RugbyAppWindow *win = rugby_app_window_new (GTK_APPLICATION (app));
gtk_window_present (GTK_WINDOW (win));
g_assert (GTK_IS_APPLICATION (app));
GtkWindow *window = gtk_application_get_active_window (GTK_APPLICATION (app));
if (!window)
window = GTK_WINDOW (rugby_app_window_new (GTK_APPLICATION (app)));
if (g_strcmp0 (PROFILE, "development") == 0)
gtk_widget_add_css_class (GTK_WIDGET (window), "devel");
gtk_window_present (GTK_WINDOW (window));
}
static void
about_activated (GSimpleAction *simple,
GVariant *parameter,
gpointer user_data)
about_activated (G_GNUC_UNUSED GSimpleAction *simple,
G_GNUC_UNUSED GVariant *parameter,
void *user_data)
{
GtkApplication *app = GTK_APPLICATION (user_data);
GtkWindow *window = gtk_application_get_active_window (app);
const char *authors[] = { "Bruce Cowan", NULL };
adw_show_about_dialog_from_appdata (GTK_WIDGET (window),
"uk/me/bcowan/Rugby/uk.me.bcowan.Rugby.metainfo.xml",
NULL,
"application-icon", "football-american",
"version", VERSION,
NULL);
}
gtk_show_about_dialog (window,
"logo-icon-name", "face-wink",
"program-name", "Rugby",
"copyright", "Copyright 2012–2020 Bruce Cowan",
"license-type", GTK_LICENSE_GPL_3_0,
"authors", authors,
"comments", "Rugby scores possiblities program",
"version", VERSION,
NULL);
static void
preferences_activated (G_GNUC_UNUSED GSimpleAction *simple,
G_GNUC_UNUSED GVariant *parameter,
void *user_data)
{
GtkApplication *app = GTK_APPLICATION (user_data);
GtkWindow *window = gtk_application_get_active_window (app);
RugbyPrefDialog *pref_window = rugby_pref_dialog_new ();
adw_dialog_present (ADW_DIALOG (pref_window), GTK_WIDGET (window));
}
static void
on_startup (GApplication *app,
gpointer user_data)
on_startup ( GApplication *app,
G_GNUC_UNUSED void *user_data)
{
const GActionEntry app_entries[] =
{
{ .name = "about", .activate = about_activated },
{ .name = "prefs", .activate = preferences_activated },
};
g_action_map_add_action_entries (G_ACTION_MAP (app),
app_entries,
G_N_ELEMENTS (app_entries),
app);
// CSS styling
g_autoptr (GtkCssProvider) provider = gtk_css_provider_new ();
gtk_css_provider_load_from_resource (provider, "/uk/me/bcowan/rugby/rugby.css");
gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
GTK_STYLE_PROVIDER (provider),
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
gtk_application_set_accels_for_action (GTK_APPLICATION (app),
"app.prefs",
(const char*[]) { "<Ctrl>comma", NULL });
}
int
main (int argc,
char **argv)
{
GtkApplication *app = gtk_application_new ("uk.me.bcowan.Rugby",
G_APPLICATION_FLAGS_NONE);
g_autoptr (AdwApplication) app = adw_application_new ("uk.me.bcowan.Rugby",
G_APPLICATION_NON_UNIQUE);
g_signal_connect (app, "startup",
G_CALLBACK (on_startup), NULL);
......
# SPDX-FileCopyrightText: 2016-2020 Bruce Cowan <bruce@bcowan.me.uk>
# SPDX-License-Identifier: CC0-1.0
# SPDX-FileCopyrightText: 2016-2024 Bruce Cowan <bruce@bcowan.me.uk>
#
# SPDX-License-Identifier: GPL-3.0-or-later
sources = [
'main.c',
'rugby-app-window.c',
'rugby-list-store.c',
'rugby-possibility.c',
'rugby-possibility-widget.c'
'rugby-possibility-widget.c',
'rugby-pref-dialog.c',
]
config_h = configure_file(configuration: conf, output: 'config.h')
config_h = vcs_tag(
input: configure_file(
output: 'config.h.in',
configuration: conf,
),
output: 'config.h',
command: ['git', 'rev-parse', '--short', 'HEAD'],
fallback: (profile == 'development') ? 'devel' : '',
)
executable('rugby',
sources, resources, config_h,
dependencies: [gio_dep, gtk_dep],
sources, config_h, resources,
dependencies: [gio_dep, gtk_dep, libadwaita_dep],
install_dir: get_option('bindir'),
install: true)
/*
* SPDX-FileCopyrightText: 2017, 2018 Bruce Cowan <bruce@bcowan.me.uk>
* SPDX-FileCopyrightText: 2017-2024 Bruce Cowan <bruce@bcowan.me.uk>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include <gtk/gtk.h>
#include "config.h"
#include "rugby-app-window.h"
#include "rugby-list-store.h"
#include "rugby-possibility.h"
#include "rugby-possibility-widget.h"
#include <glib/gi18n.h>
struct _RugbyAppWindow
{
GtkApplicationWindow parent;
AdwApplicationWindow parent;
RugbyListStore *store;
GtkWidget *scorespin;
GtkWidget *stack;
GtkWidget *listbox;
GSettings *win_settings;
};
G_DEFINE_TYPE (RugbyAppWindow, rugby_app_window, GTK_TYPE_APPLICATION_WINDOW)
G_DEFINE_FINAL_TYPE (RugbyAppWindow, rugby_app_window, ADW_TYPE_APPLICATION_WINDOW)
static void
scorespin_value_changed_cb (GtkSpinButton *spin,
RugbyAppWindow *self)
list_store_items_changed_cb ( GListModel *model,
G_GNUC_UNUSED unsigned position,
G_GNUC_UNUSED unsigned removed,
G_GNUC_UNUSED unsigned added,
RugbyAppWindow *self)
{
int score = gtk_spin_button_get_value_as_int (spin);
unsigned n_items = g_list_model_get_n_items (model);
if (n_items == 0)
gtk_stack_set_visible_child_name (GTK_STACK (self->stack), "empty_page");
else
gtk_stack_set_visible_child_name (GTK_STACK (self->stack), "list_page");
}
rugby_list_store_set_score (self->store, score);
static char *
item_tooltip_cb (GtkListItem *item)
{
RugbyPossibility *possibility = gtk_list_item_get_item (item);
if (!possibility)
return NULL;
GString *tooltip = g_string_new (NULL);
int tries = rugby_possibility_get_tries (possibility);
int utries = rugby_possibility_get_utries (possibility);
int kicks = rugby_possibility_get_kicks (possibility);
if (tries > 0)
{
g_string_printf (tooltip, ngettext ("%d converted try",
"%d converted tries",
tries),
tries);
}
if (utries > 0)
{
if (tooltip->len > 0)
g_string_append (tooltip, ", ");
g_string_append_printf (tooltip, ngettext ("%d unconverted try",
"%d unconverted tries",
utries),
utries);
}
if (kicks > 0)
{
if (tooltip->len > 0)
g_string_append (tooltip, ", ");
g_string_append_printf (tooltip, ngettext ("%d kick",
"%d kicks",
kicks),
kicks);
}
return g_string_free (tooltip, FALSE);
}
static GtkWidget *
listbox_widget_func (gpointer item,
gpointer user_data)
static char *
header_label_cb (GtkListItem *item)
{
RugbyPossibility *possibility = RUGBY_POSSIBILITY (item);
RugbyPossibility *possibility = gtk_list_header_get_item (GTK_LIST_HEADER (item));
if (!possibility)
return NULL;
return rugby_possibility_widget_new (possibility);
int total_tries = rugby_possibility_total_tries (possibility);
return g_strdup_printf (ngettext ("%d try", "%d tries", total_tries), total_tries);
}
static void
rugby_app_window_init (RugbyAppWindow *self)
activate_score_changed (G_GNUC_UNUSED GSimpleAction *action,
GVariant *parameter,
void *user_data)
{
gtk_widget_init_template (GTK_WIDGET (self));
RugbyAppWindow *self = RUGBY_APP_WINDOW (user_data);
self->store = rugby_list_store_new ();
gtk_list_box_bind_model (GTK_LIST_BOX (self->listbox),
G_LIST_MODEL (self->store),
listbox_widget_func,
NULL,
NULL);
double current_value = gtk_spin_button_get_value (GTK_SPIN_BUTTON (self->scorespin));
const char *direction = g_variant_get_string (parameter, NULL);
if (g_strcmp0 (direction, "up") == 0)
gtk_spin_button_set_value (GTK_SPIN_BUTTON (self->scorespin), current_value + 1.0);
else if (g_strcmp0 (direction, "down") == 0)
gtk_spin_button_set_value (GTK_SPIN_BUTTON (self->scorespin), current_value - 1.0);
else
g_assert_not_reached ();
}
static void
rugby_app_window_dispose (GObject *object)
{
RugbyAppWindow *self = RUGBY_APP_WINDOW (object);
g_clear_object (&self->store);
gtk_widget_dispose_template (GTK_WIDGET (object), RUGBY_TYPE_APP_WINDOW);
g_clear_object (&RUGBY_APP_WINDOW (object)->win_settings);
G_OBJECT_CLASS (rugby_app_window_parent_class)->dispose (object);
}
static void
rugby_app_window_init (RugbyAppWindow *self)
{
gtk_widget_init_template (GTK_WIDGET (self));
const GActionEntry win_entries[] = {
{ .name = "score-changed", .activate = activate_score_changed, .parameter_type = "s" },
};
g_action_map_add_action_entries (G_ACTION_MAP (self),
win_entries,
G_N_ELEMENTS (win_entries),
self);
self->win_settings = g_settings_new ("uk.me.bcowan.Rugby.window");
g_settings_bind (self->win_settings, "height",
self, "default-height",
G_SETTINGS_BIND_DEFAULT);
g_settings_bind (self->win_settings, "width",
self, "default-width",
G_SETTINGS_BIND_DEFAULT);
}
static void
rugby_app_window_class_init (RugbyAppWindowClass *klass)
{
GObjectClass *obj_class = G_OBJECT_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
obj_class->dispose = rugby_app_window_dispose;
g_type_ensure (RUGBY_TYPE_POSSIBILITY_WIDGET);
g_type_ensure (RUGBY_TYPE_LIST_STORE);
object_class->dispose = rugby_app_window_dispose;
gtk_widget_class_set_template_from_resource (widget_class,
"/uk/me/bcowan/rugby/interface.ui");
gtk_widget_class_bind_template_child (widget_class, RugbyAppWindow, listbox);
"/uk/me/bcowan/Rugby/gtk/window.ui");
gtk_widget_class_bind_template_child (widget_class, RugbyAppWindow, scorespin);
gtk_widget_class_bind_template_child (widget_class, RugbyAppWindow, stack);
gtk_widget_class_bind_template_callback (widget_class, scorespin_value_changed_cb);
gtk_widget_class_bind_template_callback (widget_class, header_label_cb);
gtk_widget_class_bind_template_callback (widget_class, item_tooltip_cb);
gtk_widget_class_bind_template_callback (widget_class, list_store_items_changed_cb);
}
RugbyAppWindow *
......
/*
* SPDX-FileCopyrightText: 2017 Bruce Cowan <bruce@bcowan.me.uk>
* SPDX-FileCopyrightText: 2017-2022 Bruce Cowan <bruce@bcowan.me.uk>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#pragma once
#include <gtk/gtk.h>
#include <adwaita.h>
G_BEGIN_DECLS
#define RUGBY_TYPE_APP_WINDOW (rugby_app_window_get_type())
G_DECLARE_FINAL_TYPE (RugbyAppWindow, rugby_app_window, RUGBY, APP_WINDOW, GtkApplicationWindow);
G_DECLARE_FINAL_TYPE (RugbyAppWindow, rugby_app_window, RUGBY, APP_WINDOW, AdwApplicationWindow)
RugbyAppWindow * rugby_app_window_new (GtkApplication *app);
RugbyAppWindow *rugby_app_window_new (GtkApplication *app);
G_END_DECLS
/*
* SPDX-FileCopyrightText: 2018 Bruce Cowan <bruce@bcowan.me.uk>
* SPDX-FileCopyrightText: 2018-2024 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"
#include <gio/gio.h>
#include <gtk/gtk.h>
struct _RugbyListStore
{
GObject parent_instance;
unsigned score;
GPtrArray *items;
int score;
GListStore *items;
GSettings *settings;
};
static void rugby_list_store_list_model_iface_init (GListModelInterface *iface);
static void rugby_list_store_section_model_iface_init (GtkSectionModelInterface *iface);
G_DEFINE_FINAL_TYPE_WITH_CODE (RugbyListStore, rugby_list_store, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL,
rugby_list_store_list_model_iface_init)
G_IMPLEMENT_INTERFACE (GTK_TYPE_SECTION_MODEL,
rugby_list_store_section_model_iface_init))
G_DEFINE_TYPE_WITH_CODE (RugbyListStore, rugby_list_store, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL,
rugby_list_store_list_model_iface_init))
enum
{
PROP_0,
PROP_SCORE,
PROP_SCORE = 1,
N_PROPS
};
......@@ -35,20 +42,14 @@ static GParamSpec *properties[N_PROPS];
// Helper functions
static int
sort_func (gconstpointer a,
gconstpointer b)
sort_func ( gconstpointer a,
gconstpointer b,
G_GNUC_UNUSED void *user_data)
{
int atries, autries;
int btries, butries;
g_object_get ((gpointer) a,
"tries", &atries,
"utries", &autries,
NULL);
g_object_get ((gpointer) b,
"tries", &btries,
"utries", &butries,
NULL);
int atries = rugby_possibility_get_tries ((void *) a);
int autries = rugby_possibility_get_utries ((void *) a);
int btries = rugby_possibility_get_tries ((void *) b);
int butries = rugby_possibility_get_utries ((void *) b);
int trydiff = (btries + butries) - (atries + autries);
......@@ -56,53 +57,59 @@ sort_func (gconstpointer a,
if (trydiff != 0)
return trydiff;
else
return atries - btries;
return btries - atries;
}
// Callbacks
static void
notify_score_cb (GObject *gobject,
GParamSpec *pspec,
gpointer user_data)
process_data (RugbyListStore *self)
{
RugbyListStore *self = RUGBY_LIST_STORE (user_data);
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 = g_list_model_get_n_items (G_LIST_MODEL (self->items));
g_list_store_remove_all (self->items);
if (self->score == 0)
{
g_list_model_items_changed (G_LIST_MODEL (self), 0, old_length, 0);
return;
}
unsigned old_length = self->items->len;
g_ptr_array_remove_range (self->items, 0, self->items->len);
int max_tries = self->score / try_points;
int max_utries = self->score / utry_points;
for (int tries = 0; tries <= max_tries; tries++)
{
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,
kicks);
g_ptr_array_add (self->items, possibility);
g_list_store_append (self->items, possibility);
g_object_unref (possibility);
}
}
}
g_ptr_array_sort (self->items, sort_func);
g_list_model_items_changed (G_LIST_MODEL (self), 0, old_length, self->items->len);
g_list_store_sort (self->items, sort_func, NULL);
g_list_model_items_changed (G_LIST_MODEL (self), 0, old_length,
g_list_model_get_n_items (G_LIST_MODEL (self->items)));
}
// GListModel implementation
static GType
rugby_list_store_get_item_type (GListModel *list)
rugby_list_store_get_item_type (G_GNUC_UNUSED GListModel *list)
{
return RUGBY_TYPE_POSSIBILITY;
}
......@@ -112,38 +119,94 @@ rugby_list_store_get_n_items (GListModel *list)
{
RugbyListStore *self = RUGBY_LIST_STORE (list);
return self->items->len;
return g_list_model_get_n_items (G_LIST_MODEL (self->items));
}
static gpointer
static void *
rugby_list_store_get_item (GListModel *list,
unsigned position)
{
RugbyListStore *self = RUGBY_LIST_STORE (list);
g_return_val_if_fail (position < self->items->len, NULL);
return g_object_ref (g_ptr_array_index (self->items, position));
return g_list_model_get_item (G_LIST_MODEL (self->items), position);
}
static void
rugby_list_store_list_model_iface_init (GListModelInterface *iface)
{
iface->get_item_type = rugby_list_store_get_item_type;
iface->get_n_items = rugby_list_store_get_n_items;
iface->get_item = rugby_list_store_get_item;
iface->get_item_type = rugby_list_store_get_item_type;
iface->get_n_items = rugby_list_store_get_n_items;
iface->get_item = rugby_list_store_get_item;
}
// SectionModel implementation
static void
rugby_list_store_get_section (GtkSectionModel *model,
unsigned position,
unsigned *out_start,
unsigned *out_end)
{
RugbyListStore *self = RUGBY_LIST_STORE (model);
unsigned n_items = g_list_model_get_n_items (G_LIST_MODEL (self->items));
RugbyPossibility *possibility = g_list_model_get_item (G_LIST_MODEL (self->items),
position);
if (!possibility)
{
*out_start = n_items;
*out_end = G_MAXUINT;
return;
}
int target_tries = rugby_possibility_total_tries (possibility);
// Find start
for (unsigned i = 0; i < n_items; i++)
{
possibility = g_list_model_get_item (G_LIST_MODEL (self->items), i);
int total = rugby_possibility_total_tries (possibility);
if (total == target_tries)
{
*out_start = i;
break;
}
}
// Find end
for (unsigned i = *out_start + 1; i < n_items; i++)
{
possibility = g_list_model_get_item (G_LIST_MODEL (self->items), i);
int total = rugby_possibility_total_tries (possibility);
if (total != target_tries)
{
*out_end = i;
return;
}
}
*out_end = n_items;
}
static void
rugby_list_store_section_model_iface_init (GtkSectionModelInterface *iface)
{
iface->get_section = rugby_list_store_get_section;
}
// Class functions
static void
rugby_list_store_finalize (GObject *object)
rugby_list_store_dispose (GObject *object)
{
RugbyListStore *self = RUGBY_LIST_STORE (object);
g_ptr_array_unref (self->items);
g_clear_object (&self->settings);
g_clear_object (&self->items);
G_OBJECT_CLASS (rugby_list_store_parent_class)->finalize (object);
G_OBJECT_CLASS (rugby_list_store_parent_class)->dispose (object);
}
static void
......@@ -157,7 +220,7 @@ rugby_list_store_get_property (GObject *object,
switch (prop_id)
{
case PROP_SCORE:
g_value_set_uint (value, rugby_list_store_get_score (self));
g_value_set_int (value, self->score);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
......@@ -174,8 +237,15 @@ rugby_list_store_set_property (GObject *object,
switch (prop_id)
{
int score;
case PROP_SCORE:
rugby_list_store_set_score (self, g_value_get_uint (value));
score = g_value_get_int (value);
if (score != self->score)
{
self->score = score;
process_data (self);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SCORE]);
}
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
......@@ -187,15 +257,13 @@ rugby_list_store_class_init (RugbyListStoreClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = rugby_list_store_finalize;
object_class->dispose = rugby_list_store_dispose;
object_class->get_property = rugby_list_store_get_property;
object_class->set_property = rugby_list_store_set_property;
properties[PROP_SCORE] = g_param_spec_uint ("score",
"Score",
"Score of the match",
0, 200, 0,
G_PARAM_READWRITE);
properties[PROP_SCORE] = g_param_spec_int ("score", "", "",
0, 200, 0,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class,
N_PROPS,
......@@ -205,38 +273,16 @@ rugby_list_store_class_init (RugbyListStoreClass *klass)
static void
rugby_list_store_init (RugbyListStore *self)
{
self->score = 0;
self->items = g_ptr_array_new_with_free_func (g_object_unref);
self->settings = g_settings_new ("uk.me.bcowan.Rugby");
g_signal_connect (self, "notify::score",
G_CALLBACK (notify_score_cb), self);
}
g_signal_connect_swapped (self->settings, "changed::try-points",
G_CALLBACK (process_data), self);
g_signal_connect_swapped (self->settings, "changed::utry-points",
G_CALLBACK (process_data), self);
g_signal_connect_swapped (self->settings, "changed::kick-points",
G_CALLBACK (process_data), self);
// Public functions
unsigned
rugby_list_store_get_score (RugbyListStore *self)
{
g_return_val_if_fail (RUGBY_IS_LIST_STORE (self), 0);
return self->score;
}
void
rugby_list_store_set_score (RugbyListStore *self,
unsigned score)
{
g_return_if_fail (RUGBY_IS_LIST_STORE (self));
if (score != self->score)
{
self->score = score;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SCORE]);
}
self->score = 0;
self->items = g_list_store_new (RUGBY_TYPE_POSSIBILITY);
}
RugbyListStore *
rugby_list_store_new (void)
{
return g_object_new (RUGBY_TYPE_LIST_STORE, NULL);
}
/*
* SPDX-FileCopyrightText: 2018 Bruce Cowan <bruce@bcowan.me.uk>
* SPDX-FileCopyrightText: 2018-2022 Bruce Cowan <bruce@bcowan.me.uk>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
......@@ -10,12 +11,7 @@
G_BEGIN_DECLS
#define RUGBY_TYPE_LIST_STORE (rugby_list_store_get_type())
G_DECLARE_FINAL_TYPE (RugbyListStore, rugby_list_store, RUGBY, LIST_STORE, GObject)
RugbyListStore * rugby_list_store_new (void);
unsigned rugby_list_store_get_score (RugbyListStore *self);
void rugby_list_store_set_score (RugbyListStore *self,
unsigned score);
G_DECLARE_FINAL_TYPE (RugbyListStore, rugby_list_store, RUGBY, LIST_STORE, GObject)
G_END_DECLS
/*
* SPDX-FileCopyrightText: 2018 Bruce Cowan <bruce@bcowan.me.uk>
* SPDX-FileCopyrightText: 2018-2024 Bruce Cowan <bruce@bcowan.me.uk>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "config.h"
#include "rugby-possibility-widget.h"
#include "rugby-possibility.h"
#include <adwaita.h>
struct _RugbyPossibilityWidget
{
GtkDrawingArea parent_instance;
GtkWidget parent_instance;
GSettings *settings;
RugbyPossibility *possibility;
};
G_DEFINE_TYPE (RugbyPossibilityWidget, rugby_possibility_widget, GTK_TYPE_DRAWING_AREA)
G_DEFINE_FINAL_TYPE (RugbyPossibilityWidget, rugby_possibility_widget, GTK_TYPE_WIDGET)
enum
{
PROP_0,
PROP_POSSIBILITY,
PROP_POSSIBILITY = 1,
N_PROPS
};
static GParamSpec *properties[N_PROPS];
#define FIXED_HEIGHT 20
static void
rugby_possibility_widget_dispose (GObject *object)
{
RugbyPossibilityWidget *self = RUGBY_POSSIBILITY_WIDGET (object);
g_clear_object (&self->settings);
g_clear_object (&self->possibility);
G_OBJECT_CLASS (rugby_possibility_widget_parent_class)->dispose (object);
......@@ -72,116 +77,91 @@ rugby_possibility_widget_set_property (GObject *object,
}
static void
rugby_possibility_widget_get_preferred_height (GtkWidget *widget,
int *minimum_height,
int *natural_height)
render_bar (GtkSnapshot *snapshot,
float x,
float w,
float h,
const GdkRGBA fill,
const GdkRGBA border)
{
if (minimum_height)
*minimum_height = FIXED_HEIGHT;
if (natural_height)
*natural_height = FIXED_HEIGHT;
graphene_rect_t area = GRAPHENE_RECT_INIT (x, 0.0, w, h);
GskRoundedRect rounded;
gsk_rounded_rect_init_from_rect (&rounded,
&area,
h / 2.0);
gtk_snapshot_push_rounded_clip (snapshot, &rounded);
gtk_snapshot_append_color (snapshot,
&fill,
&area);
gtk_snapshot_pop (snapshot);
gtk_snapshot_append_border (snapshot,
&rounded,
(float[]) { 2.0, 2.0, 2.0, 2.0 },
(GdkRGBA[]) { border,
border,
border,
border });
}
static void
render_bar (cairo_t *cr,
GtkStyleContext *context,
double x,
double y,
double w,
double h,
const char *style)
{
gtk_style_context_save (context);
gtk_style_context_add_class (context, style);
gtk_render_background (context, cr, x, y, w, h);
gtk_style_context_restore (context);
}
static gboolean
rugby_possibility_widget_draw (GtkWidget *widget,
cairo_t *cr)
rugby_possibility_widget_snapshot (GtkWidget *widget,
GtkSnapshot *snapshot)
{
RugbyPossibilityWidget *self = RUGBY_POSSIBILITY_WIDGET (widget);
double width = gtk_widget_get_allocated_width (widget);
double height = gtk_widget_get_allocated_height (widget);
double x = 0.0, y = 0.0;
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");
GtkStyleContext *context = gtk_widget_get_style_context (widget);
gtk_style_context_save (context);
gtk_style_context_add_class (context, "level-cell");
int width = gtk_widget_get_width (widget);
int height = gtk_widget_get_height (widget);
float x = 0.0;
gtk_render_background (context, cr, x, y, width, height);
gtk_render_frame (context, cr, x, y, width, height);
int tries = rugby_possibility_get_tries (self->possibility);
int utries = rugby_possibility_get_utries (self->possibility);
int kicks = rugby_possibility_get_kicks (self->possibility);
int tries, utries, kicks;
int score = tries * try_points + utries * utry_points + kicks * kick_points;
g_object_get (self->possibility,
"tries", &tries,
"utries", &utries,
"kicks", &kicks,
NULL);
int score = tries * 7 + utries * 5 + kicks * 3;
gtk_style_context_add_class (context, "fill-block");
GdkRGBA fill;
GdkRGBA border;
AdwStyleManager *manager = adw_style_manager_get_default ();
if (adw_style_manager_get_dark (manager))
gdk_rgba_parse (&border, "white");
else
gdk_rgba_parse (&border, "black");
// Tries
double w = width / (score / 7.0);
float w = width / (score / (float) try_points);
gdk_rgba_parse (&fill, "#33d17a"); // Green 3
for (int i = 0; i < tries; i++)
{
render_bar (cr, context, x, y, w, height, "score-try");
render_bar (snapshot, x, w, height, fill, border);
x += w;
}
// Unconverted tries
w = width / (score / 5.0);
w = width / (score / (float) utry_points);
gdk_rgba_parse (&fill, "#f6d32d"); // Yellow 3
for (int i = 0; i < utries; i++)
{
render_bar (cr, context, x, y, w, height, "score-utry");
render_bar (snapshot, x, w, height, fill, border);
x += w;
}
// Unconverted kicks
w = width / (score / 3.0);
// Kicks
w = width / (score / (float) kick_points);
gdk_rgba_parse (&fill, "#e01b24"); // Red 3
for (int i = 0; i < kicks; i++)
{
render_bar (cr, context, x, y, w, height, "score-kick");
render_bar (snapshot, x, w, height, fill, border);
x += w;
}
gtk_style_context_restore (context);
return TRUE;
}
static void
rugby_possibility_widget_constructed (GObject *obj)
{
RugbyPossibilityWidget *self = RUGBY_POSSIBILITY_WIDGET (obj);
int tries, utries, kicks;
g_autoptr (GString) tooltip = g_string_new (NULL);
g_object_get (self->possibility,
"tries", &tries,
"utries", &utries,
"kicks", &kicks,
NULL);
if (tries > 0 || utries > 0)
g_string_append_printf (tooltip, "%d tries, %d converted",
tries + utries, tries);
if (kicks > 0)
{
if (tooltip->len == 0)
g_string_append_printf (tooltip, "%d kicks", kicks);
else
g_string_append_printf (tooltip, ", %d kicks", kicks);
}
gtk_widget_set_tooltip_text (GTK_WIDGET (self), tooltip->str);
G_OBJECT_CLASS (rugby_possibility_widget_parent_class)->constructed (obj);
}
static void
......@@ -190,19 +170,16 @@ rugby_possibility_widget_class_init (RugbyPossibilityWidgetClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->constructed = rugby_possibility_widget_constructed;
object_class->dispose = rugby_possibility_widget_dispose;
object_class->get_property = rugby_possibility_widget_get_property;
object_class->set_property = rugby_possibility_widget_set_property;
widget_class->draw = rugby_possibility_widget_draw;
widget_class->get_preferred_height = rugby_possibility_widget_get_preferred_height;
widget_class->snapshot = rugby_possibility_widget_snapshot;
properties[PROP_POSSIBILITY] = g_param_spec_object ("possibility",
"Possibility",
"Possibility to be represented",
RUGBY_TYPE_POSSIBILITY,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
properties[PROP_POSSIBILITY] =
g_param_spec_object ("possibility", "", "",
RUGBY_TYPE_POSSIBILITY,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class,
N_PROPS,
......@@ -212,12 +189,5 @@ rugby_possibility_widget_class_init (RugbyPossibilityWidgetClass *klass)
static void
rugby_possibility_widget_init (RugbyPossibilityWidget *self)
{
}
GtkWidget *
rugby_possibility_widget_new (RugbyPossibility *possibility)
{
return g_object_new (RUGBY_TYPE_POSSIBILITY_WIDGET,
"possibility", possibility,
NULL);
self->settings = g_settings_new ("uk.me.bcowan.Rugby");
}
/*
* SPDX-FileCopyrightText: 2018 Bruce Cowan <bruce@bcowan.me.uk>
* SPDX-FileCopyrightText: 2018-2022 Bruce Cowan <bruce@bcowan.me.uk>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
......@@ -7,14 +8,10 @@
#include <gtk/gtk.h>
#include "rugby-possibility.h"
G_BEGIN_DECLS
#define RUGBY_TYPE_POSSIBILITY_WIDGET (rugby_possibility_widget_get_type())
G_DECLARE_FINAL_TYPE (RugbyPossibilityWidget, rugby_possibility_widget, RUGBY, POSSIBILITY_WIDGET, GtkDrawingArea)
GtkWidget * rugby_possibility_widget_new (RugbyPossibility *possibility);
G_DECLARE_FINAL_TYPE (RugbyPossibilityWidget, rugby_possibility_widget, RUGBY, POSSIBILITY_WIDGET, GtkWidget)
G_END_DECLS
/*
* SPDX-FileCopyrightText: 2018 Bruce Cowan <bruce@bcowan.me.uk>
* SPDX-FileCopyrightText: 2018-2024 Bruce Cowan <bruce@bcowan.me.uk>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include <config.h>
#include "rugby-possibility.h"
struct _RugbyPossibility
{
GObject parent_instance;
gint tries;
gint utries;
gint kicks;
int tries;
int utries;
int kicks;
};
G_DEFINE_TYPE (RugbyPossibility, rugby_possibility, G_TYPE_OBJECT)
G_DEFINE_FINAL_TYPE (RugbyPossibility, rugby_possibility, G_TYPE_OBJECT)
enum
{
PROP_0,
PROP_TRIES,
PROP_TRIES = 1,
PROP_UTRIES,
PROP_KICKS,
N_PROPS
......@@ -29,7 +30,7 @@ static GParamSpec *properties[N_PROPS];
static void
rugby_possibility_get_property (GObject *object,
guint prop_id,
unsigned prop_id,
GValue *value,
GParamSpec *pspec)
{
......@@ -38,13 +39,13 @@ rugby_possibility_get_property (GObject *object,
switch (prop_id)
{
case PROP_TRIES:
g_value_set_int (value, self->tries);
g_value_set_int (value, rugby_possibility_get_tries (self));
break;
case PROP_UTRIES:
g_value_set_int (value, self->utries);
g_value_set_int (value, rugby_possibility_get_utries (self));
break;
case PROP_KICKS:
g_value_set_int (value, self->kicks);
g_value_set_int (value, rugby_possibility_get_kicks (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
......@@ -53,7 +54,7 @@ rugby_possibility_get_property (GObject *object,
static void
rugby_possibility_set_property (GObject *object,
guint prop_id,
unsigned prop_id,
const GValue *value,
GParamSpec *pspec)
{
......@@ -84,17 +85,17 @@ rugby_possibility_class_init (RugbyPossibilityClass *klass)
object_class->set_property = rugby_possibility_set_property;
properties[PROP_TRIES] =
g_param_spec_int ("tries", "Tries", "Converted tries",
0, 28, 0,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
g_param_spec_int ("tries", "", "",
0, 200, 0,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
properties[PROP_UTRIES] =
g_param_spec_int ("utries", "Utries", "Unconverted tries",
0, 40, 0,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
g_param_spec_int ("utries", "", "",
0, 200, 0,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
properties[PROP_KICKS] =
g_param_spec_int ("kicks", "Kicks", "Penalties and drop goals",
0, 66, 0,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
g_param_spec_int ("kicks", "", "",
0, 200, 0,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class,
N_PROPS,
......@@ -103,14 +104,14 @@ rugby_possibility_class_init (RugbyPossibilityClass *klass)
}
static void
rugby_possibility_init (RugbyPossibility *self)
rugby_possibility_init (G_GNUC_UNUSED RugbyPossibility *self)
{
}
RugbyPossibility *
rugby_possibility_new (gint tries,
gint utries,
gint kicks)
rugby_possibility_new (int tries,
int utries,
int kicks)
{
return g_object_new (RUGBY_TYPE_POSSIBILITY,
"tries", tries,
......@@ -118,3 +119,35 @@ rugby_possibility_new (gint tries,
"kicks", kicks,
NULL);
}
int
rugby_possibility_get_tries (RugbyPossibility *self)
{
g_assert (RUGBY_IS_POSSIBILITY (self));
return self->tries;
}
int
rugby_possibility_get_utries (RugbyPossibility *self)
{
g_assert (RUGBY_IS_POSSIBILITY (self));
return self->utries;
}
int
rugby_possibility_get_kicks (RugbyPossibility *self)
{
g_assert (RUGBY_IS_POSSIBILITY (self));
return self->kicks;
}
int
rugby_possibility_total_tries (RugbyPossibility *self)
{
g_assert (RUGBY_IS_POSSIBILITY (self));
return self->tries + self->utries;
}
/*
* SPDX-FileCopyrightText: 2018 Bruce Cowan <bruce@bcowan.me.uk>
* SPDX-FileCopyrightText: 2018-2024 Bruce Cowan <bruce@bcowan.me.uk>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
......@@ -13,8 +14,14 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE (RugbyPossibility, rugby_possibility, RUGBY, POSSIBILITY, GObject)
RugbyPossibility * rugby_possibility_new (int tries,
int utries,
int kicks);
RugbyPossibility *rugby_possibility_new (int tries,
int utries,
int kicks);
int rugby_possibility_get_tries (RugbyPossibility *self);
int rugby_possibility_get_utries (RugbyPossibility *self);
int rugby_possibility_get_kicks (RugbyPossibility *self);
int rugby_possibility_total_tries (RugbyPossibility *self);
G_END_DECLS
/*
* SPDX-FileCopyrightText: 2020-2021 Bruce Cowan <bruce@bcowan.me.uk>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "rugby-pref-dialog.h"
struct _RugbyPrefDialog
{
AdwPreferencesDialog parent_instance;
GtkWidget *try_spin;
GtkWidget *utry_spin;
GtkWidget *kick_spin;
GSettings *settings;
};
G_DEFINE_FINAL_TYPE (RugbyPrefDialog, rugby_pref_dialog, ADW_TYPE_PREFERENCES_DIALOG)
static void
rugby_pref_dialog_dispose (GObject *object)
{
RugbyPrefDialog *self = RUGBY_PREF_DIALOG (object);
g_clear_object (&self->settings);
gtk_widget_dispose_template (GTK_WIDGET (object), RUGBY_TYPE_PREF_DIALOG);
G_OBJECT_CLASS (rugby_pref_dialog_parent_class)->dispose (object);
}
static void
rugby_pref_dialog_class_init (RugbyPrefDialogClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->dispose = rugby_pref_dialog_dispose;
gtk_widget_class_set_template_from_resource (widget_class,
"/uk/me/bcowan/Rugby/gtk/prefs.ui");
gtk_widget_class_bind_template_child (widget_class, RugbyPrefDialog, try_spin);
gtk_widget_class_bind_template_child (widget_class, RugbyPrefDialog, utry_spin);
gtk_widget_class_bind_template_child (widget_class, RugbyPrefDialog, kick_spin);
}
static void
rugby_pref_dialog_init (RugbyPrefDialog *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);
}
RugbyPrefDialog *
rugby_pref_dialog_new (void)
{
return g_object_new (RUGBY_TYPE_PREF_DIALOG,
NULL);
}
/*
* SPDX-FileCopyrightText: 2020-2024 Bruce Cowan <bruce@bcowan.me.uk>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#pragma once
#include "rugby-app-window.h"
#include <adwaita.h>
G_BEGIN_DECLS
#define RUGBY_TYPE_PREF_DIALOG (rugby_pref_dialog_get_type())
G_DECLARE_FINAL_TYPE (RugbyPrefDialog, rugby_pref_dialog, RUGBY, PREF_DIALOG, AdwPreferencesDialog)
RugbyPrefDialog *rugby_pref_dialog_new (void);
G_END_DECLS
# SPDX-FileCopyrightText: 2022-2024 Bruce Cowan
#
# SPDX-License-Identifier: CC0-1.0
[wrap-git]
directory = blueprint-compiler
url = https://gitlab.gnome.org/jwestman/blueprint-compiler.git
revision = v0.14.0
depth = 1
[provide]
program_names = blueprint-compiler
{
"app-id": "uk.me.bcowan.Rugby",
"runtime": "org.gnome.Platform",
"runtime-version": "47",
"sdk": "org.gnome.Sdk",
"command": "rugby",
"finish-args": [
"--share=ipc",
"--device=dri",
"--socket=fallback-x11",
"--socket=wayland"
],
"modules": [
{
"name": "blueprint-compiler",
"buildsystem": "meson",
"sources": [
{
"type": "git",
"url": "https://gitlab.gnome.org/jwestman/blueprint-compiler",
"tag": "v0.14.0"
}
]
},
{
"name": "rugby",
"buildsystem": "meson",
"builddir": true,
"sources": [
{
"type": "dir",
"path": "."
}
],
"config-opts": [
"-Dprofile=development"
]
}
]
}
SPDX-FileCopyrightText: 2024 Bruce Cowan <bruce@bcowan.me.uk>
SPDX-License-Identifier: GPL-3.0-or-later